How to Deploy a Website on Nginx: Server Block Setup
Run on the server with one command (check the script contents below first):
curl -sSL https://cp.lv/scripts/razvernut-sajt-na-nginx.sh | sudo bash…or with wget:
wget -qO- https://cp.lv/scripts/razvernut-sajt-na-nginx.sh | sudo bashScript contents razvernut-sajt-na-nginx.sh:
#!/usr/bin/env bash
set -e
# 1. Site directory and permissions
sudo mkdir -p /var/www/example.com
sudo chown -R www-data:www-data /var/www/example.com
sudo chmod -R 755 /var/www/example.com
echo "<h1>example.com works</h1>" | sudo tee /var/www/example.com/index.html > /dev/null
# 2. server block (quoted 'EOF' leaves Nginx variables alone)
sudo tee /etc/nginx/sites-available/example.com > /dev/null << 'EOF'
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
location ~* \.(jpg|jpeg|png|webp|css|js|woff2)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
}
EOF
# 3. Enable the site and disable the default config
sudo ln -sf /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
echo "Site deployed: open http://example.com"
For Nginx to serve your website, you have to describe a virtual host — a server block: where the files live, which domain to serve and how to handle requests. Below is a working scheme for both static and PHP sites.
Step 1. Prepare the site directory
Put the site files in a separate directory and make the web user www-data their owner:
sudo mkdir -p /var/www/example.com
sudo chown -R www-data:www-data /var/www/example.com
sudo chmod -R 755 /var/www/example.com
Upload the files (with rsync or git clone, for example). To test, create a landing page:
echo "<h1>example.com works</h1>" | sudo tee /var/www/example.com/index.html
Step 2. Server block for a static site
Open /etc/nginx/sites-available/example.com in an editor:
sudo nano /etc/nginx/sites-available/example.com
File contents:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
location ~* \.(jpg|jpeg|png|webp|css|js|woff2)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
}
Or write the whole config with a single command — copy it and paste it into the console (the quotes around 'EOF' matter, so that the Nginx variables $uri stay as they are):
sudo tee /etc/nginx/sites-available/example.com > /dev/null << 'EOF'
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
location ~* \.(jpg|jpeg|png|webp|css|js|woff2)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
}
EOF
The try_files ... =404 directive serves the file if it exists and returns an honest 404 otherwise. The expires block turns on browser caching for static assets.
Step 3. The PHP variant
If the site runs on PHP, add handling through PHP-FPM and index.php. Open the same file in an editor (sudo nano /etc/nginx/sites-available/example.com) and make it look like this:
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
}
Or write the PHP variant with a single command (the quotes around 'EOF' matter, so that the Nginx variables $uri stay as they are):
sudo tee /etc/nginx/sites-available/example.com > /dev/null << 'EOF'
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
}
EOF
Here try_files with a fallback to /index.php is the standard for CMSes and frameworks with pretty URLs (WordPress, Laravel).
Step 4. Enable and verify
Enable the site with a symlink, check the syntax and reload:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
nginx -t should answer syntax is ok and test is successful. If it does not, the error points at the file and the line.
Step 5. Disable the default site
So that Nginx stops serving its default placeholder, remove the default config:
sudo rm /etc/nginx/sites-enabled/default
sudo systemctl reload nginx
Common errors
| Symptom | Cause | Fix |
|---|---|---|
| 403 Forbidden | no permissions on the files | chown www-data and chmod 755 |
| 404 on every URL | wrong root |
check the directory path |
| PHP downloads as a file | no location ~ \.php$ block |
add FPM handling |
| Another site opens | default is still enabled |
remove the default config |
Step 6. Logs for troubleshooting
If something does not work, look at the error log of that specific site:
sudo tail -f /var/log/nginx/example.com.error.log
FAQ
How does a server block differ from an Apache virtual host?
It is the same concept — the description of a single site. In Nginx one server { } block equals one virtual host.
Do I have to restart Nginx after every change?
systemctl reload nginx is enough: it applies the config without dropping active connections. A full restart is rarely needed.
How do I host several sites on one server?
Create a separate file in sites-available for each domain with a unique server_name and root, then enable them with symlinks in sites-enabled.
Why does the browser show an old version of the page?
The cache from the expires block kicked in. Clear the browser cache or shorten the cache lifetime while developing.
Once deployed, add HTTPS — Nginx works well with Let’s Encrypt certificates. For production sites, look at the plans on the VPS hosting page, and for a CMS there is WordPress VPS.