Nginx is a fast, widely used web server. This guide installs it on Ubuntu 24.04 and sets up one site in its own folder. The same steps work on Debian 12.
1. Install
sudo apt update
sudo apt install nginx
Nginx starts automatically. Check it:
systemctl status nginx
2. Open the firewall
If you use UFW (see firewall setup), allow web traffic:
sudo ufw allow 'Nginx Full'
Visit http://your-server-ip and you should see the Nginx welcome page.
3. Create a folder for your site
sudo mkdir -p /var/www/example.com/public
echo '<h1>It works</h1>' | sudo tee /var/www/example.com/public/index.html
4. Add a server block
Create /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 index.php;
location / {
try_files $uri $uri/ =404;
}
}
Enable it by linking it into sites-enabled:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
5. Test and reload
These are the commands you will use after every configuration change:
sudo nginx -t
sudo systemctl reload nginx
nginx -t checks the configuration for mistakes. Only reload when it reports syntax is ok and test is successful. A reload applies the change without dropping visitors.
Once your domain points to the server, visit it to see your page.
Add PHP
Nginx does not run PHP itself; it passes PHP requests to PHP-FPM. Install it:
sudo apt install php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-zip
The extensions after php-fpm cover what WordPress and most PHP software needs. Check which version was installed, because the socket name includes it:
ls /run/php/
You will see something like php8.3-fpm.sock. In your server block, change the location / line to pass unknown addresses to index.php, and add a PHP block that uses that socket:
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location ~ /\.(?!well-known) {
deny all;
}
The last block hides files such as .env and .git, while still allowing /.well-known/ for certificate checks. Test and reload, then check PHP works by creating a test file, opening it in the browser, and deleting it straight afterwards, since it reveals server details:
echo '<?php phpinfo();' | sudo tee /var/www/example.com/public/info.php
sudo rm /var/www/example.com/public/info.php
Sensible extras
Add these inside the http block of /etc/nginx/nginx.conf, or in a file under /etc/nginx/conf.d/:
server_tokens off;
client_max_body_size 64M;
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
server_tokens off stops Nginx advertising its version number. client_max_body_size raises the upload limit from the default 1 MB, which otherwise causes “413 Request Entity Too Large” errors on uploads; PHP’s own upload_max_filesize must be raised to match. gzip compresses text files, often to a fifth of their size.
Browsers can keep static files for longer if you tell them to:
location ~* \.(css|js|jpg|jpeg|png|webp|svg|woff2)$ {
expires 30d;
access_log off;
}
If something goes wrong
| Problem | Likely cause |
|---|---|
nginx -t fails | A missing semicolon or brace; the error names the file and line |
bind() to 0.0.0.0:80 failed (98: Address already in use) | Apache or another program is using port 80 |
| Still seeing the welcome page | The default site is answering; remove /etc/nginx/sites-enabled/default or check server_name |
| PHP files download instead of running | The PHP location block is missing or not matching |
| 502 Bad Gateway | PHP-FPM stopped, or the socket path is wrong |
| 403 Forbidden | No index file, or permissions on the site folder |
Where things are
| Path | What it holds |
|---|---|
/etc/nginx/nginx.conf | Main settings |
/etc/nginx/sites-available/ | One file per site |
/etc/nginx/sites-enabled/ | Links to the sites that are switched on |
/var/log/nginx/access.log | Every request |
/var/log/nginx/error.log | Problems, the first place to look |
Next
Add HTTPS with a free Let’s Encrypt certificate. To run PHP or an app behind Nginx, see reverse proxies.
Related
Something out of date? Software changes. If a step no longer works, tell us and we will check it and update the page.
