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 widely adopted for its performance, efficiency, and versatility in web infrastructure. Key reasons for using NGINX include:
- Low resource usage with high concurrency
NGINX uses an event-driven, asynchronous architecture that handles thousands of simultaneous connections with minimal memory and CPU consumption. This makes it ideal for high-traffic environments. - Efficient static content delivery
It serves static files such as HTML, CSS, JavaScript, and images with exceptional speed, reducing server load and improving client response times. - Advanced reverse proxy and load balancing
NGINX supports multiple load balancing methods (round-robin, IP-hash, least connections) and can proxy requests to backend servers, enabling horizontal scaling and high availability. - Clear and flexible configuration
Its configuration syntax is declarative and structured, making it easy to read, manage, and automate. Features like conditional blocks, variable usage, and modular design allow complex setups with minimal overhead. - Extensive community and documentation
As a mature and popular open-source project, NGINX benefits from a large community, frequent updates, and comprehensive documentation, facilitating troubleshooting and continuous learning.
NGINX vs Apache #
NGINX and Apache are two of the most widely used web servers. Each has its strengths, but they differ significantly in architecture and performance characteristics.
Comparison Table
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, declarative | Complex, feature-rich |
Load Balancing | Built-in support | Requires third-party modules |
Reverse Proxy | First-class support | Configurable via modules |
OS Support | Primarily Unix-based | Cross-platform |
Security | Strong, minimal attack surface | Larger attack surface |
Resource Usage | Low, even under high load | Higher memory and CPU usage |
Modules | Limited, lightweight | Extensive and mature |
Popularity | Rapidly growing | Long-standing, widely used |
Key Takeaways
- NGINX offers superior performance and scalability, especially in high-concurrency scenarios.
- Apache is more flexible and extensible through its mature module ecosystem.
NGINX is the preferred choice for modern, containerised, or microservice-based architectures.
Installation #
Install on Linux (Ubuntu/Debian):
sudo apt install nginx -y
Start NGINX service:
sudo systemctl start nginx
Enable NGINX to start at boot:
sudo systemctl enable nginx
Verify installation:
nginx -v
Or open a browser and visit:
http://<public_ipv4>
Essential Commands #
1. Basics #
Start NGINX:
sudo systemctl start nginx
Stop NGINX:
sudo systemctl stop nginx
Restart NGINX:
sudo systemctl restart nginx
Enable auto-start on boot:
sudo systemctl enable nginx
Disable auto-start on boot:
sudo systemctl disable nginx
Show service status:
sudo systemctl status nginx
2. Configuration #
Test configuration:
sudo nginx -t
Expected output:
nginx: configuration file /etc/nginx/nginx.conf test is successful
Before applying changes, validate the NGINX configuration for syntax errors.
Reload NGINX:
sudo systemctl reload nginx
This applies configuration changes without stopping the service or disrupting active connections.
Combine test and reload:
sudo nginx -t && sudo systemctl reload nginx
3. Other #
Show NGINX version:
nginx -v
With additional build configuration details:
nginx -V
Show help:
nginx -h
Directory Structure #
Example:
/var/www/example.com/
└── public_html/
└── index.html
/var/www/staging.example.com/
└── public_html/
└── index.html
/etc/nginx/sites-available/
├── example.com
└── staging.example.com
/etc/nginx/sites-enabled/
├── example.com -> ../sites-available/example.com (symlink)
└── staging.example.com -> ../sites-available/staging.example.com (symlink)
Website Files
- /var/www/example.com/public_html/index.html
Contains the website files forexample.com
. Thepublic_html
folder holds all the publicly accessible content. - /var/www/staging.example.com/public_html/index.html
Contains the website files forstaging.example.com
, a separate site or environment, with its ownpublic_html
folder.
NGINX Configuration
- /etc/nginx/sites-available/
This directory stores all available site configurations. Each file corresponds to a website or virtual host (e.g.,example.com
,staging.example.com
). - /etc/nginx/sites-enabled/
This directory contains symbolic links (symlinks) to the configuration files insites-available
for sites that are currently active. For example:example.com -> ../sites-available/example.com
means theexample.com
configuration is enabled and used by NGINX.
Summary
- Website files are kept in
/var/www/<site>/public_html/
. - Site configurations are stored in
/etc/nginx/sites-available/
. - Active sites are enabled by symlinking their config files into
/etc/nginx/sites-enabled/
. - This separation makes managing multiple sites simple and prevents accidental removal of configurations.
Workflow #
Set Up a Site (HTML) #
List enabled sites:
ls -l /etc/nginx/sites-enabled/
Disable default site:
sudo unlink /etc/nginx/sites-enabled/default
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.
Create site directory:
sudo mkdir -p /var/www/<site>/public_html
Example site: example.com
Add test HTML file:
sudo vim /var/www/<site>/public_html/index.html
Add:
<h1>It works!</h1>
Set ownership:
sudo chown -R www-data:www-data /var/www/
Create server block configuration:
sudo vim /etc/nginx/sites-available/<site>
Add:
server {
listen 80;
listen [::]:80;
server_name <name>; # Add: <domain>, www.<domain> or <public_ipv4>
root /var/www/<site>/public_html;
index index.html; # Serve index.html when a directory is requested
location / {
try_files $uri $uri/ =404;
}
}
Or with HTTP to HTTPS redirect:
server {
listen 80;
listen [::]:80;
server_name <name>; # Add: <domain>, www.<domain> or <public_ipv4>
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name <name>; # Add: <domain>, www.<domain> or <public_ipv4>
root /var/www/<site>/public_html;
index index.html; # Serve index.html when a directory is requested
ssl_certificate <path/to>cert.pem;
ssl_certificate_key <path/to>key.pem;
location / {
try_files $uri $uri/ =404;
}
}
Create a symbolic link to enable the site:
sudo ln -s /etc/nginx/sites-available/<site> /etc/nginx/sites-enabled/
Test configuration:
sudo nginx -t
Expected output:
nginx: configuration file /etc/nginx/nginx.conf test is successful
Reload NGINX:
sudo systemctl reload nginx
To verify, visit the site in a browser:
http://<public_ipv4>
Set Up a Site (PHP) #
Install PHP-FPM:
sudo apt install php-fpm -y
List enabled sites:
ls -l /etc/nginx/sites-enabled/
Disable default site:
sudo unlink /etc/nginx/sites-enabled/default
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.
Create site directory:
sudo mkdir -p /var/www/<site>/public_html
Example site: example.com
Add PHP test file:
sudo vim /var/www/<site>/public_html/index.php
Add:
<?php phpinfo(); ?>
Set ownership:
sudo chown -R www-data:www-data /var/www/
Create server block configuration:
sudo vim /etc/nginx/sites-available/<site>
Add:
server {
listen 80;
listen [::]:80;
server_name <name>; # Add: <domain>, www.<domain> or <public_ipv4>
root /var/www/<site>/public_html;
index index.php; # Serve index.php when a directory is requested
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php<version>-fpm.sock; # Add installed PHP version
}
}
Or with HTTP to HTTPS redirect:
server {
listen 80;
listen [::]:80;
server_name <name>; # Add: <domain>, www.<domain> or <public_ipv4>
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name <name> ; # Add: <domain>, www.<domain> or <public_ipv4>
root /var/www/<site>/public_html;
index index.php; # Serve index.php when a directory is requested
ssl_certificate <path/to>cert.pem;
ssl_certificate_key <path/to>key.pem;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php<version>-fpm.sock; # Add installed PHP version
}
}
Create symbolic link to enable site:
sudo ln -s /etc/nginx/sites-available/<site> /etc/nginx/sites-enabled/
Test configuration:
sudo nginx -t
Expected output:
nginx: configuration file /etc/nginx/nginx.conf test is successful
Reload NGINX:
sudo systemctl reload nginx
To verify, visit the site in a browser:
http://<public_ipv4>
Monitoring and Logs #
Install CCZE (optional):
sudo apt install ccze -y
CCZE enhances log readability by adding colour to the output.
View NGINX access log:
sudo tail -f /var/log/nginx/access.log | ccze
View NGINX error log:
sudo tail -f /var/log/nginx/error.log | ccze
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/<site> /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;
listen [::]:80;
server_name <name>; # Add: <domain>, www.<domain> or <public_ipv4>
root /var/www/<site>/public_html;
index index.html; # Serve index.html when a directory is requested
}
403 Forbidden #
Symptoms:
Browser shows a "403 Forbidden" error when trying to access a site.
Causes:
- Incorrect file or directory permissions
Files or directories do not have the correct ownership or mode. - NGINX does not have read access to the web root
The web server user (typicallywww-data
) cannot access the site directory or files. - Missing or misconfigured
index
directive
NGINX cannot find a default file to serve when a directory is requested.
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; # Use index.php if your site uses PHP
- Or to support both:
index index.html index.php;
502 Bad Gateway #
Symptoms:
Nginx returns a 502 Bad Gateway error.
Cause:
The upstream server (e.g. PHP-FPM) is down, misconfigured, or unreachable.
Solution:
1. Check Upstream Server Status
Ensure the backend service (e.g. PHP-FPM) is running and listening on the correct socket or port:
sudo systemctl status php<version>-fpm
2. Verify Nginx Configuration
Ensure Nginx is properly configured to pass requests to the correct upstream socket or port:
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php<version>-fpm.sock; # Confirm the PHP version matches the installed version
}
3. Check Logs
Inspect log files for error details:
# Nginx error log
tail -f /var/log/nginx/error.log
# PHP-FPM log
tail -f /var/log/php<version>-fpm.log
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;
listen [::]:80;
server_name <name>; # Add: <domain>, www.<domain> or <public_ipv4>
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name <name>; # Add: <domain>, www.<domain> or <public_ipv4>
...
}
- 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:
sudo openssl x509 -enddate -noout -in /etc/ssl/cloudflare/cert.pem
- Ensure proper paths and permissions:
ssl_certificate /etc/ssl/cloudflare/cert.pem;
ssl_certificate_key /etc/ssl/cloudflare/key.pem;
- Restart NGINX after changes:
sudo systemctl restart nginx