Difference between revisions of "Install nginx"
Line 345: | Line 345: | ||
} | } | ||
− | The commented line should be uncommented | + | The commented line should be uncommented prior to letsencrypt certificate renewal, then commented after renewal. |
For servers or domains that do not offer HTTPS, use the following: | For servers or domains that do not offer HTTPS, use the following: |
Revision as of 17:44, 27 January 2019
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 and configure nginx
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:nginx/development
PPA for those desiring the development version of nginx, now called 'mainline' version.
The nginx -V
command will list the installed version of nginx and its compiled nginx modules.
Configure nginx
The main configuration file for nginx is nginx.conf
. This nginx PPA is configured such that nginx.conf
is generally only used for settings affecting how nginx runs and not site-specific rules. The default nginx.conf
file contains many obsolete and unnecessary directives, so it won't be used. Make a backup of the original nginx.conf
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 worker_processes
to the number of threads supported by the CPU. Setting this to auto
is an easier way to set this, though a number may be used instead and can be found using the command lscpu
, the output of which will display the details of the CPU. The CPU(s):
row of the output is the number of threads supported by the server.
The worker_connections
setting determines the maximum number of simultaneous connections that can be opened by a worker process. 1024
is likely sufficient unless the site experiences heavy traffic. The total simultaneous connections that the server can handle will be worker_connections
*worker_processes
.
By enabling multi_accept
, 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."[1] This can become an issue for higher traffic sites.
The client_max_body_size
sets the allowed maximum size of the client request body.[2] For some common web applications, this can become an issue. 20 MB is usually sufficient.
The index
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 include /etc/nginx/sites-enabled/*;
. This is what tells nginx to find the configuration for each site on the server. It is possible to manage sites directly from the nginx.conf
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 nginx.conf
. These files need to be created and configured.
Virtual server files
The configuration file for each website is located in the /etc/nginx/sites-available/
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 /etc/nginx/sites-enabled/
directory as per the line in the /etc/nginx/nginx.conf
that states include /etc/nginx/sites-enabled/*;
and content is served from the root
directory stated in the server
block of the symlinked sites-available
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, /etc/nginx/sites-enabled/default
is symlinked to /etc/nginx/sites-available/default
. Note that it is normal for symlinks to have 777 permissions and that this does not alter the permissions of the symlinked target. In /etc/nginx/sites-available/default
the line root /usr/share/nginx/html;
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 include
, 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 gzip
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 include
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 vanilla.conf
and vanilla_https.conf
are better than using forums.conf
and forums_https.conf
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:
# HTTP server 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; } }
Everything in the server
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 listen
setting defines ports to listen to for the IPv4 address and the the second listen
is for the IPv6 address. If there is no IPv6 address assigned to the server, do not set this directive.
Adding default_server
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 server
block per port on the server.
The root
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 server_name
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 access.log
and error.log
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 # invoke-rc.d nginx rotate >/dev/null 2>&1 start-stop-daemon --stop --signal USR1 --quiet --pidfile /run/nginx.pid --name nginx endscript }
Using the location /var/www/*/logs/*.log
means that the logs will be rotated for every website added to the server, assuming the same directory tree is used. The number after rotate
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 filename.log
, yesterday's will be filename.log.1
, the rest will be numbered .gz
archives (filename.log.2.gz
), with the lower numbers being the more recently created.
Note that the log files and archives will be owned by user www-data
and group adm
and have 0640
attributes. This could be an issue if different user is needing to read these files.
There is currently a 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 /var/www/
. It is not required that this directory be accessible to users that are members of the www-data
group and it can be convenient for servers with multiple users to create sub-directories of /var/www/
for storing common files. For this purpose, an additional group webdevs
is created. Current users requiring access to the website directories should be added to this new group and the www-data
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 /webdevs/
directory is created to be a convenient location to store files that members of the webdevs
group can all access without cluttering up the /var/www/
directory.
Add site content
Add an index.html
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 /var/www/example.com/public/index.html
and change Welcome to nginx!
to Welcome to example.com!
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 root
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 nginx.conf
, a sites-available file, global-configs file, package-configs file, adding a sites-enabled symlink, etc. (all effectively examples of changes to the nginx.conf
via the include
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 index.html
file in /var/www/example.com/public/
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 access_log
is set to off
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:
# Redirect to www.example.com 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; }
The access_log off;
configuration reduces noise in the site's access log and the error_log
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:
# Redirect to www.example.com 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; }
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:
# Redirect to example.com 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; # root /var/www/example.com/public; }
The commented line should be uncommented prior to letsencrypt certificate renewal, then commented after renewal.
For servers or domains that do not offer HTTPS, use the following:
# Redirect to example.com 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; }
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 <head></head>
tags in the page source:
<meta HTTP-EQUIV="REFRESH" content="0; url=//www.example.com/location" />
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. server_name subdomain.example.com;
with appropriate directive set for the server block).
Custom error pages
Using the error_page
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 /var/www/example.com/public/404.html
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 error_page
directives are being used for different errors, it may be desirable to create a global-configs/error_page.conf
file and use the include
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 index
file and simply list the directory's contents in a browser, use the autoindex
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 default_server
.
root@servername:~# mkdir /var/www/<ipv4 address>/ root@servername:~# mkdir /var/www/<ipv4 address>/{logs,public} root@servername:~# mkdir /var/www/<ipv4 address>/public/{<ipv4 address>,<ipv6 address>} root@servername:~# nano /etc/nginx/sites-available/<ipv4 address>
Add to the file:
# IPv4 HTTP server server { listen 80; root /var/www/<ipv4 address>/public/<ipv4 address>; access_log /var/www/<ipv4 address>/logs/access.log; error_log /var/www/<ipv4 address>/logs/error.log; server_name <ipv4 address>; include global-configs/http_server.conf; location / { try_files $uri $uri/ =404; } } # IPv6 HTTP server server { listen [::]:80; root /var/www/<ipv4 address>/public/<ipv6 address>; access_log /var/www/<ipv4 address>/logs/access.log; error_log /var/www/<ipv4 address>/logs/error.log; server_name [<ipv6 address>]; include global-configs/http_server.conf; location / { try_files $uri $uri/ =404; } }
Create the sites-enabled
symlink, then verify and load the nginx configuration.
root@servername:~# ln -s /etc/nginx/sites-available/<ipv4 address> /etc/nginx/sites-enabled/ root@servername:~# nginx -t root@servername:~# service nginx reload
It is possible to have only one server block and one index.html
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://[<ipv6 address>]). Also be sure to update /etc/logrotate.d/nginx
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 limit_except
directive can be used to block these requests.
Block requests to a server by adding limit_except
to a location
block:
location / { limit_except GET { deny all; } try_files $uri $uri/ =404; }
.htaccess
There is no option in nginx to use .htaccess
files. However, much of what is accomplished through .htaccess
files can be done in location blocks. There is a converter at Winginx.com that can make some conversions of .htaccess
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 .htaccess
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.
References
External links
How to set up a safe and secure Web server | Ars Technica
Nginx/Location - WhyAskWhy.org Includes convenient reference for regular expressions commonly used in nginx location
blocks.
Regular-Expressions.info Tutorials for learning regular expressions.