Installing Nginx on a VPS – A Step-by-Step Guide from A to Z for Beginners

Published on
Belongs to Category: Hosting Knowledge|Posted by: Le Thanh Giang|||11 min read
Facebook share iconLinkedIn share iconTwitter share iconPinterest share iconTumblr share icon
How to Install Nginx on a VPS – A Complete A-Z Guide (Ubuntu 22.04/24.04)

Introduction

Nginx is one of the most popular and powerful web servers in use today, powering major websites like Netflix, Dropbox, and WordPress.com. Thanks to its event-driven architecture, Nginx can handle thousands of concurrent connections with minimal resource consumption.

When you get a VPS (Virtual Private Server), the first thing to do is install and configure a web server. This guide walks you through every step from A to Z on how to install Nginx on a VPS running Ubuntu 22.04 or 24.04.

If you're new to Nginx, start with our article What is Nginx? A Comprehensive Guide. And if you don't have a VPS yet, check out What is VPS? Comparison with Shared Hosting.

Install Nginx on VPS

Prerequisites

Before we begin, make sure you have:

Requirements

  • A VPS running Ubuntu 22.04 or 24.04 (LTS).
  • Root access or a user with sudo privileges.
  • SSH access to your VPS (use PuTTY on Windows or Terminal on macOS/Linux).
  • A domain name pointing to your VPS IP (if you want to run a live website).

Connect via SSH

ssh user@your-server-ip

Replace user with your username and your-server-ip with your actual VPS IP address.

Update the System

Always update the package list before installing new software:

sudo apt update
sudo apt upgrade -y

This ensures you're installing the latest available versions.

SSH connection to VPS

Step 1: Install Nginx

1.1. Install from the Official Repository

Ubuntu includes Nginx in its default package repository:

sudo apt install nginx -y

Once installed, Nginx starts automatically. Verify:

sudo systemctl status nginx

You should see output similar to:

● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
     Active: active (running) since ...

1.2. Configure the Firewall (UFW)

If UFW (Uncomplicated Firewall) is active, open the necessary ports:

sudo ufw allow 'Nginx Full'

Check the status:

sudo ufw status

Expected output:

Status: active

To                         Action      From
--                         ------      ----
Nginx Full                 ALLOW       Anywhere
Nginx Full (v6)            ALLOW       Anywhere (v6)

Nginx Full opens both port 80 (HTTP) and 443 (HTTPS).

1.3. Verify Nginx Is Running

Open a browser and visit http://your-server-ip. If you see the "Welcome to nginx!" page, you've installed it successfully.

To find your VPS IP:

curl -4 icanhazip.com
Welcome to Nginx page

1.4. Important Directory Structure

Familiarize yourself with these key Nginx paths:

PathDescription
/etc/nginx/nginx.confMain configuration file
/etc/nginx/sites-available/Configuration files for each site (not yet active)
/etc/nginx/sites-enabled/Symlinks to enabled sites
/etc/nginx/conf.d/Additional configuration snippets
/var/www/Root directory for website files
/var/log/nginx/access.logAccess log
/var/log/nginx/error.logError log

Learn more: What is a Web Server?


Step 2: Configure Virtual Hosts (Server Blocks)

Virtual Hosts (called Server Blocks in Nginx) let you run multiple websites on a single VPS.

2.1. Create the Website Directory

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

Create a sample index.html:

nano /var/www/example.com/html/index.html

Add some content:

<html>
    <head>
        <title>Welcome to example.com</title>
    </head>
    <body>
        <h1>Nginx installed successfully!</h1>
        <p>Your site is running on example.com</p>
    </body>
</html>

2.2. Create a Server Block

Create the configuration file:

sudo nano /etc/nginx/sites-available/example.com

Add the following:

server {
    listen 80;
    listen [::]:80;

    root /var/www/example.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name example.com www.example.com;

    location / {
        try_files $uri $uri/ =404;
    }
}

2.3. Enable the Server Block

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

Test the configuration before reloading:

sudo nginx -t

If the output says test is successful, reload Nginx:

sudo systemctl reload nginx

2.4. Disable the Default Server Block

Nginx ships with a default server block. Remove it:

sudo rm /etc/nginx/sites-enabled/default
sudo systemctl reload nginx

Tip: Use sudo unlink /etc/nginx/sites-enabled/default to preserve the original file.

Visit http://example.com — you should see your new site.


Step 3: Integrate PHP-FPM for WordPress

To run WordPress or any PHP-based CMS, you need PHP-FPM.

3.1. Install PHP-FPM

sudo apt install php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-xmlrpc php-zip php-opcache -y

This installs PHP 8.3 (default on Ubuntu 24.04) along with essential extensions for WordPress.

3.2. Configure Nginx for PHP-FPM

Edit your server block:

sudo nano /etc/nginx/sites-available/example.com

Add the location ~ \.php$ block:

server {
    listen 80;
    listen [::]:80;

    root /var/www/example.com/html;
    index index.php index.html index.htm;

    server_name example.com www.example.com;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
    }

    location ~ /\.ht {
        deny all;
    }
}

Test and reload:

sudo nginx -t
sudo systemctl reload nginx

3.3. Verify PHP Is Working

Create a PHP test file:

echo "<?php phpinfo(); ?>" | sudo tee /var/www/example.com/html/info.php

Visit http://example.com/info.php. If you see the PHP info page, PHP-FPM is working.

Important: Delete info.php after testing as it exposes sensitive information:

sudo rm /var/www/example.com/html/info.php

Learn more about how to optimize WordPress hosting after completing this setup.


Step 4: Secure Nginx

4.1. Disable Server Version Information

By default, Nginx includes its version in HTTP headers. Disable it:

Open the main config:

sudo nano /etc/nginx/nginx.conf

Add this line inside the http block:

server_tokens off;

4.2. Add Security Headers

Include these headers in your server block:

add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;

4.3. Limit Upload Size

Nginx caps file uploads at 1MB by default. To increase it:

client_max_body_size 128M;

4.4. Prevent Brute Force and DDoS

Limit requests from a single IP:

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;

server {
    ...
    location / {
        limit_req zone=mylimit burst=20 nodelay;
        ...
    }
}

4.5. Block Access to Sensitive Files

location ~ /\.(?!well-known) {
    deny all;
}

location = /wp-config.php {
    deny all;
}

Test and reload after each change:

sudo nginx -t && sudo systemctl reload nginx

See also: Comprehensive website security guide.


Step 5: Install SSL with Let's Encrypt

HTTPS is mandatory for modern websites. Let's Encrypt provides free SSL certificates.

5.1. Install Certbot

sudo apt install certbot python3-certbot-nginx -y

5.2. Obtain an SSL Certificate

sudo certbot --nginx -d example.com -d www.example.com

Certbot will automatically:

  1. Verify domain ownership.
  2. Issue the SSL certificate.
  3. Update the Nginx configuration with HTTPS redirect.

5.3. Test Auto-Renewal

sudo certbot renew --dry-run

Let's Encrypt certificates are valid for 90 days. Certbot handles auto-renewal via a cron job.

Learn more: What is SSL? and What is HTTPS?

After SSL installation, your Nginx config will look like:

server {
    listen 443 ssl;
    server_name example.com www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;

    root /var/www/example.com/html;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
    }
}

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

For a Cloudflare-based approach, see Install Free SSL Cloudflare.

Install Let's Encrypt SSL for Nginx

Step 6: Optimize Nginx Performance

6.1. Configure Worker Processes

Edit /etc/nginx/nginx.conf:

worker_processes auto;
worker_connections 1024;
keepalive_timeout 65;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
  • worker_processes auto — matches the number of CPU cores.
  • worker_connections — max connections per worker.
  • sendfile — optimizes static file delivery.
  • tcp_nopush / tcp_nodelay — TCP optimization.

6.2. Enable Gzip Compression

gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript text/javascript image/svg+xml;

6.3. Cache Static Files

Inside your server block:

location ~* \.(jpg|jpeg|png|gif|ico|css|js|webp|avif|woff|woff2)$ {
    expires 365d;
    add_header Cache-Control "public, immutable";
}

6.4. WordPress-Specific Optimizations

If you're running WordPress, add these rules:

# Cache static files
location ~* \.(jpg|jpeg|png|gif|ico|css|js|webp|avif)$ {
    expires 365d;
    add_header Cache-Control "public, immutable";
}

# Deny access to dot files
location ~ /\.(?!well-known) {
    deny all;
}

# Protect wp-login from brute force
location = /wp-login.php {
    limit_req zone=login burst=3 nodelay;
}

# Block PHP execution in uploads
location ~* /uploads/.*\.php$ {
    deny all;
}

See also: 26+ Tips to Optimize WordPress Website Speed.

6.5. Test Performance

Use these commands to verify:

# Check worker processes
ps aux | grep nginx

# Check active connections
sudo ss -tlnp | grep nginx

For external testing, use GTmetrix or PageSpeed Insights:


Step 7: Monitoring and Logging

7.1. View Nginx Logs

# Real-time access log
sudo tail -f /var/log/nginx/access.log

# Real-time error log
sudo tail -f /var/log/nginx/error.log

7.2. Analyze Logs with GoAccess

sudo apt install goaccess -y
sudo goaccess /var/log/nginx/access.log -o /var/www/example.com/html/report.html --log-format=COMBINED

7.3. Monitor with Netdata

bash <(curl -Ss https://my-netdata.io/kickstart.sh)

Netdata provides a real-time dashboard for CPU, RAM, disk, network, and Nginx metrics.


Step 8: Common Troubleshooting

8.1. "Port 80 already in use"

Apache is occupying port 80. Stop it:

sudo systemctl stop apache2
sudo systemctl disable apache2
sudo systemctl start nginx

8.2. "502 Bad Gateway"

PHP-FPM is not running or the socket path is incorrect:

sudo systemctl restart php8.3-fpm
sudo systemctl status php8.3-fpm

Verify the socket path:

ls /var/run/php/

8.3. "404 Not Found"

Check the root directive and verify files exist:

ls -la /var/www/example.com/html/

Make sure the index directive is correct:

index index.php index.html index.htm;

8.4. "413 Request Entity Too Large"

Increase client_max_body_size:

client_max_body_size 128M;

8.5. Always Test Before Reloading

sudo nginx -t

If there's a syntax error, Nginx will show the exact line.

Error CodeCauseSolution
502 Bad GatewayPHP-FPM not running or wrong socket pathRestart PHP-FPM, check socket path
404 Not FoundWrong root path or missing index fileVerify root and index directives
413 Request Entity Too LargeUpload exceeds client_max_body_sizeIncrease client_max_body_size value
Permission DeniedWrong owner/permissions on directoryRun chown -R www-data:www-data /var/www/
Address already in usePort 80/443 taken by ApacheStop Apache, start Nginx

Frequently Asked Questions

How is Nginx different from Apache?

Nginx uses an event-driven architecture, handling more connections with fewer resources than Apache. It's ideal for high-traffic websites and reverse proxy setups. See the comparison in What is Apache?.

Can I install WordPress on a VPS with Nginx?

Yes. After completing the steps above (especially PHP-FPM and MySQL), you can install WordPress. See our WordPress Complete Guide.

How do I know if Nginx is running well?

Run sudo systemctl status nginx to check the service status. Use htop for CPU/RAM monitoring, and GTmetrix for external speed tests.

Should I use Nginx or Apache for a new WordPress site?

Nginx paired with PHP-FPM delivers better performance than Apache, especially under high traffic. On shared hosting, the provider usually decides — but on a VPS, Nginx is the optimal choice.

Check out our Hostinger vs Namecheap comparison if you're choosing a VPS provider.


Summary

You've successfully installed Nginx on a VPS from A to Z:

  • Connected and prepared your VPS.
  • Installed Nginx and configured the firewall.
  • Created virtual hosts for your websites.
  • Integrated PHP-FPM for dynamic content.
  • Secured the server with security headers and rate limiting. Read the Server Security Guide for more measures.
  • Installed a free Let's Encrypt SSL certificate.
  • Optimized performance with gzip, caching, and worker tuning.
  • Set up monitoring and learned common troubleshooting.

VPS + Nginx provides a rock-solid foundation for any website — from a WordPress blog to complex web applications. By setting it up yourself, you gain full control and a deep understanding of your server.

If you need professional website design or hosting optimization, contact RiverLee for expert consultation.

Comments

0 Comment(s)

Loading...

Latest Posts

Related Posts

Newsletter border

Subscribe to Receive Updates from RiverLee