Nginx is the default reverse proxy / static-file server on most modern Linux stacks. This guide installs the upstream Nginx package on Debian 12 (not the older one in the distro repo), serves a basic site, terminates TLS with Let's Encrypt, and adds two of the headers every public site should send.
Prerequisites
- Debian 12 with
sudo. - A DNS A/AAAA record pointing at the server.
- Outbound TCP/443 + 80 reachable for ACME HTTP-01 challenges.
Step 1: Add the upstream Nginx repo
sudo apt update
sudo apt install -y curl gnupg2 ca-certificates lsb-release debian-archive-keyring
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/debian $(lsb_release -cs) nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
sudo apt update
sudo apt install -y nginx
sudo systemctl enable --now nginx
Step 2: Open the firewall
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw status
Step 3: Serve a static site
sudo mkdir -p /var/www/example.sa
echo '<h1>Hello from SKYLINE</h1>' | sudo tee /var/www/example.sa/index.html
sudo chown -R www-data:www-data /var/www/example.sa
Drop /etc/nginx/conf.d/example.sa.conf:
server {
listen 80;
listen [::]:80;
server_name example.sa www.example.sa;
root /var/www/example.sa;
index index.html;
access_log /var/log/nginx/example.sa.access.log;
error_log /var/log/nginx/example.sa.error.log;
location / {
try_files $uri $uri/ =404;
}
}
Test syntax and reload:
sudo nginx -t && sudo systemctl reload nginx
curl -fI http://example.sa/
Step 4: TLS with Let's Encrypt
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.sa -d www.example.sa \
--agree-tos --redirect -m ops@example.sa --no-eff-email
Certbot writes the cert paths, adds the redirect block, and installs a systemd renewal timer:
sudo systemctl list-timers certbot.timer
sudo certbot renew --dry-run
Step 5: Add the basic security headers
Drop /etc/nginx/conf.d/headers.conf:
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Frame-Options "SAMEORIGIN" always;
Reload Nginx, then verify with curl -I https://example.sa/.
Step 6: A simple reverse-proxy block
To put Nginx in front of an app on 127.0.0.1:3000 (Node, Python, anything):
location / {
proxy_pass http://127.0.0.1:3000;
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;
proxy_read_timeout 60s;
}
Verify
sudo nginx -t
curl -fI https://example.sa/
curl -s -o /dev/null -w "%{http_code}\n" https://example.sa/missing # expect 404
Conclusion
Upstream Nginx + Certbot is the easiest path to a reliable HTTPS-by-default server on Debian. Keep your site configs in /etc/nginx/conf.d/*.conf (or git) and you have everything you need.
Next steps
- Add a cron job to back up
/etc/nginxdaily. - Tighten the host with unattended security upgrades.
- For Docker-based services, see Docker + Compose (same on Debian).
Comments
0 total · 0 threads