Nginx handles everything from serving static websites and hosting PHP applications to acting as a reverse proxy for backend services. Whether you need to host a WordPress site, serve a Node.js application, or load balance traffic across multiple servers, Nginx provides the performance and flexibility to handle it. By the end of this guide, you will have a working Nginx installation with server blocks configured, firewall rules in place, and optional SSL encryption ready for production use.
Nginx is available directly from the default Debian repositories, making installation straightforward with no additional repository configuration required. If you need the latest features before they reach Debian stable, see how to install Nginx mainline on Debian.
Preparing Your System Before Nginx Installation
First, ensure your system is updated before installing Nginx. This prevents potential conflicts during the installation and also reduces the risk of compatibility issues and security vulnerabilities.
To update your system packages, run the following:
sudo apt update && sudo apt upgrade -y
This command fetches the list of available updates (via apt update) and then upgrades the current software packages to their latest versions (using apt upgrade). The -y flag automatically confirms the upgrade prompt.
Choose Your Nginx Package
Debian offers several Nginx package variants. On Debian 12 and later, the base nginx package contains the actual web server binary, while variant packages add optional modules on top.
| Package | Modules Included | Best For |
|---|---|---|
| nginx | Core web server only | Most users, minimal footprint |
| nginx-core | nginx + GeoIP, image-filter, XSLT, mail, stream | Users who need standard modules |
| nginx-light | nginx + echo module | Minimal installations with echo support |
| nginx-full | nginx-core + PAM auth, DAV, GeoIP2, upstream-fair | Extended functionality without Lua |
| nginx-extras | nginx-full + Lua, cache-purge, headers-more, nchan | Advanced users needing Lua scripting |
For most users, install the standard nginx package. The base package handles static sites, reverse proxying, and SSL termination without additional modules. Install nginx-core if you need image filtering or GeoIP lookup, or nginx-extras if you require Lua scripting or cache purging. If you need custom modules or specific compile-time options, see how to build Nginx from source on Debian.
Install Nginx Web Server
Now, install Nginx from the default Debian repositories:
sudo apt install nginx -y
Once complete, APT installs Nginx along with its dependencies and automatically starts the service.
Verify Nginx Installation
Next, confirm the installed Nginx version:
nginx -v
Expected output:
nginx version: nginx/1.x.x
Nginx versions vary by Debian release: Debian 11 ships nginx 1.18.0, Debian 12 ships 1.22.1, and Debian 13 ships 1.26.3. Your output will match your specific release.
Additionally, check the Nginx service status:
systemctl status nginx
Expected output (key lines):
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
Active: active (running)
If the status shows “active (running),” Nginx is working correctly. However, if the service is not running, start and enable it with the following command:
sudo systemctl enable nginx --now
Configure UFW Firewall for Nginx
UFW (Uncomplicated Firewall) provides an easy-to-use interface for managing iptables firewall rules. Although it is not installed on Debian by default, you can easily install it from the default repositories. For a comprehensive guide on UFW configuration, see how to install UFW on Debian.
Install UFW Firewall
First, install UFW from the Debian repositories:
sudo apt install ufw -y
Enable UFW Firewall
If you are connected via SSH, allow SSH access before enabling UFW to prevent lockout from your server.
Before enabling UFW, allow SSH connections to prevent being locked out of a remote server:
sudo ufw allow OpenSSH
Now enable UFW:
sudo ufw enable
By default, UFW’s settings block all incoming connections and allow all outgoing ones. As a result, the SSH rule you just added ensures you maintain remote access.
View UFW Application Profiles
UFW uses application profiles, which are sets of rules for specific applications. To see which installed applications have UFW profiles available, simply run:
sudo ufw app list
Allow Nginx Through UFW
Next, configure UFW to allow Nginx connections through HTTP (Port 80), HTTPS (Port 443), or both.
For HTTP (Port 80) only:
sudo ufw allow 'Nginx HTTP'
For HTTPS (Port 443) only:
sudo ufw allow 'Nginx HTTPS'
Alternatively, to allow both HTTP and HTTPS:
sudo ufw allow 'Nginx Full'
Verify Firewall Rules
Finally, confirm your rules are in place by checking the active firewall rules:
sudo ufw status
Expected output:
Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere Nginx Full ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) Nginx Full (v6) ALLOW Anywhere (v6)
Test Nginx in Browser
After setting up UFW, verify you can see the Nginx landing page. In your browser, go to your server’s IP address:
http://your_server_ip
For local setups, use:
http://localhost
If you see the Nginx default welcome page, then the firewall configuration is complete and Nginx is serving traffic correctly.

Create Nginx Server Blocks
Server blocks (similar to Apache virtual hosts) allow you to host multiple domains from a single server. Each domain has its own configuration file with separate document roots and settings. For production sites, you’ll also want to configure www to non-www redirects and URL rewrite rules. Throughout this section, replace example.com with your actual domain name.
Create a Directory for Your Domain
Create a directory for your domain to store your website’s files:
sudo mkdir -p /var/www/example.com/
Assign Ownership to the Nginx Directory
Next, assign directory ownership to the www-data user and group, which Nginx uses by default:
sudo chown -R www-data:www-data /var/www/example.com/
Create a Test HTML Page
After that, create a test HTML page in your domain directory to confirm your Nginx server block works:
sudo nano /var/www/example.com/index.html
Then, add the following HTML code:
<html>
<head>
<title>Welcome to Example.com</title>
</head>
<body>
<h1>Success! The Nginx server block is working!</h1>
</body>
</html>
Once you’ve pasted the code into the nano editor, press CTRL+O to save the changes and then CTRL+X to exit the editor.
Create the Server Block Configuration
Now, create a server block configuration file for your domain:
sudo nano /etc/nginx/sites-available/example.com.conf
Then, add the following configuration:
server {
listen 80;
listen [::]:80;
root /var/www/example.com/;
index index.html index.htm index.nginx-debian.html;
server_name example.com www.example.com;
location / {
try_files $uri $uri/ =404;
}
}
This configuration tells Nginx to listen for incoming connections on port 80 for both example.com and www.example.com. Replace the server_name directive with your actual domain.
Enable the Server Block
Subsequently, enable your server block by creating a symbolic link from the sites-available directory to the sites-enabled directory:
sudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/
Configure Server Names Hash Bucket Size
If you use long domain names or host many domains, you may need to increase the server names hash bucket size to avoid configuration errors.
Edit the Main Nginx Configuration
Open the nginx.conf file:
sudo nano /etc/nginx/nginx.conf
Inside this file, look for the line server_names_hash_bucket_size 64; within the http {} block and uncomment it.
This directive allows Nginx to handle long domain names and a larger number of server names by allocating more memory. However, only uncomment this line if you encounter an error about the server names hash bucket size.
Afterward, save the changes and exit the editor by pressing CTRL+O and CTRL+X.
Test and Reload Nginx Configuration
Before restarting Nginx, verify that your configuration syntax is correct:
sudo nginx -t
If your configuration is correct, you’ll see this output:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
These messages indicate that your Nginx configuration has been successfully validated. Therefore, reload Nginx to apply the changes:
sudo systemctl reload nginx
Test the Server Block
Finally, open your domain in a web browser. You should see the test page confirming your server block is active.

Manage Nginx Service and Files
Set File Permissions for Web Content
Security for files and folders on your web server is paramount. Avoid overly permissive access rights by setting correct permissions for all files and directories in your webroot.
Remember to replace /var/www/example.com/ with your webroot path:
sudo find /var/www/example.com/ -type d -exec chmod 755 "{}" \;
sudo find /var/www/example.com/ -type f -exec chmod 644 "{}" \;
These commands set read and execute permissions for directories and read-write permissions for files for the owner. Groups and others get read-only access. Adjust these permissions as your application demands.
Secure Nginx with Let’s Encrypt SSL
HTTPS encrypts traffic between your server and visitors, which is essential for any production website. Let’s Encrypt provides free SSL certificates that are widely trusted. For a complete walkthrough including advanced configuration options, see how to secure Nginx with Let’s Encrypt on Debian.
First, refresh the package cache and install the Certbot package with Nginx integration:
sudo apt update && sudo apt install python3-certbot-nginx -y
If you see “Unable to locate package”, your main Debian repository may be missing. Run
apt-cache policy python3-certbot-nginxto check. Some minimal server installations only include security repositories and need the main repository added.
Then, obtain and install a certificate for your domain:
sudo certbot --nginx --agree-tos --redirect --hsts --staple-ocsp --email you@example.com -d example.com -d www.example.com
Replace you@example.com with your email address and the domain names with your actual domains. Include both the apex domain (example.com) and www subdomain to match your server block configuration. This command obtains a certificate, configures Nginx to use it, enables HTTP to HTTPS redirection, and adds security headers. For additional hardening, see how to configure security headers in Nginx.
Verify Automatic Certificate Renewal
Let’s Encrypt certificates expire after 90 days. Fortunately, Debian automatically installs a systemd timer that handles certificate renewal, so manual cron configuration is not required.
To confirm this, verify the renewal timer is active:
sudo systemctl status certbot.timer
Expected output:
● certbot.timer - Run certbot twice daily
Loaded: loaded (/lib/systemd/system/certbot.timer; enabled; preset: enabled)
Active: active (waiting)
Additionally, test that the renewal process works without actually renewing:
sudo certbot renew --dry-run
If the dry run completes without errors, automatic renewal is configured correctly.
Monitor Nginx Server Logs
Monitor your server logs to troubleshoot issues and track visitor activity. Nginx logs are stored in /var/log/nginx/. List the log files:
ls -l /var/log/nginx/
Among these, the most relevant log files are the access.log and error.log. To monitor logs in real-time, use tail -f followed by the path to the log:
tail -f /var/log/nginx/access.log
Update Nginx
Before updating your Nginx server, creating a backup of your current configurations is wise. To back up your main nginx.conf file, use the following command:
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx-backup.conf
Alternatively, if you have extensively customized your Nginx setup, you might want to back up your entire Nginx directory:
sudo cp -r /etc/nginx/ /etc/nginx-bkup
With your configurations safely backed up, you can now proceed to update Nginx:
sudo apt update && sudo apt install --only-upgrade nginx -y
Using --only-upgrade updates only Nginx without upgrading other system packages. As a best practice, regularly back up your configurations, especially in complex setups.
Configure Log Rotation
By default, Nginx includes a daily log rotation feature through logrotate. However, you can customize these settings based on your retention and storage requirements.
Edit the Log Rotation Configuration
Open the Nginx logrotate configuration file:
sudo nano /etc/logrotate.d/nginx
Once you open the file, you’ll see content resembling the following. From here, adjust the directives in this file to fit your log retention and rotation needs, especially if you use monitoring tools like fail2ban.
Default Log Rotation Configuration
The default configuration looks like this:
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
prerotate
if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
run-parts /etc/logrotate.d/httpd-prerotate; \
fi \
endscript
postrotate
invoke-rc.d nginx rotate >/dev/null 2>&1
endscript
}
Log Rotation Parameters Explained
The key settings to adjust are:
- Daily: This setting sets the log rotation frequency. While it defaults to ‘daily,’ you can change it to ‘weekly’ or ‘monthly.’ However, daily rotations typically simplify log management.
- Rotate 14: This number tells the system how many log files to keep. For example, a setting of ’14’ retains the 14 latest logs. If you want to store only a week of logs, adjust this number to ‘7’.
While Nginx lets you modify other settings, always make changes with care. Otherwise, changing settings without understanding their impact can cause unexpected results. Therefore, ensure you modify these settings to suit your needs without causing unintended issues.
After making changes, test the configuration with a dry run:
sudo logrotate --debug /etc/logrotate.d/nginx
This command simulates log rotation without actually modifying files, allowing you to verify your configuration before it takes effect.
Troubleshoot Common Nginx Issues
If Nginx fails to start or reload, use these diagnostic steps to identify and resolve the problem.
Configuration Syntax Errors
If you see an error like this when reloading Nginx:
nginx: [emerg] unknown directive "server_nam" in /etc/nginx/sites-enabled/example.com.conf:7
Test the configuration for syntax errors:
sudo nginx -t
The output identifies the exact file and line number. Fix the typo in the configuration file, then verify:
sudo nginx -t
Expected output after fixing:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Port Binding Conflicts
If Nginx fails to start with an error like:
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
Check which process is using the port:
sudo ss -tlnp | grep -E ':80|:443'
Example output showing Apache using port 80:
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("apache2",pid=1234,fd=4))
Stop the conflicting service or configure Nginx to use a different port. After resolving the conflict, start Nginx and verify:
sudo systemctl start nginx
systemctl status nginx
Review Error Logs
For errors not caught by the syntax test, check the Nginx error log:
sudo tail -50 /var/log/nginx/error.log
Alternatively, filter for specific errors:
sudo grep -i "error" /var/log/nginx/error.log | tail -20
Remove Nginx
If you no longer need Nginx, follow these steps to remove it completely.
First, stop and disable the Nginx service:
sudo systemctl disable nginx --now
Next, remove Nginx and its configuration files:
sudo apt purge nginx -y
Then, remove any orphaned dependencies that were installed with Nginx:
sudo apt autoremove -y
Warning: The following command permanently deletes all Nginx configuration files in
/etc/nginx/, including any custom server blocks and SSL configurations. Ensure you have backed up any configurations you want to keep.
If configuration remnants exist after purging, remove them manually:
sudo rm -rf /etc/nginx/
Finally, verify Nginx has been removed:
nginx -v
Expected output:
bash: nginx: command not found
Conclusion
You now have Nginx installed and configured on Debian with server blocks for hosting multiple domains, firewall rules for controlled access, and SSL certificates for encrypted connections. From here, consider enabling Gzip compression to reduce bandwidth usage, configuring rate limiting to prevent abuse, and setting up a database server with MariaDB on Debian or PHP on Debian for dynamic web applications.
Reading package lists… Done
Building dependency tree… Done
Reading state information… Done
E: Unable to locate package python3-certbot-nginx
Thanks for reporting this, schel4ok. The
python3-certbot-nginxpackage is in the main repository on all current Debian releases (11, 12, and 13). This error typically occurs when the package cache is stale or the main repository is missing from your sources configuration.First, refresh your package cache and retry:
If it still fails, check whether the package is available from your configured repositories:
If the output shows “Candidate: (none)”, your main Debian repository is missing. Some minimal server installations only include security repositories. Check your sources with
cat /etc/apt/sources.list /etc/apt/sources.list.d/*and ensure you have an entry for your release’s main repository (bullseye, bookworm, or trixie).