DOCS-1: Init document work

This commit is contained in:
Blake Ridgway
2026-07-28 07:20:32 -05:00
parent 8f02a3fc8e
commit 0cbcc962f7
66 changed files with 12224 additions and 71 deletions

View File

@@ -0,0 +1,253 @@
---
title: "Set Up Automated Backups with Restic"
description: "Automate encrypted off-site backups on your Arcline VPS using restic."
section: vps
order: 6
---
# Set Up Automated Backups with Restic
Restic is a fast, encrypted backup tool that supports local and remote storage backends (SFTP, S3, B2, rsync.net). This guide covers backing up your VPS to a remote repository.
---
## Prerequisites
- A VPS with sudo access
- A backup destination (SFTP server, Backblaze B2, or local storage)
---
## Step 1 — Install restic
```bash
sudo apt update
sudo apt install restic -y
```
Verify:
```bash
restic version
```
---
## Step 2 — Initialize a repository
### Option A: SFTP/SSH (recommended for Arcline customers)
If you have SSH access to a backup server:
```bash
restic init --repo sftp:backup@backup-server:/var/backups/example-vps/
```
You'll be prompted for a repository password — this encrypts your backups. Store it in a password manager — if you lose it, you cannot recover your data.
### Option B: Backblaze B2
```bash
export B2_ACCOUNT_ID="your-application-key-id"
export B2_ACCOUNT_KEY="your-application-key"
restic init --repo b2:bucket-name:/example-vps
```
### Option C: Local directory
```bash
sudo mkdir -p /backups/example-vps-repo
restic init --repo /backups/example-vps-repo
```
---
## Step 3 — Create a backup script
```bash
sudo nano /usr/local/bin/backup.sh
```
```bash
#!/bin/bash
set -e
# Repository location and password
export RESTIC_REPOSITORY="sftp:backup@backup-server:/var/backups/example-vps/"
export RESTIC_PASSWORD="your-repo-password"
# Files and directories to back up
BACKUP_PATHS=(
/var/www
/etc/nginx
/etc/letsencrypt
/opt
/home
)
# Directories to exclude
EXCLUDE_PATTERNS=(
--exclude "/var/www/example.com/cache"
--exclude "*.log"
)
echo "Starting backup at $(date)"
# Create the backup
restic backup "${EXCLUDE_PATTERNS[@]}" "${BACKUP_PATHS[@]}"
# Keep last 7 daily, 4 weekly, 6 monthly snapshots
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
echo "Backup completed at $(date)"
```
Make it executable:
```bash
sudo chmod +x /usr/local/bin/backup.sh
```
---
## Step 4 — Test the backup
Run the backup manually:
```bash
sudo /usr/local/bin/backup.sh
```
List snapshots:
```bash
restic -r sftp:backup@backup-server:/var/backups/example-vps/ snapshots
```
> You'll need `RESTIC_PASSWORD` exported or passed via `--password-file` for any restic command.
---
## Step 5 — Schedule daily backups with systemd
Create a service file:
```bash
sudo nano /etc/systemd/system/restic-backup.service
```
```ini
[Unit]
Description=Restic backup
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
```
Create a timer:
```bash
sudo nano /etc/systemd/system/restic-backup.timer
```
```ini
[Unit]
Description=Daily restic backup
[Timer]
OnCalendar=daily
RandomizedDelaySec=3600
Persistent=true
[Install]
WantedBy=timers.target
```
Enable and start the timer:
```bash
sudo systemctl daemon-reload
sudo systemctl enable restic-backup.timer
sudo systemctl start restic-backup.timer
```
Verify:
```bash
sudo systemctl status restic-backup.timer
sudo systemctl list-timers | grep restic
```
---
## Step 6 — Restoring from a backup
List available snapshots:
```bash
restic -r sftp:backup@backup-server:/var/backups/example-vps/ snapshots
```
Restore the latest snapshot:
```bash
restic -r sftp:backup@backup-server:/var/backups/example-vps/ restore latest --target /tmp/restore
```
Or restore a specific snapshot by ID:
```bash
restic -r ... restore <snapshot-id> --target /tmp/restore
```
To restore only specific paths:
```bash
restic -r ... restore <snapshot-id> --target /tmp/restore --path /var/www
```
---
## Step 7 — Database backups
For MySQL databases, add a pre-backup dump step:
```bash
#!/bin/bash
set -e
# Dump all databases
mysqldump --all-databases --single-transaction --quick | gzip > /tmp/mysql-all.sql.gz
# Include the dump in the backup
restic backup --hostname example-vps /tmp/mysql-all.sql.gz "${BACKUP_PATHS[@]}"
rm /tmp/mysql-all.sql.gz
```
---
## Monitoring backups
Add a health check notification:
```bash
# After successful backup
curl -fsS -m 10 --retry 5 https://hc-ping.com/your-uuid
# Or on failure, notify via Discord/Slack webhook
curl -fsS -m 10 -X POST -H "Content-Type: application/json" \
-d '{"content":"Backup failed on example-vps"}' \
https://discord.com/api/webhooks/your-webhook-url
```
---
## What's next
- [Install fail2ban](/vps/fail2ban/) for SSH brute-force protection
- [Set up a Go service](/vps/go-systemd/) with systemd

214
content/vps/fail2ban.md Normal file
View File

@@ -0,0 +1,214 @@
---
title: "Set Up Fail2ban for SSH Brute-Force Protection"
description: "Protect your Arcline VPS from SSH brute-force attacks with fail2ban."
section: vps
order: 7
---
# Set Up Fail2ban for SSH Brute-Force Protection
Fail2ban monitors system logs for repeated failed login attempts and temporarily bans the offending IP addresses using the firewall. It's essential for any internet-facing server.
---
## Prerequisites
- A VPS with SSH access and sudo privileges
- UFW or iptables already installed (see [Initial VPS Setup](/vps/initial-setup/))
---
## Step 1 — Install fail2ban
```bash
sudo apt update
sudo apt install fail2ban -y
```
---
## Step 2 — Configure fail2ban for SSH
The default configuration file is `/etc/fail2ban/jail.conf`. Don't edit it directly — it gets overwritten on updates. Instead, create a local override:
```bash
sudo nano /etc/fail2ban/jail.local
```
```ini
[DEFAULT]
# Ban IPs for 1 hour after 5 failed attempts within 10 minutes
bantime = 3600
findtime = 600
maxretry = 5
# Send email alerts (optional)
# destemail = you@example.com
# action = %(action_mwl)s
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
```
If you changed your SSH port, specify it:
```ini
[sshd]
enabled = true
port = 2222
logpath = %(sshd_log)s
```
---
## Step 3 — Start fail2ban
```bash
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
```
Check the status:
```bash
sudo systemctl status fail2ban
```
---
## Step 4 — Monitor banned IPs
View the SSH jail status:
```bash
sudo fail2ban-client status sshd
```
This shows the total bans and currently active bans.
View the ban log:
```bash
sudo tail -f /var/log/fail2ban.log
```
---
## Step 5 — Unban an IP
If you accidentally lock yourself out (you should have tested SSH key access before enabling, but just in case):
```bash
sudo fail2ban-client set sshd unbanip 203.0.113.42
```
Or from the console (if you still have a root session open):
```bash
sudo iptables -D f2b-sshd -s 203.0.113.42 -j DROP
```
---
## Step 6 — Additional jails (optional)
### Nginx
```ini
[nginx-http-auth]
enabled = true
logpath = /var/log/nginx/error.log
```
### Nginx bot protection (repeat offenders)
```ini
[nginx-botsearch]
enabled = true
logpath = /var/log/nginx/access.log
maxretry = 2
findtime = 86400
bantime = 86400
```
This bans IPs that hit common admin paths (wp-admin, etc.) that don't exist on your server.
### Wordpress
```ini
[wordpress]
enabled = true
filter = wordpress
logpath = /var/log/auth.log
```
You may need to create a custom filter for your specific application logs.
---
## Step 7 — Whitelist IPs
To exclude trusted IPs from bans (your office IP, for example):
```ini
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.100
```
---
## Permanent bans with recidive jail
Habitual offenders get progressively longer bans:
```ini
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
maxretry = 3
findtime = 604800 # 1 week
bantime = 604800 # 1 week
```
An IP that triggers bans 3 times in a week gets banned for a week.
---
## Testing fail2ban
From a different machine (or after whitelisting your IP), intentionally fail SSH login a few times:
```bash
ssh nonexistent@your.vps.ip.address
```
After 5 failures, further attempts should hang or be refused. Check with:
```bash
sudo fail2ban-client status sshd
```
---
## Performance notes
Fail2ban uses minimal resources — typically under 50MB of RAM with a few jails enabled. It reads log files using Python's `pyinotify` (if available) or polls every second.
If you have high-traffic sites with aggressive bots, increase `findtime` and lower `maxretry` to catch them sooner:
```ini
[nginx-botsearch]
maxretry = 2
findtime = 3600
bantime = 86400
```
---
## What's next
- [Deploy a Go binary](/vps/go-systemd/) as a systemd service
- [Set up automated backups](/vps/automated-backups/) with restic

215
content/vps/go-systemd.md Normal file
View File

@@ -0,0 +1,215 @@
---
title: "Deploy a Go Binary as a Systemd Service"
description: "Run a Go application as a background service on your Arcline VPS with systemd."
section: vps
order: 5
---
# Deploy a Go Binary as a Systemd Service
Go compiles to a single static binary — no runtime, no dependencies, no package manager. This makes it ideal for running as a systemd service on your Arcline VPS.
---
## Prerequisites
- A VPS with SSH access
- A Go binary compiled for Linux amd64 (or arm64 if using an ARM VPS)
---
## Step 1 — Build your Go binary
On your local machine, cross-compile for your target VPS:
```bash
# For Linux amd64 (most common)
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o myapp
# For Linux arm64 (e.g., Raspberry Pi)
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o myapp
```
The `CGO_ENABLED=0` flag ensures a fully static binary with no external library dependencies.
---
## Step 2 — Upload the binary
```bash
scp myapp yourname@your.vps.ip.address:/tmp/
```
On the VPS, move it to its final location:
```bash
sudo mkdir -p /opt/myapp
sudo mv /tmp/myapp /opt/myapp/
sudo chmod +x /opt/myapp/myapp
```
---
## Step 3 — Create a systemd service file
```bash
sudo nano /etc/systemd/system/myapp.service
```
```ini
[Unit]
Description=My Go Application
After=network.target
Wants=network-online.target
[Service]
Type=simple
User=yourname
Group=yourname
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/myapp
Restart=always
RestartSec=5
EnvironmentFile=-/opt/myapp/.env
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/myapp
[Install]
WantedBy=multi-user.target
```
---
## Step 4 — Create an environment file
If your app reads configuration from environment variables:
```bash
sudo nano /opt/myapp/.env
```
```
PORT=8080
DATABASE_PATH=/opt/myapp/data.db
LOG_LEVEL=info
```
Secure the file:
```bash
sudo chmod 600 /opt/myapp/.env
sudo chown yourname:yourname /opt/myapp/.env
```
---
## Step 5 — Start and enable the service
```bash
sudo systemctl daemon-reload
sudo systemctl start myapp
sudo systemctl enable myapp # starts on boot
```
Check the status:
```bash
sudo systemctl status myapp
```
---
## Step 6 — Set up Nginx reverse proxy (if it's a web app)
If your Go app serves HTTP on a port like `8080`, put Nginx in front:
```nginx
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
Enable SSL with Certbot:
```bash
sudo certbot --nginx -d api.example.com
```
---
## Managing the service
| Command | Description |
|---------|-------------|
| `sudo systemctl start myapp` | Start the service |
| `sudo systemctl stop myapp` | Stop the service |
| `sudo systemctl restart myapp` | Restart the service |
| `sudo systemctl status myapp` | Show status and recent logs |
| `sudo systemctl enable myapp` | Enable auto-start on boot |
| `sudo systemctl disable myapp` | Disable auto-start |
| `journalctl -u myapp -f` | Follow live logs |
---
## Updating the binary
```bash
# Build new version locally
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o myapp
# Upload
scp myapp yourname@your.vps.ip.address:/tmp/
# On the VPS
sudo systemctl stop myapp
sudo cp /tmp/myapp /opt/myapp/
sudo systemctl start myapp
sudo systemctl status myapp
```
---
## Logging
Your Go app's stdout and stderr are automatically captured by systemd's journal. View them with:
```bash
journalctl -u myapp -f
```
For persistent log files, your app can write to a file, or you can configure systemd to forward logs to syslog:
```bash
sudo mkdir -p /var/log/myapp
sudo chown yourname:yourname /var/log/myapp
```
Then in your service file, add:
```
StandardOutput=append:/var/log/myapp/stdout.log
StandardError=append:/var/log/myapp/stderr.log
```
---
## What's next
- [Set up automated backups](/vps/automated-backups/) with restic
- [Install fail2ban](/vps/fail2ban/) for SSH brute-force protection

View File

@@ -0,0 +1,202 @@
---
title: "Initial VPS Setup (Debian/Ubuntu)"
description: "First steps after provisioning a new VPS: users, SSH keys, firewall, and system updates."
section: vps
order: 1
---
# Initial VPS Setup
This guide walks you through the first steps after provisioning a new Arcline VPS. You'll create a non-root user, harden SSH, set up a firewall, and apply system updates.
---
## Before you begin
You'll receive your VPS login credentials from Arcline after provisioning. Your initial login is as `root` via SSH.
```
ssh root@your.vps.ip.address
```
If you're on macOS or Linux, the SSH client is built in. On Windows, use PowerShell, Windows Terminal, or WSL.
---
## Step 1 — Create a non-root user
Working as root for daily tasks is risky. Create an administrative user:
```bash
adduser yourname
```
Follow the prompts to set a strong password. Then add the user to the `sudo` group:
```bash
usermod -aG sudo yourname
```
For Debian, the sudo group may be named differently. Verify with `groups yourname` — if you see `sudo`, you're set.
---
## Step 2 — Copy your SSH key
From your local machine (not the VPS), copy your SSH public key to the new user:
```bash
ssh-copy-id yourname@your.vps.ip.address
```
If `ssh-copy-id` isn't available, manually create the `.ssh` directory and `authorized_keys` file:
```bash
# On the VPS, as your new user:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# Edit this file and paste your public key
nano ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
```
Test that key-based login works from a new terminal:
```bash
ssh yourname@your.vps.ip.address
```
If you can log in without a password prompt, proceed.
---
## Step 3 — Harden SSH
Edit the SSH server configuration:
```bash
sudo nano /etc/ssh/sshd_config
```
Make the following changes:
```
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
Port 22
```
If you changed the SSH port, note it — you'll need it in firewall rules below.
Restart SSH:
```bash
sudo systemctl restart sshd
```
Before closing your current session, open a **second terminal** and verify you can still log in as your new user. If something went wrong, you still have the root session to fix it.
---
## Step 4 — Set up the firewall (UFW)
UFW (Uncomplicated Firewall) is the easiest way to manage iptables rules on Ubuntu/Debian.
First, allow SSH so you don't lock yourself out:
```bash
sudo ufw allow ssh
```
If you changed the SSH port:
```bash
sudo ufw allow 2222/tcp # replace 2222 with your port
```
For a web server, allow HTTP and HTTPS:
```bash
sudo ufw allow http
sudo ufw allow https
```
Enable the firewall:
```bash
sudo ufw enable
```
Check the status:
```bash
sudo ufw status verbose
```
Default deny on incoming, allow on outgoing is the correct policy. Only the ports you explicitly opened should be listed.
---
## Step 5 — Apply system updates
Keep the system current:
```bash
sudo apt update
sudo apt upgrade -y
```
Enable automatic security updates:
```bash
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure --priority=low unattended-upgrades
```
Select **Yes** when prompted about automatically installing security updates.
---
## Step 6 — Set the timezone and hostname
Set the correct timezone:
```bash
sudo timedatectl set-timezone America/New_York # or your timezone
```
Verify with `timedatectl`.
Set a descriptive hostname:
```bash
sudo hostnamectl set-hostname myserver
```
Add it to `/etc/hosts`:
```bash
echo "127.0.1.1 myserver" | sudo tee -a /etc/hosts
```
---
## Step 7 — Install essential tools
A few packages you'll want on every server:
```bash
sudo apt install -y curl wget git htop net-tools ufw fail2ban
```
Fail2ban will be configured in a dedicated guide. For now it runs with sensible defaults.
---
## What's next
- [Install Nginx + PHP-FPM + MySQL](/vps/nginx-php-mysql/) for a LEMP stack
- [Deploy a static site](/vps/static-site/) with Nginx
- [Set up fail2ban](/vps/fail2ban/) for SSH brute-force protection

View File

@@ -0,0 +1,208 @@
---
title: "Install Nginx + PHP-FPM + MySQL on Debian/Ubuntu"
description: "Set up a LEMP stack on your Arcline VPS for hosting PHP applications and WordPress."
section: vps
order: 2
---
# Install Nginx + PHP-FPM + MySQL
This guide walks through setting up a LEMP stack (Linux, Nginx, MySQL, PHP) on your Arcline VPS. This is the foundation for hosting WordPress, Laravel, and most PHP applications.
---
## Prerequisites
- A VPS provisioned through Arcline
- SSH access with sudo privileges (see [Initial VPS Setup](/vps/initial-setup/))
- A domain pointed to your VPS IP (see [Point Your Nameservers](/getting-started/nameservers/))
---
## Step 1 — Install Nginx
Nginx is the web server. It's lightweight, fast, and handles concurrent connections much better than Apache.
```bash
sudo apt update
sudo apt install nginx -y
```
Verify it's running:
```bash
sudo systemctl status nginx
```
Visit your VPS IP in a browser — you should see the default Nginx welcome page.
---
## Step 2 — Install MySQL (MariaDB)
MariaDB is a drop-in replacement for MySQL that's faster and more open:
```bash
sudo apt install mariadb-server mariadb-client -y
```
Run the security script:
```bash
sudo mysql_secure_installation
```
Follow the prompts:
- Set a root password
- Remove anonymous users: **Y**
- Disallow root login remotely: **Y**
- Remove test database: **Y**
- Reload privilege tables: **Y**
Verify the installation:
```bash
sudo mysql -u root -p
```
You should get a MariaDB prompt. Type `exit` to quit.
---
## Step 3 — Install PHP-FPM
PHP-FPM (FastCGI Process Manager) runs PHP scripts. Install the version appropriate for your needs:
```bash
# PHP 8.3 (recommended for most applications)
sudo apt install php8.3-fpm php8.3-mysql php8.3-curl php8.3-gd php8.3-mbstring php8.3-xml php8.3-xmlrpc php8.3-zip php8.3-intl php8.3-bcmath -y
```
For WordPress, the required extensions are: `mysql`, `curl`, `gd`, `mbstring`, `xml`, `zip`.
Verify PHP-FPM is running:
```bash
sudo systemctl status php8.3-fpm
```
---
## Step 4 — Configure Nginx for PHP
Create a site configuration file:
```bash
sudo nano /etc/nginx/sites-available/example.com
```
Replace `example.com` with your actual domain:
```nginx
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.php index.html;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
```
Create the web root and enable the site:
```bash
sudo mkdir -p /var/www/example.com
sudo chown -R $USER:$USER /var/www/example.com
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
---
## Step 5 — Test PHP processing
Create a test file:
```bash
echo "<?php phpinfo();" > /var/www/example.com/info.php
```
Visit `http://example.com/info.php` in your browser — you should see the PHP information page.
Remove this file after testing — it exposes sensitive server information:
```bash
rm /var/www/example.com/info.php
```
---
## Step 6 — Set up SSL with Let's Encrypt
Install Certbot:
```bash
sudo apt install certbot python3-certbot-nginx -y
```
Obtain a certificate:
```bash
sudo certbot --nginx -d example.com -d www.example.com
```
Follow the prompts. Certbot will automatically modify your Nginx config to serve HTTPS and set up auto-renewal. Verify the renewal timer:
```bash
sudo systemctl status certbot.timer
```
---
## Directory structure summary
```
/var/www/example.com/ # Web root — your site files go here
├── index.php # Main entry point
├── wp-admin/ # (WordPress) admin panel
├── wp-content/ # (WordPress) themes, plugins, uploads
└── ... # Your application files
/etc/nginx/
├── sites-available/ # All site configs (enabled via symlink)
│ └── example.com
└── sites-enabled/ # Active site configs
└── example.com → ../sites-available/example.com
```
---
## Troubleshooting
**Nginx fails to start:** Check syntax with `sudo nginx -t`. Look at the error log: `sudo journalctl -u nginx`.
**PHP not processing:** Verify the PHP-FPM socket path matches in both your Nginx config and PHP-FPM pool config: `sudo nano /etc/php/8.3/fpm/pool.d/www.conf` — look for `listen =`.
**MySQL connection refused:** Make sure MySQL is running: `sudo systemctl status mariadb`. Check the socket: `sudo mysql -u root -p -S /var/run/mysqld/mysqld.sock`.
---
## What's next
- [Install WordPress](/wordpress/install-vps/) on your VPS
- [Deploy a Node.js app](/vps/nodejs-pm2/) with PM2
- [Set up automated backups](/vps/automated-backups/) with restic

230
content/vps/nodejs-pm2.md Normal file
View File

@@ -0,0 +1,230 @@
---
title: "Deploy a Node.js App with PM2 and Nginx"
description: "Run a Node.js application behind Nginx reverse proxy with PM2 process management."
section: vps
order: 4
---
# Deploy a Node.js App with PM2 and Nginx
This guide covers running a Node.js application on your Arcline VPS with PM2 for process management and Nginx as a reverse proxy.
---
## Prerequisites
- A VPS with Nginx installed
- A Node.js application (Express, Koa, Fastify, or similar)
- SSH access to your VPS
---
## Step 1 — Install Node.js
Install Node.js from the official NodeSource repository (recommended over the system package manager):
```bash
# Node.js 22.x (LTS)
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install nodejs -y
```
Verify:
```bash
node --version
npm --version
```
---
## Step 2 — Install PM2
PM2 is a process manager that keeps your Node.js app running, handles logging, and provides monitoring.
```bash
sudo npm install -g pm2
```
---
## Step 3 — Upload your application
Create a directory for your app:
```bash
sudo mkdir -p /var/www/example.com
sudo chown -R $USER:$USER /var/www/example.com
```
Upload your application files via SFTP, rsync, or git:
```bash
cd /var/www/example.com
git clone https://git.arcline.it/yourname/your-app.git .
npm install --production
```
---
## Step 4 — Start the app with PM2
```bash
pm2 start app.js --name example-app
```
Or if your app uses `npm start`:
```bash
pm2 start npm --name example-app -- start
```
Save the PM2 process list so it restarts on reboot:
```bash
pm2 save
pm2 startup
```
The `pm2 startup` command will output a command for you to run with sudo. Follow its instructions.
---
## Step 5 — Configure Nginx as a reverse proxy
Your Node.js app runs on a port like `3000` or `8080`. Nginx will sit in front of it, handling SSL and serving static assets directly.
Create an Nginx config:
```bash
sudo nano /etc/nginx/sites-available/example.com
```
```nginx
server {
listen 80;
server_name example.com www.example.com;
# If your app serves static files from a public directory
location /static/ {
alias /var/www/example.com/public/;
expires 1y;
add_header Cache-Control "public, immutable";
}
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
```
Enable the site:
```bash
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
Set up SSL:
```bash
sudo certbot --nginx -d example.com -d www.example.com
```
---
## Step 6 — Environment variables
Create an environment file:
```bash
nano /var/www/example.com/.env
```
```
PORT=3000
NODE_ENV=production
DATABASE_URL=postgres://...
```
Update your PM2 process to load it:
```bash
pm2 delete example-app
pm2 start app.js --name example-app --env-file /var/www/example.com/.env
pm2 save
```
Or use a PM2 ecosystem file (`ecosystem.config.js`):
```javascript
module.exports = {
apps: [{
name: 'example-app',
script: 'app.js',
env_file: '/var/www/example.com/.env',
instances: 2,
exec_mode: 'cluster',
max_memory_restart: '500M',
}]
};
```
Then:
```bash
pm2 start ecosystem.config.js
```
---
## PM2 useful commands
| Command | Description |
|---------|-------------|
| `pm2 list` | List all processes |
| `pm2 logs` | Show live logs |
| `pm2 logs --lines 100` | Show last 100 lines |
| `pm2 monit` | Real-time CPU/memory monitor |
| `pm2 restart example-app` | Restart an app |
| `pm2 reload example-app` | Zero-downtime reload |
| `pm2 stop example-app` | Stop an app |
| `pm2 delete example-app` | Remove from PM2 |
| `pm2 save` | Save process list |
| `pm2 startup` | Generate startup script |
---
## WebSocket support
If your app uses WebSockets, ensure the upgrade headers are passed through. The config above already includes them. For socket.io, add these to your Nginx config:
```nginx
location /socket.io/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 86400;
}
```
---
## What's next
- [Deploy a Go binary](/vps/go-systemd/) as a systemd service
- [Set up automated backups](/vps/automated-backups/) with restic
- [Install fail2ban](/vps/fail2ban/) for SSH protection

183
content/vps/static-site.md Normal file
View File

@@ -0,0 +1,183 @@
---
title: "Deploy a Static Site with Nginx"
description: "Host a static HTML site, Hugo, or Jekyll site on your Arcline VPS with Nginx."
section: vps
order: 3
---
# Deploy a Static Site with Nginx
Static sites are fast, secure, and simple to host. This guide covers deploying plain HTML, Hugo, and Jekyll sites on your Arcline VPS.
---
## Prerequisites
- A VPS with Nginx installed (see [Nginx + PHP-FPM + MySQL](/vps/nginx-php-mysql/) for setup)
- A domain pointed to your VPS IP
- Your static site files (HTML, CSS, JS) ready to upload
---
## Step 1 — Create the site directory
```bash
sudo mkdir -p /var/www/example.com
sudo chown -R $USER:$USER /var/www/example.com
```
---
## Step 2 — Upload your site files
### Via SFTP (FileZilla, Cyberduck)
Connect to your VPS:
```
Host: your.vps.ip.address
User: yourname
Port: 22
Protocol: SFTP
```
Upload files to `/var/www/example.com/`.
### Via rsync (command line)
```bash
rsync -avz --delete ./_site/ yourname@your.vps.ip.address:/var/www/example.com/
```
The `--delete` flag removes remote files that no longer exist locally — perfect for rebuilds.
### Via SCP
```bash
scp -r ./my-site/* yourname@your.vps.ip.address:/var/www/example.com/
```
---
## Step 3 — Configure Nginx
Create a site configuration:
```bash
sudo nano /etc/nginx/sites-available/example.com
```
```nginx
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.html;
# Gzip static assets
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# HTML files — shorter cache
location ~* \.html$ {
expires 1h;
add_header Cache-Control "public, must-revalidate";
}
location / {
try_files $uri $uri/ =404;
}
}
```
Enable the site:
```bash
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
---
## Step 4 — Set up SSL
```bash
sudo certbot --nginx -d example.com -d www.example.com
```
---
## Deploying a Hugo site
If you build your site with Hugo locally:
1. Generate the site: `hugo`
2. The output goes to the `public/` directory
3. Upload `public/` to your server
Or **build directly on the VPS** (for CI/CD style deployment):
```bash
# Install Hugo on the VPS
sudo apt install hugo -y
# Or download a specific version from GitHub releases
# Clone your repo
git clone https://git.arcline.it/yourname/your-site.git /var/www/example.com-source
# Build
cd /var/www/example.com-source
hugo -d /var/www/example.com
```
---
## Deploying a Jekyll site
Jekyll requires Ruby. Install it on the VPS:
```bash
sudo apt install ruby-full build-essential -y
sudo gem install jekyll bundler
```
Clone and build:
```bash
git clone https://git.arcline.it/yourname/your-site.git /var/www/example.com-source
cd /var/www/example.com-source
bundle install
jekyll build -d /var/www/example.com
```
---
## Security headers for static sites
Add this to your Nginx config inside the `server` block for recommended security headers:
```nginx
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()";
```
Test and reload:
```bash
sudo nginx -t && sudo systemctl reload nginx
```
---
## What's next
- [Deploy a Node.js app](/vps/nodejs-pm2/) with PM2 + Nginx
- [Deploy a Go binary](/vps/go-systemd/) as a systemd service
- [Set up automated backups](/vps/automated-backups/) with restic