Developers

How to Set Up Nginx on a VPS: Install, Configure and Serve a Site

A step-by-step guide to installing Nginx on Ubuntu, writing a server block, testing the config safely and serving your first site over HTTP and HTTPS.

By Zebra Hosting Cloud

Nginx (pronounced "engine-x") is one of the most widely used web servers, valued for its low memory use and its ability to serve many connections at once. On a VPS it is often the first thing you install. This guide takes you from a clean Ubuntu or Debian server to a working site, and explains the layout of the configuration so you can extend it with confidence.

Install Nginx and learn the layout

Install and check that it runs

sudo apt update
sudo apt install nginx
sudo systemctl status nginx

The package starts the service automatically. If you use a firewall, make sure ports 80 and 443 are open (with ufw, sudo ufw allow 'Nginx Full' does both). Visiting your server's IP address in a browser should show the default Nginx welcome page.

On AlmaLinux or Rocky Linux the package is also called nginx and is installed with dnf; the main difference is how the configuration is organised, covered below.

Understand the configuration layout

The main file is /etc/nginx/nginx.conf. You rarely need to edit it. On Debian and Ubuntu, each site gets its own file:

  • /etc/nginx/sites-available/ holds configuration files you have written.
  • /etc/nginx/sites-enabled/ holds symbolic links to the ones that are active.

On Red Hat style systems the convention is simpler: place a .conf file in /etc/nginx/conf.d/. The directives are the same either way.

Create and enable a site

First create a folder for the site's files and a test page:

sudo mkdir -p /var/www/example.com/public
echo '<h1>It works</h1>' | sudo tee /var/www/example.com/public/index.html

Then write a server block, Nginx's name for a virtual host, in /etc/nginx/sites-available/example.com:

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

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

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

The important lines: server_name tells Nginx which requests belong to this block based on the domain; root is the folder to serve; and try_files says "serve the file if it exists, otherwise return a 404". Your domain's A record (and AAAA record for IPv6) must point to the server for this to work from the internet.

Enable, test and reload

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

Always run nginx -t before reloading. It checks the syntax and tells you the file and line of any error. A reload applies the new configuration without dropping existing connections, whereas a restart briefly interrupts them. If the test fails, the old configuration keeps running, so a typo cannot take your site down as long as you do not skip the check.

Redirect www to the bare domain

Most sites pick one canonical address. A second, tiny server block can send all www requests to the bare domain with a permanent redirect (shown here for HTTP; Certbot can add the HTTPS equivalent):

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

Remember to list only example.com in the main block's server_name afterwards. If the default welcome page keeps appearing for your domain, remove the default site link with sudo rm /etc/nginx/sites-enabled/default, run the test command again and reload.

Add HTTPS

Browsers expect HTTPS, and search engines favour it. The usual route is a free Let's Encrypt certificate obtained with Certbot, whose Nginx plugin edits your server block for you:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com

Certbot adds a listen 443 ssl block, points to the certificate files and offers to redirect HTTP to HTTPS. It also installs a scheduled task that renews the certificate before it expires; confirm with sudo certbot renew --dry-run.

Useful additions

  • Compression: enable gzip on; in the http block, with a list of types to compress, to reduce transfer sizes.
  • Caching static files: a location ~* \.(css|js|png|jpg|svg|woff2)$ block with expires 30d; lets browsers keep assets.
  • Hide the version: server_tokens off; stops Nginx advertising its version number in headers and error pages.
  • Per-site logs: add access_log and error_log lines to a server block so each site has its own files under /var/log/nginx/.
  • Passing to an app: use proxy_pass for Node.js or Python apps, or fastcgi_pass for PHP-FPM.

Troubleshooting

When something fails, look at the error log first: sudo tail -f /var/log/nginx/error.log. A 403 usually means a permissions problem: the Nginx worker user (www-data on Debian and Ubuntu) must be able to read the files and traverse every parent directory. A 502 means Nginx could not reach the application behind it. If the wrong site appears, check that your server_name matches the domain exactly and remember that the first server block (or one marked default_server) answers requests that match nothing else.

The knowledge base lists more fixes for common server and DNS problems.

Keeping the configuration tidy

As you add sites, resist the temptation to paste everything into one file. Keep one file per site, put shared snippets (for example common security headers or PHP handling) in separate files, and include them with the include directive. Comment unusual lines, and keep the whole /etc/nginx folder in a private Git repository so every change is recorded and you can see what changed when something breaks. Before large edits, copy the working file, so you can restore it in seconds. For certificate details, see our SSL page.

Finally, remember that Nginx is only the web server. It does not run PHP or your application code itself. It hands requests to PHP-FPM or to an application server, so a working Nginx page is the start of the job, not the end.

Running Nginx on Zebra Hosting

If you want to run your own web server stack with full control, a Zebra Hosting VPS is delivered within 24 hours. If you would rather not manage configuration files, our Plesk-based plans handle web server setup for you.