nginx Setup
Overview
nginx (pronounced “engine-x”) is a web server that can serve static files and act as a reverse proxy for backend applications. In a typical setup:
Internet
│
▼
┌─────────────────────────────┐
│ nginx │
│ │
│ :80 (HTTP) ──► redirect │
│ :443 (HTTPS) ──┬──► static files (/var/www/)
│ └──► proxy to localhost:3000
└─────────────────────────────┘
nginx handles:
- SSL/TLS termination (HTTPS)
- Serving static files efficiently
- Proxying requests to backend applications
- Load balancing (if needed)
Prerequisites
- VPS setup completed (see VPS Setup)
- UFW configured (see UFW Setup)
- Domain name pointed to your VPS IP (optional, but required for SSL)
Installation
Update package list and install nginx:
sudo apt update
sudo apt install -y nginx
Check the installed version:
nginx -v
Enable nginx to start on boot and start it now:
sudo systemctl enable nginx
sudo systemctl start nginx
Verify it’s running:
sudo systemctl status nginx
Firewall Rules
nginx needs ports 80 (HTTP) and 443 (HTTPS) open. Allow both with a single command (see UFW Setup for details):
sudo ufw allow 'Nginx Full'
Test Installation
Open your browser and visit:
http://<vps-ip>
You should see the default nginx welcome page. This confirms nginx is installed and the firewall is configured correctly.
Important Directories
nginx organizes configuration files in a specific structure:
| Path | Description |
|---|---|
/etc/nginx/nginx.conf | Main configuration file (rarely edited directly) |
/etc/nginx/sites-available/ | Store all site configurations here |
/etc/nginx/sites-enabled/ | Symlinks to enabled sites (nginx only reads this) |
/var/www/ | Default location for website files |
/var/log/nginx/ | Access and error logs |
The sites-available/sites-enabled pattern lets you easily enable or disable sites without deleting configurations.
Server Block (Virtual Host)
A server block defines how nginx handles requests for a specific domain. Each domain gets its own configuration file.
Create a Configuration File
sudo vim /etc/nginx/sites-available/<domain>
Static Site Configuration
For serving HTML, CSS, and JavaScript files:
server {
listen 80;
listen [::]:80;
server_name <domain>;
root /var/www/<domain>;
index index.html;
location / {
try_files $uri $uri/ =404;
}
access_log /var/log/nginx/<domain>.access.log;
error_log /var/log/nginx/<domain>.error.log;
}
| Directive | Purpose |
|---|---|
listen 80 | Accept HTTP connections on port 80 |
listen [::]:80 | Same for IPv6 |
server_name | The domain this block responds to |
root | Directory containing website files |
index | Default file to serve for directory requests |
try_files | Try the URI as a file, then as a directory, then return 404 |
Create Web Root and Test Page
Create the directory for your website files:
sudo mkdir -p /var/www/<domain>
sudo chown -R $USER:$USER /var/www/<domain>
Create a simple test page:
echo "<h1>Welcome to <domain></h1>" > /var/www/<domain>/index.html
Enable the Site
Create a symlink from sites-available to sites-enabled:
sudo ln -s /etc/nginx/sites-available/<domain> /etc/nginx/sites-enabled/
Test the configuration for syntax errors:
sudo nginx -t
If the test passes, reload nginx to apply changes:
sudo systemctl reload nginx
Visit http://<domain> to see your test page.
Reverse Proxy
A reverse proxy forwards requests to a backend application (e.g., Node.js, Python, Go) running on localhost.
Client Request
│
▼
┌─────────────┐ ┌─────────────────┐
│ nginx │ ──► │ Your App │
│ :443 │ │ localhost:3000 │
└─────────────┘ └─────────────────┘
Reverse Proxy Configuration
server {
listen 80;
server_name <domain>;
location / {
proxy_pass http://localhost: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;
}
}
| Directive | Purpose |
|---|---|
proxy_pass | URL of the backend application |
proxy_http_version 1.1 | Use HTTP/1.1 for upstream connections |
Host $host | Pass the original Host header to the backend |
X-Real-IP | Pass the client’s real IP address |
X-Forwarded-For | Chain of proxy IPs |
X-Forwarded-Proto | Original protocol (http or https) |
WebSocket Support
If your backend uses WebSockets (real-time connections), add these headers:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_cache_bypass $http_upgrade;
This tells nginx to upgrade the connection from HTTP to WebSocket when requested.
Serving Multiple Applications
You can serve multiple applications under one domain using different location blocks. Each location can serve static files or proxy to different backend applications.
domain.com/ → /var/www/<domain> (static files)
domain.com/app → localhost:3000 (backend app)
Example Configuration
server {
listen 443 ssl;
server_name <domain>;
# Main site serves static files
location / {
root /var/www/<domain>;
try_files $uri $uri/ =404;
}
# App at /app subpath
location /app {
proxy_pass http://localhost:3000;
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;
}
}
Trailing Slash in proxy_pass
The trailing slash in proxy_pass changes how nginx forwards requests:
Without trailing slash - preserves the full path:
location /app {
proxy_pass http://localhost:3000;
}
# Request: domain.com/app/page → Backend receives: /app/page
With trailing slash - strips the location prefix:
location /app {
proxy_pass http://localhost:3000/;
}
# Request: domain.com/app/page → Backend receives: /page
Use the trailing slash when your backend application serves from root. Without the trailing slash, your application must handle requests with the /app prefix included.
Application Configuration
Your application must be configured to handle its base path. If using the trailing slash in proxy_pass, your app serves from root as normal. Without the trailing slash, configure your app to serve from /app. If routes return 404 or assets fail to load, check this configuration.
Test by visiting https://<domain>/app in your browser.
Common Commands
| Command | Description |
|---|---|
sudo nginx -t | Test configuration syntax |
sudo systemctl reload nginx | Apply config changes (no downtime) |
sudo systemctl restart nginx | Full restart |
sudo systemctl stop nginx | Stop nginx |
sudo tail -f /var/log/nginx/access.log | Watch access logs in real-time |
sudo tail -f /var/log/nginx/error.log | Watch error logs in real-time |
Always run nginx -t before reloading to catch syntax errors.