The cleanest and probably the "safest" way to do this part is to generate configuration with Drush, it's amazing how this tool never fails to surprise in the most positive way! Otherwise, check below more extensive example - warning just an example - there is some extra security rules as well as gzip compression etc.
Additionally, there is a Logrotate utilization example.
Install
Code
# Install current stable version.
apt install nginx
# Check Firewall settings.
ufw app list
# Make sure NGINX has full access.
ufw allow 'Nginx Full'
# Confirm firewall status.
ufw status
# Check NGINX status.
systemctl status nginx
Generate server block with Drush
Code
drush generate misc:nginx-virtual-host
Advanced example, Drupal >= 10
Code
server {
listen 135.181.156.54:443 ssl http2;
listen [::]:443 ssl http2;
server_name ph-eu.dev;
set $base /usr/share/nginx/html/ph-eu.dev;
root $base/web;
# SSL.
ssl_certificate /etc/letsencrypt/live/ph-eu.dev/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ph-eu.dev/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/ph-eu.dev/chain.pem;
# Security headers.
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# Gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;
# Indexes
index index.php index.htm index.html;
# Disable sendfile as per https://docs.vagrantup.com/v2/synced-folders/virtualbox.html
#sendfile off;
#error_log /dev/stdout info;
#access_log /var/log/nginx/access.log;
location / {
absolute_redirect off;
try_files $uri $uri/ /index.php?$query_string; # For Drupal >= 7
}
location @rewrite {
# For D7 and above:
# Clean URLs are handled in drupal_environment_initialize().
rewrite ^ /index.php;
}
# Handle image styles for Drupal 7+.
location ~ ^/sites/.*/files/styles/ {
try_files $uri @rewrite;
}
# Pass the PHP scripts to FastCGI server listening on socket.
location ~ '\.php$|^/update.php' {
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_intercept_errors off;
# fastcgi_read_timeout should match max_execution_time in php.ini
fastcgi_read_timeout 10m;
fastcgi_param SERVER_NAME $host;
#fastcgi_param HTTPS $fcgi_https;
}
# Prevent clients from accessing hidden files (starting with a dot)
# This is particularly important if you store .htpasswd files in the site hierarchy
# Access to `/.well-known/` is allowed.
# https://www.mnot.net/blog/2010/04/07/well-known
# https://tools.ietf.org/html/rfc5785
location ~* /\.(?!well-known\/) {
deny all;
}
# Prevent clients from accessing to backup/config/source files.
location ~* (?:\.(?:bak|conf|dist|fla|in[ci]|log|psd|sh|sql|sw[op])|~)$ {
deny all;
}
# Regular private file serving (i.e. handled by Drupal).
location ^~ /system/files/ {
## For not signaling a 404 in the error log whenever the
## system/files directory is accessed add the line below.
## Note that the 404 is the intended behavior.
log_not_found off;
access_log off;
expires 30d;
try_files $uri @rewrite;
}
# Media: images, icons, video, audio, HTC.
location ~* \.(jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|webp|htc)$ {
try_files $uri @rewrite;
expires max;
log_not_found off;
}
# Js and Css always loaded.
location ~* \.(js|css)$ {
try_files $uri @rewrite;
expires -1;
log_not_found off;
}
# Logging.
access_log /usr/share/nginx/html/ph-eu.dev/logs/access.log;
error_log /usr/share/nginx/html/ph-eu.dev/logs/error.log warn;
#include /etc/nginx/common.d/*.conf;
#include /mnt/ddev_config/nginx/*.conf;
}
Logrotate option
Code
# Edit or create logrotate config
nano /etc/logrotate.d/nginx
# Append similar to this.
/usr/share/nginx/html/ph-eu.dev/logs/*.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
DIR=$(dirname $1);
#USER=$(stat -c "%U" $DIR);
chown -R nk_:www-data $DIR;
chmod 0755 $DIR/*;
endscript
su nk_ www-data
}
Sources
Install
Configuration
- https://www.zend.com/blog/configuring-nginx-for-drupal
- DDEV Drupal 10 conf: https://github.com/ddev/ddev/blob/master/pkg/ddevapp/webserver_config_assets/nginx-site-drupal10.conf
Docker Drupal 10 conf: https://github.com/dbierer/drupal_10_nginx_php_fpm/blob/main/Docker/drupal.conf - https://git.drupalcode.org/issue/drupal-2937161/-/blob/2937161-drupal-nginx-conf/example.nginx
- https://www.howtoforge.com/tutorial/debian-nginx-drupal