Install nginx

This article describes the installation and configuration of nginx onto Ubuntu Server 18.04 and is part of a series of articles covering creating a LEMP web server.

Nearly all of the commands in this article require root privileges, so elevate the session to a root session:

username@servername:~$ sudo -i

Install nginx
For this installation and server configuration, a popular Personal Package Archive (PPA) will be added as the repository for nginx:

root@servername:~# add-apt-repository ppa:nginx/stable && aptitude update root@servername:~# aptitude install nginx root@servername:~# nginx -V

It is also an option to install the  PPA for those desiring the development version of nginx, now called 'mainline' version.

The  command will list the installed version of nginx and its compiled nginx modules.

Configure nginx
The main configuration file for nginx is. This nginx PPA is configured such that  is generally only used for settings affecting how nginx runs and not site-specific rules. The default  file contains many obsolete and unnecessary directives, so it won't be used. Make a backup of the original  file and create a new one:

root@servername:~# mv /etc/nginx/nginx.conf /etc/nginx/original.nginx.conf root@servername:~# nano /etc/nginx/nginx.conf

Paste into the new file:

user www-data; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf; events { worker_connections 1024; multi_accept on; } http { sendfile on; tcp_nopush on; tcp_nodelay on; types_hash_max_size  2048; server_tokens off; client_max_body_size 20000k; client_header_timeout 10; client_body_timeout  10; keepalive_timeout    10 10; send_timeout         10; index index.html index.htm; include /etc/nginx/mime.types; default_type application/octet-stream; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; }

Change  to the number of threads supported by the CPU. Setting this to  is an easier way to set this, though a number may be used instead and can be found using the command , the output of which will display the details of the CPU. The  row of the output is the number of threads supported by the server.

The  setting determines the maximum number of simultaneous connections that can be opened by a worker process. is likely sufficient unless the site experiences heavy traffic. The total simultaneous connections that the server can handle will be *.

By enabling, nginx processes will grab connections more aggressively. From the nginx wiki: "If disabled, a worker process will accept one new connection at a time. Otherwise, a worker process will accept all new connections at a time." This can become an issue for higher traffic sites.

The  sets the allowed maximum size of the client request body. For some common web applications, this can become an issue. 20 MB is usually sufficient.

The  directive establishes what nginx will open when a directory is called from a browser, either by specific file name or by file type, and will do this in order from left to right.

Note the line further down which states. This is what tells nginx to find the configuration for each site on the server. It is possible to manage sites directly from the  file, but this is not recommended as it can get rather cluttered, which tends to increase the prevalence of syntax errors and other misconfigurations.

Configure and enable virtual servers
As mentioned above, site settings are managed in their own files instead of directly editing. These files need to be created and configured.

Virtual server files
The configuration file for each website is located in the  directory, but the files here are only for the settings of each site and do not tell nginx to serve the site nor do they contain the content of a site. Nginx will only serve sites that are in the  directory as per the line in the   that states   and content is served from the   directory stated in the   block of the symlinked   file. To see this currently in action, run the following:

root@servername:~# ll /etc/nginx/sites-available/ && ll /etc/nginx/sites-enabled/

With the initial nginx setup,  is symlinked to. Note that it is normal for symlinks to have 777 permissions and that this does not alter the permissions of the symlinked target. In  the line   tells nginx where to get the content for the site.

Create global-configs directory
Some configuration settings are desirable for nearly all virtual servers and some configuration settings are desirable for all servers running specific options. By making files with these common settings and using, these settings can be easily and conveniently added and managed while keeping the sites-available files easier to read.

root@servername:~# mkdir /etc/nginx/global-configs root@servername:~# nano /etc/nginx/global-configs/http_server.conf

Paste into the new file:

location ~ /\. { access_log off; log_not_found off; deny all; } location ~ ~$ { access_log off; log_not_found off; deny all; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { allow all; log_not_found off; access_log off; } gzip on; gzip_disable "msie6"; gzip_min_length 1100; gzip_vary on; gzip_proxied any; gzip_buffers 16 8k; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/rss+xml text/javascript image/svg+xml application/x-font-ttf font/opentype application/vnd.ms-fontobject;

The first two entries prevent nginx from opening files that are a potential security risk and the second two reduce noise in the access log. The  directives enable compression such that there is a balance between server load and bandwidth.

Create package-configs directory
Popular web packages can be universally configured for serving on multiple server blocks by using the  directive in a given site's server block. This is another way to reduce syntax errors in virtual server configurations, make the configuration files cleaner and easier to read, and reduce the time required to correct the package configuration issues that inevitably arise.

root@servername:~# mkdir /etc/nginx/package-configs

Most packages will require two files - one for the HTTP server block and one for the HTTPS server block, the latter of which is addressed in more detail when setting up SSL/TLS.

Note that when making package-configs files, it is better to use the package name than its category. For example, when installing Vanilla Forums, using the file names  and   are better than using   and   because the same server may also host a Phorum forum, which would require a different package-configs file.

Create a virtual server
Assuming a domain is ready to go and appropriate DNS records have been created and are pointing at the server, disable the default settings and create a new sites-available file.

root@servername:~# rm /etc/nginx/sites-enabled/default root@servername:~# mv /etc/nginx/sites-available/default /etc/nginx/sites-available/original.sites-available.file root@servername:~# nano /etc/nginx/sites-available/example.com

Paste the following into the new file:

server { listen 80 default_server; listen [::]:80 default_server; root /var/www/example.com/public; access_log /var/www/example.com/logs/access.log; error_log /var/www/example.com/logs/error.log; server_name example.com www.example.com; include global-configs/http_server.conf; location / { try_files $uri $uri/ =404; } }
 * 1) HTTP server

Everything in the  brackets is referred to as the server block, and the file can have more than one server block. It is good practice to have the main HTTP server block be the first server block in a sites-available file.

The first  setting defines ports to listen to for the IPv4 address and the the second   is for the IPv6 address. If there is no IPv6 address assigned to the server, do not set this directive.

Adding  tells nginx to serve this when http requests hit the server and nothing else matches the request. Note that with this setting, the server will serve this sites-available file even when someone inputs the IP address. This setting can only be applied to one  block per port on the server.

The  setting establishes the location of the root directory for the website's content. Everything in this directory will be publicly available unless special rules are added to prevent access to specific locations.

The  is how nginx knows which server block to serve when a request comes in. The example file above uses the common www subdomain, but server blocks can also be made for other subdomains such as forum, blog, mail, or whatever is desired, and the subdomains can be in their own server blocks so that they can have their own unique configurations.

Logrotate
Adding additional locations of the  and   files means that the current nginx logrotate file needs to be updated.

root@servername:~# nano /etc/logrotate.d/nginx

Add the following below everything currently in the file:

/var/www/*/logs/*.log { daily missingok rotate 36500 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 start-stop-daemon --stop --signal USR1 --quiet --pidfile /run/nginx.pid --name nginx endscript }
 * 1) 		invoke-rc.d nginx rotate >/dev/null 2>&1

Using the location  means that the logs will be rotated for every website added to the server, assuming the same directory tree is used. The number after  is the number of rotations that logrotate will keep before deleting them. 36500 will keep 100 years of logs. Log archives are stored in the same directory as the logs are created. The most recent log will always be, yesterday's will be  , the rest will be numbered   archives , with the lower numbers being the more recently created.

Note that the log files and archives will be owned by user  and group   and have   attributes. This could be an issue if different user is needing to read these files.

There is currently a [//bugs.launchpad.net/nginx/+bug/1450770 bug in the nginx.org PPA] that affects the operation of log rotations. The nginx package installs with the commented out line not commented by default and without the line below it, which is a fix, so it is necessary to change these lines in the default log rotation block to match the new one.

Establish the website content directory tree and add content
The content of the websites will be located in a separate directory tree from the nginx configuration files. Since the server can host many sites, it is good practice to use a uniform method for storing each site's content.

The first directory in the tree will be. It is not required that this directory be accessible to users that are members of the  group and it can be convenient for servers with multiple users to create sub-directories of   for storing common files. For this purpose, an additional group  is created. Current users requiring access to the website directories should be added to this new group and the  group.

root@servername:~# addgroup webdevs root@servername:~# adduser username webdevs root@servername:~# adduser username www-data root@servername:~# mkdir -p /var/www/webdevs root@servername:~# chown -R root:webdevs /var/www/ root@servername:~# chmod -R g+s /var/www/ root@servername:~# mkdir -p /var/www/example.com/{backup,logs,private,public}/ root@servername:~# chmod -R 775 /var/www/ root@servername:~# touch /var/www/example.com/logs/{access.log,error.log} root@servername:~# chmod 664 /var/www/example.com/logs/{access.log,error.log} root@servername:~# chown www-data:adm /var/www/example.com/logs/*

In this setup, the directories are given 775 permissions and files 664 to make file editing and working with SFTP more convenient.

Note that any time a user's group membership is changed, the changes will not take effect in the current session. While this will not affect the root session currently being used, if the root session is exited, the user's session will have only the group memberships it had when it logged in.

The  directory is created to be a convenient location to store files that members of the   group can all access without cluttering up the   directory.

Add site content
Add an  file to the site's root directory. root@servername:~# cp /usr/share/nginx/html/index.html /var/www/example.com/public/ root@servername:~# chmod 664 /var/www/example.com/public/index.html

It can be a good idea to change something in the file to make it unique, this way it can be accurately determined that the page being served is not from some other previous configuration. For example, open  and change   to   in the header and body.

Now create the sites-enabled symlink to tell nginx to serve the site:

root@servername:~# ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com

It is generally a good idea to test the nginx configuration after making changes to it. Note that the test should always be run with  privileges and it is not necessary to resart the nginx service to run the test. If anything other than the following output is displayed, investigate and repair immediately:

root@servername:~# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful

Whenever a change is made to an nginx configuration, such as editing, a sites-available file, global-configs file, package-configs file, adding a sites-enabled symlink, etc. (all effectively examples of changes to the   via the   directive), the nginx service must be reloaded for the changes to take effect. Note that this is not necessary to restart nginx for changes to site content.

root@servername:~# service nginx reload

Open the firewall and test
Verify UFW is aware of nginx and enable nginx to be available through the firewall:

root@servername:~# ufw app list Available applications: Nginx Full Nginx HTTP Nginx HTTPS OpenSSH root@servername:~# ufw allow 'Nginx Full'

The  file in   should now load when pointing a browser to  http://www.example.com .

The server can now serve static http websites. Not very exciting, but very fast!

Common and useful configurations
Nginx is vastly configurable with nearly unlimited options, however, there are some configurations that administrators commonly wish to employ. The below configurations are just one way to accomplish the titled configuration goal.

Configurations below that include HTTPS blocks will only function after setting up SSL/TLS with letsencrypt, which is covered in the next article.

Redirecting subdomains
It is common to serve a site primarily as either  http://example.com  or  http://www.example.com . The following two configurations will permanently redirect browsers to one or the other.

Note that  is set to   to reduce log noise, but the error log is still configured. Occasionally, there may be issues related to redirection and it can be useful to create a separate error log file just for redirects since the configurations below will log errors to the domain's main error log.

Force www subdomain
To force the server to only load a domain using the www subdomain, use the following configuration.

root@servername:~# nano /etc/nginx/sites-available/example.com

Change the following in the HTTP server block:

server_name www.example.com;

Add the following server block to the bottom of the file:

server { listen 80; listen 443 ssl; listen [::]:80; listen [::]:443 ssl; server_name example.com; access_log off; error_log /var/www/example.com/logs/error.log; include global-configs/https_server.conf; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem; return 301 $scheme://www.example.com$request_uri; }
 * 1) Redirect to www.example.com

The  configuration reduces noise in the site's access log and the   configuration directs errors to be logged in the site's error log instead of the general nginx error log.

For servers or domains that do not offer HTTPS, use the following:

server { listen 80; listen [::]:80; server_name example.com; access_log off; error_log /var/www/example.com/logs/error.log; return 301 http://www.example.com$request_uri; }
 * 1) Redirect to www.example.com

Force no www subdomain
To force the server to only load a domain and not use the www subdomain, use the following configuration.

root@servername:~# nano /etc/nginx/sites-available/example.com

Change the following in the HTTP server block:

server_name example.com;

Add the following server block below the HTTP server block:

server { listen 80; listen 443 ssl; listen [::]:80; listen [::]:443 ssl; server_name www.example.com; access_log off; error_log /var/www/example.com/logs/error.log; include global-configs/https_server.conf; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem; return 301 $scheme://example.com$request_uri; }
 * 1) Redirect to example.com
 * 1)    root /var/www/example.com/public;

The commented line should be uncommented during letsencrypt certificate renewal, then commented after renewal.

For servers or domains that do not offer HTTPS, use the following:

server { listen 80; listen [::]:80; server_name www.example.com; access_log off; error_log /var/www/example.com/logs/error.log; return 301 http://example.com$request_uri; }
 * 1) Redirect to example.com

HTML redirect
Although not an nginx configuration, it may be desired to redirect a page without configuring nginx. This can be accomplished by placing the following entry between the  tags in the page source:



Force a directory to load a subdomain
To force the server to send a user to a subdomain when requesting a directory, such as redirecting  www.example.com/blog/  to  blog.example.com , use the following configuration.

root@servername:~# nano /etc/nginx/sites-available/example.com

Add the following location block to the HTTP server block:

location ^~ /directoryname/ { rewrite ^ http://subdomain.example.com permanent; }

This should be included for any server block serving the domain. For example, an associated HTTPS server block would include this location block. Note that this configuration requires a server block for the subdomain (e.g.  with appropriate directive set for the server block).

Custom error pages
Using the  directive allows for custom pages to be displayed based on error codes, the most common being 404. Here is an example of how to use the directive for this code.

Create a webpage that will be the error page. This can be named anything, but for this example the file is

Open the sites-available file and add the directive to the applicable server blocks:

username@servername:~$ sudo nano /etc/nginx/sites-available/example.com

In each server block that the directive will be applicable for, add:

error_page 404 /404.html;

If several  directives are being used for different errors, it may be desirable to create a   file and use the   directive to clean up the server block code.

The nginx wiki has additional details for this directive.

Autoindex
To enable nginx to load the contents of a directory with no  file and simply list the directory's contents in a browser, use the   directive:

location /subdirectory/ { autoindex on; }

Serve IP address as page
For various reasons it may be desirable to serve a page for the server's IP address. Without this configuration, nginx will send requests for the IP address to the configured.

root@servername:~# mkdir /var/www/ / root@servername:~# mkdir /var/www/ /{logs,public} root@servername:~# mkdir /var/www/ /public/{, } root@servername:~# nano /etc/nginx/sites-available/

Add to the file:

server { listen 80; root /var/www/ /public/ ; access_log /var/www/ /logs/access.log; error_log /var/www/ /logs/error.log; server_name ; include global-configs/http_server.conf; location / { try_files $uri $uri/ =404; } } server { listen [::]:80; root /var/www/ /public/ ; access_log /var/www/ /logs/access.log; error_log /var/www/ /logs/error.log; server_name [ ]; include global-configs/http_server.conf; location / { try_files $uri $uri/ =404; } }
 * 1) IPv4 HTTP server
 * 1) IPv6 HTTP server

Create the  symlink, then verify and load the nginx configuration. root@servername:~# ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/ root@servername:~# nginx -t root@servername:~# service nginx reload

It is possible to have only one server block and one  file to serve both IP addresses. The above configuration supports having separate files for displaying different pages for each IP address or even log to different logfiles. To visit an IPv6 address from a browser, enclose the address in brackets (e.g., http://[ ]</tt>). Also be sure to update  with a new block specifying the location of the log files.

Block POST requests
In some rare cases it may be desired to block POST requests coming from bots to specific locations or URLs. The  directive can be used to block these requests.

Block requests to a server by adding  to a   block:

location / { limit_except GET { deny all; }        try_files $uri $uri/ =404; }

.htaccess
There is no option in nginx to use  files. However, much of what is accomplished through  files can be done in location blocks. There is a converter at Winginx.com that can make some conversions of  files for use in nginx, but note that it should be considered only a guide to provide a place to start, as the generated configuration will most likely not be suitable for production use. If the  file is needing to be converted for a popular package, don't forget to search the web for a possible solution.

Next step
Now that nginx is set up, it's time to configure the server for SSL/TLS.