How to Add Nginx on a Server
Mudassar H.
9/8/2025
devopsnginxweblinux
In this article we’ll install Nginx, set up a basic site, and confirm it’s running.
This post also shows MDX features: code blocks, tables, lists, React components, and more.
Update System Packages
sudo apt update && sudo apt upgrade -y
Install Nginx
sudo apt install nginx -y
After installation, check status:
systemctl status nginx
If it’s not active, start and enable:
sudo systemctl enable --now nginx
Basic Firewall (Optional)
sudo ufw allow 'Nginx Full'
sudo ufw status
Default Directory
The default root (on Ubuntu/Debian):
/var/www/html
Replace the index:
echo "<h1>Nginx Works!</h1>" | sudo tee /var/www/html/index.html
Open the server IP in a browser.
Simple Server Block
Create a new site:
sudo mkdir -p /var/www/example.com
sudo nano /etc/nginx/sites-available/example.com
Config (minimal):
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Enable it:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Quick Reference Table
| Step | Action | Command / Info |
|---|---|---|
| 1 | Update packages | apt update |
| 2 | Install nginx | apt install nginx |
| 3 | Enable service | systemctl enable --now nginx |
| 4 | Add server block | edit config + reload |
Common Pitfalls
- Forgetting to reload after config change:
sudo systemctl reload nginx - Wrong root path ownership: fix with
sudo chown -R $USER:$USER /var/www/example.com - DNS not propagated yet: use raw IP temporarily.
Next Steps
- Add SSL with Certbot
- Set up reverse proxy for Node / Python app
- Add caching and gzip/brotli
That’s it—your basic Nginx setup is live.
Set Up Nginx as a Reverse Proxy for a Node App
Overview
We’ll run a Node.js app on port 3000 and proxy public traffic through Nginx on port 80.
Sample Node App
mkdir node-proxy-app && cd node-proxy-app
npm init -y
npm i express
Create server.js:
import express from 'express';
const app = express();
app.get('/', (_req, res) => {
res.send('<h2>Hello from Node behind Nginx!</h2>');
});
app.listen(3000, () => console.log('Node app on :3000'));
Run it:
node server.js
systemd Service (Optional but Recommended)
sudo nano /etc/systemd/system/node-proxy.service
Service file:
[Unit]
Description=Node Proxy Example
After=network.target
[Service]
Type=simple
WorkingDirectory=/home/youruser/node-proxy-app
ExecStart=/usr/bin/node server.js
Restart=on-failure
User=youruser
Environment=NODE_ENV=production
# Hardening (optional)
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target
Enable + start:
sudo systemctl daemon-reload
sudo systemctl enable --now node-proxy
Nginx Reverse Proxy Block
sudo nano /etc/nginx/sites-available/node-proxy.conf
Paste:
server {
listen 80;
server_name node.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Optional: health endpoint caching off
location /health {
proxy_pass http://127.0.0.1:3000/health;
add_header Cache-Control "no-store";
}
}
Enable + test:
sudo ln -s /etc/nginx/sites-available/node-proxy.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Add a Health Route
In server.js:
app.get('/health', (_req, res) => {
res.json({ ok: true, uptime: process.uptime() });
});
Hardening Ideas
- Use
limit_req_zonefor rate limiting - Add gzip or brotli
- Put Node behind a socket (
/run/node.sock) withproxy_pass http://unix:/run/node.sock:; - Enable HTTPS (Let’s Encrypt)
Quick Tag Table
| Tag | Why it matters |
|---|---|
| reverse-proxy | Architectural pattern |
| node | Backend runtime |
| nginx | Front layer / static + proxy |
Deploy Notes
Don’t forget firewall rules and to restart services after updating units or configs.
Wrap Up
You now have:
- A managed Node process (systemd)
- Nginx proxying traffic
- A foundation for SSL + scaling