Tech Story
As a platform engineer, I want the Linode VPS configured with a reverse proxy, automatic TLS certificates, a least-privilege deploy user, and a clean directory structure so that Station can be deployed securely without running as root or exposing unencrypted traffic.
ELI5 Context
What is Nginx (as a reverse proxy)? Nginx sits in front of your apps like a receptionist. When a request arrives for api.drdnt.org, Nginx says "that's the NestJS backend" and forwards it. It also handles HTTPS (the padlock) so your NestJS app doesn't have to worry about SSL at all — it just speaks plain HTTP internally.
What is Let's Encrypt / Certbot? Let's Encrypt is a free service that issues SSL certificates (what makes https:// work). Without a certificate, browsers show a scary "not secure" warning and all traffic is sent in plain text — anyone on the same network can read it. Certbot is the tool that automatically requests the certificate and renews it before it expires (certificates last 90 days). You set it up once and forget about it.
Why a deploy user instead of root? Root can do anything on the server — delete the OS, read every file, etc. If your deployment process is ever compromised (e.g. a malicious GitHub Actions run), root access = total server compromise. A deploy user can only do what it needs: run Docker commands and restart services. Principle of least privilege.
What is a swap file? RAM is fast but limited (2GB). A swap file is disk space that pretends to be RAM when you run out. It's slow (disk vs RAM), but it prevents your server from crashing when memory spikes. Think of it as an emergency overflow bucket.
Technical Elaboration
New files (in infra/scripts/)
infra/scripts/bootstrap-vps.sh
A one-time setup script to run manually on the VPS after it's provisioned. Documents and automates:
- Update system packages (
apt update && apt upgrade -y)
- Install Docker + Docker Compose plugin (official Docker repo)
- Install Nginx
- Install Certbot + Nginx plugin (
certbot python3-certbot-nginx)
- Create
deploy user: useradd -m -s /bin/bash deploy
- Add
deploy to docker group (so it can run Docker without sudo)
- Add SSH public key to
~deploy/.ssh/authorized_keys
- Create
/opt/station/ directory, set ownership to deploy
- Create 2GB swap file at
/swapfile (prevents OOM kills on 2GB RAM)
infra/nginx/api.drdnt.org.conf
server {
listen 80;
server_name api.drdnt.org;
# Certbot will add the HTTPS block after cert issuance
location / {
proxy_pass http://localhost:3001;
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;
}
}
infra/nginx/station.drdnt.org.conf
Proxies to the React frontend container (port 5173 or nginx:80 inside Docker).
infra/nginx/bot.drdnt.org.conf
Reserved — proxies to station-bot health endpoint (port TBD). Placeholder config.
infra/scripts/issue-certs.sh
Documents the one-time Certbot command:
certbot --nginx -d api.drdnt.org -d station.drdnt.org -d bot.drdnt.org
Certbot edits the Nginx configs to add HTTPS + auto-redirect from HTTP.
infra/scripts/setup-swap.sh
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab # persist across reboots
infra/README.md (update from #106)
Add a "VPS Baseline" section with step-by-step instructions referencing these scripts.
Directory structure on VPS after setup
/opt/station/
docker-compose.prod.yml (deployed by CI)
.env.production (set manually once, never in git)
logs/
Definition of Done
Dependencies
Tech Story
As a platform engineer, I want the Linode VPS configured with a reverse proxy, automatic TLS certificates, a least-privilege deploy user, and a clean directory structure so that Station can be deployed securely without running as root or exposing unencrypted traffic.
ELI5 Context
What is Nginx (as a reverse proxy)? Nginx sits in front of your apps like a receptionist. When a request arrives for
api.drdnt.org, Nginx says "that's the NestJS backend" and forwards it. It also handles HTTPS (the padlock) so your NestJS app doesn't have to worry about SSL at all — it just speaks plain HTTP internally.What is Let's Encrypt / Certbot? Let's Encrypt is a free service that issues SSL certificates (what makes
https://work). Without a certificate, browsers show a scary "not secure" warning and all traffic is sent in plain text — anyone on the same network can read it. Certbot is the tool that automatically requests the certificate and renews it before it expires (certificates last 90 days). You set it up once and forget about it.Why a deploy user instead of root? Root can do anything on the server — delete the OS, read every file, etc. If your deployment process is ever compromised (e.g. a malicious GitHub Actions run), root access = total server compromise. A
deployuser can only do what it needs: run Docker commands and restart services. Principle of least privilege.What is a swap file? RAM is fast but limited (2GB). A swap file is disk space that pretends to be RAM when you run out. It's slow (disk vs RAM), but it prevents your server from crashing when memory spikes. Think of it as an emergency overflow bucket.
Technical Elaboration
New files (in
infra/scripts/)infra/scripts/bootstrap-vps.shA one-time setup script to run manually on the VPS after it's provisioned. Documents and automates:
apt update && apt upgrade -y)certbot python3-certbot-nginx)deployuser:useradd -m -s /bin/bash deploydeploytodockergroup (so it can run Docker without sudo)~deploy/.ssh/authorized_keys/opt/station/directory, set ownership todeploy/swapfile(prevents OOM kills on 2GB RAM)infra/nginx/api.drdnt.org.confinfra/nginx/station.drdnt.org.confProxies to the React frontend container (port 5173 or nginx:80 inside Docker).
infra/nginx/bot.drdnt.org.confReserved — proxies to station-bot health endpoint (port TBD). Placeholder config.
infra/scripts/issue-certs.shDocuments the one-time Certbot command:
Certbot edits the Nginx configs to add HTTPS + auto-redirect from HTTP.
infra/scripts/setup-swap.shinfra/README.md(update from #106)Add a "VPS Baseline" section with step-by-step instructions referencing these scripts.
Directory structure on VPS after setup
Definition of Done
infra/scripts/bootstrap-vps.shwritten and tested on the VPSapi.drdnt.org,station.drdnt.org,bot.drdnt.org; HTTPS works and HTTP redirects to HTTPScertbot renew --dry-runpassesdeployuser exists, is indockergroup, can SSH with deploy key, cannot sudo/opt/station/exists, owned bydeployfree -hshows swap)infra/scripts/with inline comments explaining each stepDependencies