Learn Nginx: Set Up a Modern, Scalable, High-Performance Web Server
Nginx is a powerful, high-performance web server that also functions well as a reverse proxy, load balancer, and HTTP cache. It is highly popular for serving static files, handling concurrent connections efficiently, and acting as a secure front end to application servers. In this guide, we will cover how to install, configure, and manage Nginx on Ubuntu Linux.
Why Use It #
Nginx is often chosen because of its:
- Low memory usage and high concurrency.
- Ability to serve static content very efficiently.
- Robust reverse proxy and load balancing capabilities.
- Simple yet powerful configuration files.
- Widespread community support and documentation.
Nginx vs Apache #
Comparison:
Feature | Nginx | Apache |
---|---|---|
Architecture | Event-driven, asynchronous | Process/thread-based |
Performance | High concurrency, low memory | Less efficient under heavy load |
Static Content | Very efficient | Less efficient |
Configuration | Simple | Complex, feature-rich |
Load Balancing | Built-in | Requires third-party modules |
Reverse Proxy | Excellent | Configurable with modules |
OS Support | Primarily Unix-based | Cross-platform |
Security | Strong, minimal attack surface | Larger attack surface |
Resource Usage | Low | Higher under heavy load |
Modules | Limited | Extensive |
Popularity | Increasing | Well-established |
Installation #
Platform: Debian / Ubuntu.
sudo apt install nginx -y
Start:
sudo systemctl start nginx
Auto start at boot:
sudo systemctl enable nginx
Verify installation:
nginx -v
Or visit: http://<public_ipv4>
Essential Commands #
1. Basics #
Start:
sudo systemctl start nginx
Stop:
sudo systemctl stop nginx
Restart:
sudo systemctl restart nginx
Enable auto-start on boot:
sudo systemctl enable nginx
Disable auto-start on boot:
sudo systemctl disable nginx
Show status:
sudo systemctl status nginx
2. Configuration #
Test:
Test the configuration for syntax errors before applying it.
sudo nginx -t
If the configuration file has no errors, you’ll see output like:
nginx: configuration file /etc/nginx/nginx.conf test is successful
Reload:
Reloading Nginx applies configuration changes without stopping the service or disrupting active connections.
sudo systemctl reload nginx
Combine:
sudo nginx -t && sudo systemctl reload nginx
3. Other #
Show version:
nginx -v
With additional build configuration details:
nginx -V
Show help:
nginx -hs
Directory Structure #
Example:
/var/www/example.com/
└── public_html/
└── index.html
/etc/nginx/sites-available/
└── example.com
/etc/nginx/sites-enabled/
└── example.com -> ../sites-available/example.com (symlink)
Workflow #
Set Up a Site (HTML) #
List enabled sites:
ls -l /etc/nginx/sites-enabled/
Disable default site:
This disables the default site by removing its active link, while keeping /etc/nginx/sites-available/default
intact in case you want to re-enable it later.
sudo unlink /etc/nginx/sites-enabled/default
Create directory:
sudo mkdir -p /var/www/<name>/public_html
Example name: example.com
Add HTML file (for testing):
sudo vim /var/www/<name>/public_html/index.html
Add:
<h1>It works!</h1>
Set permissions:
sudo chown -R www-data:www-data /var/www/
Create server block:
sudo vim /etc/nginx/sites-available/<name>
Add:
server {
listen 80;
listen [::]:80;
server_name <public_ipv4> <domain> <www.domain>;
root /var/www/<name>/public_html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Alternative (with HTTPS redirect):
server {
listen 80;
listen [::]:80;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name <public_ipv4> <domain> <www.domain>;
ssl_certificate <path/to/cert>.pem;
ssl_certificate_key <path/to/key>.pem;
root /var/www/<name>/public_html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Create symbolic link to enable site:
sudo ln -s /etc/nginx/sites-available/<name> /etc/nginx/sites-enabled/
Test configuration:
sudo nginx -t
If the output says the configuration is OK:
Reload NGINX:
sudo systemctl restart nginx
Verify:
Visit website: http://<public_ipv4>
Set Up a Site (PHP) #
Install PHP:
sudo apt install php-fpm -y
List enabled sites:
ls -l /etc/nginx/sites-enabled/
Disable enabled sites:
sudo unlink /etc/nginx/sites-enabled/<name>
Create directory:
sudo mkdir -p /var/www/<name>/public_html
Example name: example.com
Add PHP file (for testing):
sudo vim /var/www/<name>/public_html/index.php
Add:
<?php phpinfo(); ?>
Set permissions:
sudo chown -R www-data:www-data /var/www/
Create server block:
sudo vim /etc/nginx/sites-available/<name>
Add:
server {
listen 80;
listen [::]:80;
server_name <public_ipv4> <domain>;
root /var/www/<name>/public_html;
index index.php;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php<version>-fpm.sock;
}
}
Create symbolic link to enable site:
sudo ln -s /etc/nginx/sites-available/<name> /etc/nginx/sites-enabled/
Test configuration:
sudo nginx -t
If the output says the configuration is OK:
Reload NGINX:
sudo systemctl restart nginx
Verify:
Visit website: http://<public_ipv4>
Monitoring and Logs #
Install CCZE (optional):
CCZE is a tool that shows logs with colours to make them easier to read.
sudo apt install ccze -y
View access log:
sudo tail -f /var/log/nginx/access.log | ccze
View error log:
sudo tail -f /var/log/nginx/error.log | ccze
Tips and Tricks #
Use Include Statements for Reusability #
Put shared logic in snippets:
/etc/nginx/snippets/ssl-params.conf
/etc/nginx/snippets/letsencrypt.conf
include snippets/ssl-params.conf;
Troubleshooting #
Unable to Connect #
Symptoms:
- Browser shows “Unable to connect” or similar error.
Causes:
- No site configuration is linked in
/etc/nginx/sites-enabled/
. - NGINX is running but not serving any site.
- Server block missing or misconfigured
listen
directive.
Solutions:
- Check for active site configurations:
ls -l /etc/nginx/sites-enabled/
- Link a site config:
sudo ln -s /etc/nginx/sites-available/<name> /etc/nginx/sites-enabled/
- Validate configuration:
sudo nginx -t
- Reload NGINX:
sudo systemctl reload nginx
- Ensure your site config has a valid
listen
directive:
server {
listen 80;
server_name <public_ipv4> <domain>;
root /var/www/<name>;
index index.html;
}
403 Forbidden #
Symptoms:
- Browser shows a "403 Forbidden" error when trying to access a site.
Causes:
- Incorrect file or directory permissions.
- NGINX not having read access to the web root.
- Missing
index
directive in the configuration.
Solutions:
- Ensure correct permissions:
sudo chown -R www-data:www-data /var/www/
sudo chmod -R 755 /var/www/
- Add or correct the
index
directive in your server block:
index index.html;
502 Bad Gateway #
Symptoms:
- NGINX returns a "502 Bad Gateway".
Causes:
- The upstream service (e.g., PHP-FPM, Node.js, etc.) is not running or not reachable.
- Incorrect
fastcgi_pass
setting.
Solutions:
- Ensure the upstream service is running:
sudo systemctl status php<version>-fpm
- Check the socket in your config:
fastcgi_pass unix:/run/php/php<version>-fpm.sock;
Too Many Redirects #
Symptoms:
- Browser shows “ERR_TOO_MANY_REDIRECTS”
Causes:
- Misconfigured
return
orrewrite
rules - Conflicting HTTP-to-HTTPS redirection loops
Solutions:
- Ensure HTTPS and HTTP configs are separate:
server {
listen 80;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
...
}
- Double-check server blocks for conflicting redirections
SSL/TLS Certificate Errors #
Symptoms:
- Browser shows "Your connection is not private" or similar TLS errors.
Causes:
- Misconfigured SSL settings
- Expired or invalid certificate
- Missing certificate files
Solutions:
- Check certificate expiry:
openssl x509 -enddate -noout -in /etc/ssl/certs/your_cert.pem
- Ensure proper paths and permissions:
ssl_certificate <path/to/cert>.pem;
ssl_certificate_key <path/to/key>.pem;
- Restart NGINX after changes:
sudo systemctl restart nginx