← Back to Projects

NGINX on Raspberry Pi

Practical, secure, production-ready steps to host websites and reverse proxies on your Pi.

Quick guide • Raspberry Pi 4/5 • Raspberry Pi OS / Ubuntu Server

Overview

Goal: Install and configure NGINX on a Raspberry Pi so it serves sites securely (HTTPS), supports virtual hosts, and can act as a reverse proxy for web apps.

Prerequisites

Step 1

Update OS & Set static IP (optional but recommended)

Always start by updating packages and setting a predictable IP address for your Pi.

sudo apt update && sudo apt upgrade -y # optional (Raspberry Pi OS): edit /etc/dhcpcd.conf or use netplan on Ubuntu # Example (Ubuntu / netplan for a static IPv4): # /etc/netplan/01-netcfg.yaml network: version: 2 ethernets: eth0: dhcp4: no addresses: [192.168.1.50/24] gateway4: 192.168.1.1 nameservers: addresses: [8.8.8.8,8.8.4.4] sudo netplan apply
Step 2

Install NGINX

Use the distribution package for stability. This installs a systemd service that starts on boot.

sudo apt install nginx -y # start & enable sudo systemctl enable --now nginx # verify sudo systemctl status nginx nginx -v
Step 3

Open firewall ports (ufw) — allow HTTP/HTTPS

# install ufw if needed sudo apt install ufw -y sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' # opens 80 and 443 sudo ufw enable sudo ufw status
Step 4

Create a server block (virtual host)

Put site files under /var/www/example.com and create an NGINX server block.

# create site dir sudo mkdir -p /var/www/example.com/html sudo chown -R $USER:$USER /var/www/example.com/html sudo chmod -R 755 /var/www/example.com # sample index cat > /var/www/example.com/html/index.html <<'EOF' <!doctype html> <html><head><meta charset="utf-8"/><title>Hello from Pi</title></head><body> <h1>Hello from Raspberry Pi NGINX</h1> </body></html> EOF # create server block file sudo tee /etc/nginx/sites-available/example.com > /dev/null <<'NGCONF' server { listen 80; listen [::]:80; server_name example.com www.example.com; root /var/www/example.com/html; index index.html index.htm; location / { try_files $uri $uri/ =404; } } NGCONF sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/ # test & reload sudo nginx -t && sudo systemctl reload nginx
Step 5

Enable HTTPS with Let's Encrypt (Certbot)

Use the Certbot NGINX plugin to automatically obtain and install certificates.

sudo apt install certbot python3-certbot-nginx -y sudo certbot --nginx -d example.com -d www.example.com # automatic renewal is installed as a systemd timer or cron job; test with: sudo certbot renew --dry-run
If you are behind NAT, forward ports 80 and 443 from your router to the Pi, or use DNS-based validation / a DNS provider plugin.
Step 6

Basic security hardening

  • Turn off server tokens so NGINX won't advertise version numbers.
  • Set up strong TLS ciphers and HSTS.
  • Disable unused modules and keep the system updated.
# in /etc/nginx/nginx.conf (http block) server_tokens off; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:...'; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"; # reload nginx sudo nginx -t && sudo systemctl reload nginx
Important: Keep the cipher list up to date; use trusted SSL configuration guides (Mozilla SSL Configuration Generator) for production.
Step 7

Use NGINX as a reverse proxy (example for a Node app)

# server block (example) server { listen 80; server_name app.example.com; 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_cache_bypass $http_upgrade; } } # restart nginx after configuration changes sudo nginx -t && sudo systemctl reload nginx
Step 8

Performance & caching tips

  • Enable gzip compression.
  • Use browser caching headers for static assets.
  • Tune worker_processes and worker_connections in nginx.conf.
# example nginx.conf tuning (http block) worker_processes auto; worker_rlimit_nofile 100000; events { worker_connections 1024; } http { gzip on; gzip_min_length 1000; gzip_proxied any; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; sendfile on; tcp_nopush on; }
Step 9

Monitoring, logs & backups

  • Access logs: /var/log/nginx/access.log, error: /var/log/nginx/error.log
  • Use logrotate (default) to prevent filesystem fill-up.
  • Back up /etc/nginx and your /var/www site content.
# quick troubleshooting commands sudo tail -n 200 /var/log/nginx/error.log sudo journalctl -u nginx -f sudo nginx -t sudo ss -ltnp | grep nginx
Step 10

Optional: Add fail2ban for brute-force protection

sudo apt install fail2ban -y # create a basic jail for nginx (example) sudo tee /etc/fail2ban/jail.d/nginx.conf > /dev/null <<'FJ' [nginx-http-auth] enabled = true filter = nginx-http-auth port = http,https logpath = /var/log/nginx/error.log maxretry = 3 FJ sudo systemctl restart fail2ban

Common troubleshooting

T-1

NGINX won't start

  • Run sudo nginx -t — fix syntax or missing semicolons.
  • Check /var/log/nginx/error.log and journalctl -u nginx.
  • Ensure port 80/443 not already bound (run ss -ltnp).
T-2

Let's Encrypt validation failed

  • Confirm DNS points to your Pi's public IP.
  • Make sure ports 80 and 443 are forwarded if behind NAT.
  • Use --staging flag to test to avoid hitting rate limits.

Wrap-up & best practices

Done: You now have a secure, maintainable NGINX server on your Raspberry Pi.