Set up your own Nginx web server

 · 8 mins

Set up your own Nginx web server

Nginx is a well known HTTP server powering many web sites (like ours) and other web apps (like reverse proxies) that is pretty easy to configure. With its speed and its cost (free!), people who don’t like shared hosting and know how to do things will generally choose to get their own web server and set it up themselves.

Requirements

  • A computer or server with a Linux distribution (recommended: Ubuntu, Debian, CentOS, RedHat)
  • If the latter is being configured from a remote location, a SSH client
  • A domain name pointed to the web server, otherwise the latter will not be easily accessible on the open web

Options

  • A SCP client which allows graphical file manipulation
  • A SSL/TLS certificate ready for installation

1 . Prepare your server

(The commands of our guide are for the Debian distribution) First of all, you need to SSH into your web server. Once in there, we can now start the procedure, but before we start we must make sure there are no traces of Nginx prior to its configuration:

sudo apt-get purge -- auto-remove nginx nginx-common
sudo apt-get clean
sudo apt-get update && sudo apt-get upgrade

Once this is done, we must also check there are no other web servers listening on port 80 and port 443:

sudo netstat -plunt

If there are any, you must change their configuration to listen to other ports, or uninstall them.

2. Install Nginx

Once all the preliminary steps are taken, we can now set up Nginx:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install nginx

This set of commands will set you up the default version of Nginx provided by your distribution’s main software source. If you wish to set up a more updated version, feel free to compile Nginx from source or add Nginx’s repositories to your sources list.

3. Configure Nginx

We will now configure Nginx with SSL/TLS enabled, for increased security. Therefore, we must start by configuring the DH parameters for Nginx using OpenSSL:

openssl dhparam -out /etc/nginx/dhparam.pem 2048

3.1 The main configuration file

Once this is done, we can now set up the main configuration file /etc/nginx/nginx.conf. Underneath, you will see a configuration we have written, and that you can use to replace the one already here.

user www-data;
pid /run/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 65535;

events {
	multi_accept on;
	worker_connections 65535;
}

http {
	charset utf-8;
	sendfile on;
	tcp_nopush on;
	tcp_nodelay on;
	server_tokens off;
	log_not_found off;
	types_hash_max_size 2048;
	client_max_body_size 16M;
	keepalive_timeout 65;

	include mime.types;
	default_type application/octet-stream;

	access_log /var/log/nginx/access.log;
	error_log /var/log/nginx/error.log warn;

	ssl_session_timeout 1d;
	ssl_session_cache shared:SSL:50m;
	ssl_session_tickets off;

	ssl_dhparam /etc/nginx/dhparam.pem;

    	ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
   	ssl_prefer_server_ciphers on;

	ssl_stapling on;
	ssl_stapling_verify on;
	resolver 8.8.8.8 8.8.4.4 208.67.222.222 208.67.220.220 valid=60s;
	resolver_timeout 2s;

	include /etc/nginx/conf.d/*.conf;
	include /etc/nginx/sites-enabled/*;
}

You might need to remove TLSv1.3 from the ssl_protocols line if your version of OpenSSL doesn’t support it.

3.2 The general parameters file

This file defines all the necessary headers of a regular site. It shall always be included within a site configuration file using the include directive, but never within a http block. It defines itself in the /etc/nginx/_general.conf

# 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 * data: 'unsafe-eval' 'unsafe-inline'" always;
#add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# . files
location ~ /\. {
	deny all;
}

# assets, media
location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ {
	expires 7d;
	access_log off;
}

# svg, fonts
location ~* \.(?:svgz?|ttf|ttc|otf|eot|woff|woff2)$ {
	add_header Access-Control-Allow-Origin "*";
	expires 7d;
	access_log off;
}

# 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/xml+rss application/atom+xml image/svg+xml;

This file should not be used for FastCGI parameters nor proxy headers.

3.3 The FastCGI configuration

This is a critical step to support dynamic sites, especially in PHP language. It defines itself in /etc/nginx/fastcgi.conf


fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  REQUEST_SCHEME     $scheme;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

4. Configuring the sites.

You will now see many cases under different scenarios and therefore different configurations.

4.1 A simple static site

Nginx is the fastest web server for static files, it’s significantly faster than Apache and uses less system resources. Now, to set up a static file on Nginx, you shall create a new file under /etc/nginx/sites-available/ and set:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name www.example.com;
    root /var/www/html/example.com/;
    index index.html index.htm;
    ssl_certificate /var/ssl/example.com/certificate.crt;
    ssl_certificate_key /var/ssl/example.com/private.key;
	add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    include _general.conf;
}

server {
    listen 80;
    listen [::]:80;
    server_name www.example.com example.com;
    return 301 https://$host$request_uri;
}

Replace with the appropriate values if needed. In this case, there is a SSL/TLS server which is configured, and the normal HTTP version is redirected to the HTTPS version. The document root is /var/www/html/example.com.

For the SSL/TLS certificate for HTTPS, all you need is to set it up in the directory of ssl_certificate directive. In our example, there must be two files in that directory: one .crt file that shall contain the leaf certificate and the eventual trust chains, and one private.key file that shall contain your private key.

There are many certificate authorities that you can use to get your certificate, including Let’s Encrypt, Buypass and TrustAsia (the free ones) or Comodo, DigiCert, GoDaddy (the paid ones).

If you really don’t want any security with your website, here’s an alternate configuration:

server {
        listen 80;
        listen [::]:80;
        server_name www.example.com example.com.com;
        include _general.conf;
        root /var/www/html/example.com/;
}

Although we do not recommend this pratice due to data tampering and eavesdropping.

4.2 Reverse proxies

Nginx is the best reverse proxy web server on the market. It is particularly useful when an application is listening on another port on HTTP only like GitLab-unicorn or Gogs, and you want to make it on the regular ports 80 and 443, with HTTPS to encrypt the communications. You must then create a new file under /etc/nginx/sites-available/ and add:

# Example configuration for a Git platform, replace the values!
server {

    listen 80;
    server_name example.com;
    
    return 301 https://$server_name$request_uri;
    
    location / {
        proxy_pass http://localhost:3000;
		proxy_set_header Host $host
    }


}

server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate /var/ssl/example.com/certificate.crt;
    ssl_certificate_key /var/ssl/example.com/private.key;


    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass http://localhost:3000;
		proxy_set_header Host $host
    }

}

# You may also reuse the try_files directive if static files in the reverse proxy are NOT loaded.

4.3 Dynamic sites

Here is an example configuration you can use for dynamic sites that use FastCGI:

server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
	
        server_name www.example.com;
	root /var/www/html/example.com/;
	
	index index.php;
	location / {
		try_files $uri $uri/ /index.php?$query_string;
	}
	location ~ \.php$ {
		include fastcgi.conf;
	}
	include _general.conf;


	# SSL
        ssl on;
        ssl_certificate /var/ssl/example.com/certificate.crt;
        ssl_certificate_key /var/ssl/example.com/private.key;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
        include _general.conf;
}

# Redirect the apex domain to its www version. You can also do the opposite, and you can also do that within any other block and for any site, not only dynamic websites.
server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;

        server_name example.com;

        # SSL
        ssl on;
        ssl_certificate /var/ssl/example.com/certificate.crt;
        ssl_certificate_key /var/ssl/example.com/private.key;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
        return 301 https://$host$request_uri;
}

# Redirect HTTP to HTTPS
server {
        listen 80;
        listen [::]:80;

        server_name www.example.com example.com;

        return 301 https://$host$request_uri;
}

4.4 General steps after configuration

Once all of that is done, you must create a symbolic link between your file in /etc/nginx/sites-available/ to a new file with the same name in /etc/nginx/sites-enabled. After that, feel free to test your configuration using:

sudo nginx -t

And if it works well, you can now restart Nginx using:

sudo systemctl restart nginx

Congratulations! Your website now works.

5. Begin creating your website

You shall now begin creating your website in the document root you have specified. Depending on your needs, you can make a dynamic site, a static site, a web app behind a reverse proxy… You might need to set up other tools like MySQL though.


Published by Rémy Samkocwa