en
How to Install and Configure Nginx on a VPS
Nginx is the world's most widely deployed web server, known for its exceptional performance under high concurrency and low memory footprint. This guide covers installation, basic configuration, virtual host setup, SSL termination with Let's Encrypt, and essential performance tuning for a production VPS deployment.
Need this done for your project?
We implement, you ship. Async, documented, done in days.
Installing Nginx and Basic Configuration
Install Nginx from official repositories for the latest stable version. On Debian/Ubuntu: `apt update && apt install -y nginx`. On RHEL/AlmaLinux: `dnf install -y nginx`. Enable and start the service with `systemctl enable --now nginx`. Verify it is running with `systemctl status nginx` and test by visiting your server IP in a browser - you should see the default Nginx welcome page.
The main configuration file is at `/etc/nginx/nginx.conf`. Key global settings include `worker_processes auto` (match CPU cores), `worker_connections 1024` (connections per worker), and `keepalive_timeout 65`. Do not edit virtual host blocks directly in the main config. Instead, use the `sites-available` / `sites-enabled` pattern: place each site configuration in `/etc/nginx/sites-available/yoursite.conf` and create a symlink to `/etc/nginx/sites-enabled/`.
After any configuration change, always test before reloading: `nginx -t` performs a syntax check and reports errors without interrupting traffic. If the test passes, apply changes gracefully with `systemctl reload nginx` (not restart, which drops active connections). On RHEL-based systems without the sites-available pattern, place site configs in `/etc/nginx/conf.d/yoursite.conf`.
Setting Up Virtual Hosts and Server Blocks
A virtual host (server block in Nginx terminology) lets a single server handle multiple domains. Create a config file at `/etc/nginx/sites-available/example.com` with the following structure: define a `server` block listening on port 80, set `server_name example.com www.example.com`, configure `root /var/www/example.com/html`, and set the `index` directive. Create the document root with `mkdir -p /var/www/example.com/html` and place your files there.
For a reverse proxy setup (common for Node.js, Python, or other application servers), replace the root/index directives with a `location /` block containing `proxy_pass http://127.0.0.1:3000`. Add proxy headers: `proxy_set_header Host $host`, `proxy_set_header X-Real-IP $remote_addr`, and `proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for`. This passes client information through to your application so it can log accurate IP addresses and handle redirects correctly.
Enable the site with `ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/`, test with `nginx -t`, and reload. You can host dozens of domains on a single VPS this way. Disable the default site if you are not using it: `rm /etc/nginx/sites-enabled/default`. A dangling default server block can expose internal information to scanners that connect via IP rather than hostname.
SSL with Let's Encrypt and Certbot
HTTPS is mandatory for any production site. Let's Encrypt provides free, automatically renewing SSL certificates. Install Certbot: `apt install -y certbot python3-certbot-nginx`. Obtain and automatically configure a certificate with `certbot --nginx -d example.com -d www.example.com`. Certbot will modify your Nginx config to add SSL directives, redirect HTTP to HTTPS, and configure HSTS headers automatically.
After obtaining a certificate, review what Certbot added to your config. It will have set `ssl_certificate` and `ssl_certificate_key` paths, configured `ssl_protocols TLSv1.2 TLSv1.3`, and added a redirect from port 80 to 443. Verify TLS configuration quality using `curl -sI https://example.com` to check response headers, or use an online SSL checker. Ensure TLSv1.0 and TLSv1.1 are disabled as they are deprecated and vulnerable.
Certbot registers a systemd timer or cron job to auto-renew certificates before expiry. Test the renewal process with `certbot renew --dry-run`. Let's Encrypt certificates expire after 90 days, so automated renewal is essential. If your server is behind a firewall, ensure port 80 is open during renewal (Certbot uses HTTP-01 challenge by default) or switch to DNS-01 challenge which does not require port 80.
Performance Tuning for Production Traffic
Enable Gzip compression to reduce bandwidth and improve load times. In `/etc/nginx/nginx.conf` within the `http` block: `gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml; gzip_min_length 1000; gzip_comp_level 6;`. Do not compress already-compressed formats like images and videos - it wastes CPU without reducing size.
Configure browser caching with `expires` directives. Static assets should be cached aggressively: add a `location ~* .(jpg|png|gif|css|js|ico|woff2)$` block with `expires 30d` and `add_header Cache-Control "public, immutable"`. For API endpoints and HTML, use `expires -1` to prevent stale content. Correct caching headers can cut server load by 60-70% for content-heavy sites.
Enable sendfile and TCP optimizations: `sendfile on; tcp_nopush on; tcp_nodelay on;`. These kernel-level settings improve file transfer efficiency and reduce latency. Set `client_max_body_size 20M` if your application accepts file uploads. Tune `keepalive_requests 100` and `keepalive_timeout 65` based on your traffic patterns. Monitor Nginx with the stub status module (`stub_status on` in a location block) to track active connections and request rates in real time.
Related Services
Why Anubiz Host
100% async — no calls, no meetings
Delivered in days, not weeks
Full documentation included
Production-grade from day one
Security-first approach
Post-delivery support included
Ready to get started?
Skip the research. Tell us what you need, and we'll scope it, implement it, and hand it back — fully documented and production-ready.