Nginx web server comes with the default website. But there will be business cases where you have to host more than one website or sub domain on your Nginx web server. In many cases, you might want to configure nginx as reverse proxy for multiple website that are hosted on your upstream server, such as Apache. This article will guide you with common configurations that tune your nginx server’s performance and offer first line of security. This article assumes that you have nginx installed on Ubuntu 16.04 LTS.
nginx.conf
Modify your nginx.conf’s http { } block with the attributes below.
user www-data; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf; events { worker_connections 10000; multi_accept on; } http { # Basic sendfile on; tcp_nopush on; tcp_nodelay on; types_hash_max_size 2048; # worker connections worker_processes 1; worker_connections 1024; # keepalive keepalive_requests 500 keepalive_timeout 65; # buffers client_body_buffer_size 100K; client_header_buffer_size 1k; client_max_body_size 25m; large_client_header_buffers 4 16k; #fastcgi fastcgi_buffers 8 16k; fastcgi_buffer_size 32k; fastcgi_connect_timeout 300; fastcgi_send_timeout 300; fastcgi_read_timeout 300; # timeouts client_body_timeout 10; client_header_timeout 10; send_timeout 10; server_names_hash_bucket_size 64; # server_name_in_redirect off; include /etc/nginx/mime.types; default_type application/octet-stream; # Logging access_log /var/www/nginx_logs/access.log; # or off # access_log off; error_log /var/www/nginx_logs/error.log; # purge cache map $request_method $purge_method { PURGE 1; default 0; } # disable bots if ($http_user_agent ~* LWP::Simple|BBBike|wget) { return 403; } # restrict header types add_header Allow "GET, POST, HEAD" always; if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 444; } # security headers server_tokens off; # add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block" always; add_header Content-Security-Policy "default-src 'self';"; add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload'; # Limit requests limit_conn_zone $binary_remote_addr zone=global_limit_conn_zone:10m; limit_req_zone $binary_remote_addr zone=global_limit_req_zone:10m rate=50r/s; # proxy cache proxy_cache_path /tmp/nginx levels=1:2 keys_zone=global_cache_zone:20m max_size=500m inactive=60m use_temp_path=off purger=on; proxy_cache_key "$scheme$request_method$host$proxy_host$request_uri"; # SSL Settings ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:50m; ssl_session_timeout 10m; # gzip gzip on; gzip_disable "msie6"; gzip_comp_level 6; gzip_min_length 1000; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_vary on; gzip_proxied expired no-cache no-store private auth; gzip_types text/plain application/x-javascript text/xml text/css application/xml application/json application/javascript application/xml+rss text/javascript; # Virtual Hosts include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*.conf; # .. }
Virtual Hosts
You can create individual configuration files for individual websites/subdomain sites in /etc/nginx/sites-available/.
$ sudo nano /etc/nginx/sites-available/www.example.com
Your site configuration file will typically have only server { } block. Below is the typical configuration that you can use. The configuration blocks have comments to make you understand what they mean.
server { listen 80; root /var/www/example.com/www.example.com; index index.php index.html index.htm; server_name example.com www.example.com; location / { # try_files $uri $uri/ /index.php; # ddos protection limit_req zone=global_limit_req_zone burst=20 nodelay; limit_req_log_level warn; limit_req_status 444; limit_conn conn_limit_per_ip 10; # deny IPs # deny 123.123.123.0/28; # proxy cache add_header X-Proxy-Cache $upstream_cache_status; proxy_cache global_cache_zone; proxy_cache_min_uses 5; proxy_cache_bypass $http_cache_control; proxy_cache_bypass $cookie_nocache $arg_nocache$arg_comment; proxy_cache_methods GET HEAD POST; proxy_cache_valid 200 302 10m; proxy_cache_valid 404 1m; proxy_cache_valid any 5m; proxy_no_cache $http_pragma $http_authorization; proxy_cache_purge $purge_method; # reverse proxy include proxy_params; proxy_pass http://127.0.0.1:8080; } location ~ \.php$ { # include snippets/fastcgi-php.conf; # fastcgi_pass unix:/run/php/php7.4-fpm.sock; } location ~ /\.ht { deny all; } # security headers server_tokens off; add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block" always; add_header Content-Security-Policy "default-src 'self';"; # enables server-side protection from BEAST attacks ssl_prefer_server_ciphers on; ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4:@STRENGTH"; # gzip responses gzip on; gzip_disable "msie6"; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; gzip_min_length 50000; gzip_proxied no-cache no-store private expired auth; # Expire rules for static content # cache.appcache, your document html and data location ~* \.(?:manifest|appcache|html?)$ { expires -1; # access_log logs/static.log; # I don't usually include a static log } # Feed location ~* \.(?:rss|atom)$ { expires 1h; add_header Cache-Control "public"; } # Media: images, icons, video, audio, HTC location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|otf|ttf|eot|woff)$ { expires 1M; access_log off; tcp_nodelay off; add_header Vary Accept-Encoding; add_header Cache-Control "public"; ## Set the OS file cache. open_file_cache max=3000 inactive=120s; open_file_cache_valid 45s; open_file_cache_min_uses 2; open_file_cache_errors off; } # CSS and Javascript location ~* \.(?:css|js)$ { expires 1w; access_log off; add_header Cache-Control "public"; } }
Once the virtual host file is added, link it to sites-available and restart the nginx server
$ sudo ln -s /etc/nginx/sites-available/www.example.com /etc/nginx/sites-enabled/www.example.com $ sudo service nginx restart