From Fedora Project Wiki

m (Remove trailing slashes in semanage command. They produce errors.)
 
(29 intermediate revisions by 5 users not shown)
Line 1: Line 1:
Nginx is a fast and lightweight web, http load balancer, reverse proxy and http cache server. The main characteristics are efficiency and escalability which makes Nginx suited for both the small and the bussiest servers on the Internet.
'''Nginx''' (pronounced "engine-x") is a fast and lightweight web server, http load balancer, reverse proxy and http cache server. The main characteristics are efficiency and scalability which makes Nginx suited for both the small and the busiest servers on the Internet.
 
You can find more documentation at the [http://nginx.org Nginx website].


== Installation ==
== Installation ==
For Fedora 22 and later versions use [[dnf|DNF]]:
$ su
# dnf install nginx
Or for older releases use YUM:


  $ su
  $ su
  # yum install nginx
  # yum install nginx


To have the server start at each boot:
To start the server at each boot:


  # systemctl enable nginx.service
  # systemctl enable nginx.service
Line 16: Line 24:
== Configuration ==
== Configuration ==


The configuration of nginx is straight forward. The main configuration file is located in {{filename|/etc/nginx/nginx.conf}} and is structured in the following way, first there is some very general configuration about nginx itself and an events block which look like this:
The main configuration file is located in {{filename|/etc/nginx/nginx.conf}} and is structured in the following way. First, there are some very general configuration options about nginx itself and an events block. Notice you should use a semicolon (;) after each option, except for the blocks themselves.
 
  user              nginx;
  user              nginx;
  worker_processes  1;
  worker_processes  auto;
   
   
  error_log  /var/log/nginx/error.log;
  error_log  /var/log/nginx/error.log;
Line 25: Line 34:
   
   
  pid        /var/run/nginx.pid;
  pid        /var/run/nginx.pid;
   
   
  events {
  events {
Line 31: Line 39:
  }
  }


The advised number of processes is the number of cores/threads your cpu has. Remember that you should write a semicolon(;) after each option, except for the blocks themselves.
The web server process will run as `root` so it can open protected ports. However, worker threads will run under the account specified by `user`, which is the user `nginx` shown above. The advised number of processes is the number of cores/threads your cpu has. You can leave it at `auto` or specify the number of workers.


After that there is one big http block that contains the general configuration related to this protocol. Notice that inside this block there is the following line
Second, there is one big http block that contains the general configuration related to this protocol. Notice that inside this block there is the following line:
    include /etc/nginx/conf.d/*.conf;
include /etc/nginx/conf.d/*.conf;
which tells us that the rest of the configuration files are going to be in the configuration directory {{filename|/etc/nginx/conf.d/}} and are going to have a .conf extension.
which tells us that the rest of the configuration files are going to be in the configuration directory {{filename|/etc/nginx/conf.d/}} and are going to have a .conf extension.


And inside this http block, either in the nginx.conf file itself or included from the configuration directory {{filename|/etc/nginx/conf.d/}} there is one server block per virtual host.
And inside this http block, either in {{filename|nginx.conf}} file or included from the configuration directory {{filename|/etc/nginx/conf.d/}} there is one server block per virtual host. The http block provides the `server_name` and document root.
 
Note that the default document root from {{filename|nginx.conf}} is {{filename|/usr/share/nginx/html}}. If you have questions regarding file permissions, directory permissions or SELinux contexts, you can examine them using the default.


== Webserver ==
Best practice is leave {{filename|/etc/nginx/nginx.conf}} untouched, and provide one configuration file under {{filename|/etc/nginx/conf.d/}} for each site. For example, if you are serving for {{filename|example.com}}, then you would create {{filename|/etc/nginx/conf.d/example.com.conf}} for the site.


Nginx was designed to be a webserver. All you need to create a virtual host is to create a new file in the {{filename|/etc/nginx/conf.d/}} directory with a .conf extension and a server block in it. the server block will be automatically included in the http block.
== Web Server ==
 
Nginx is designed to allow multiple sites. All you need to create a virtual host is to create a new file in the {{filename|/etc/nginx/conf.d/}} directory with a .conf extension and a server block in it. The server block will be automatically included in the http block.
 
For example, {{filename|/etc/nginx/conf.d/example.com.conf}}
server {
listen 80;
server_name example.com;
root /var/www/example.com/public_html;
index index.php index.html;
}
 
You can also specify multiple server names in the `server_name` option:
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/public_html;
index index.php index.html;
}


For example, {{filename|/etc/nginx/conf.d/myhost.com.conf}}
You can listen for IPv6 using multiple `listen` options:
  server {
  server {
  listen 80;
  listen 80;
  server_name myhost.com;
listen [::]:80;
  root /var/www/myhost.com/public_html;
server_name example.com www.example.com;
root /var/www/example.com/public_html;
index index.php index.html;
}
 
You can also change the port Nginx listens on using the `listen` option:
 
server {
listen 3131;
  server_name example.com www.example.com;
  root /var/www/example.com/public_html;
  index index.php index.html;
  index index.php index.html;
  }
  }


=== TLS/SSL ===
Note that you may need to modify the `http_port_t` in SELinux as shown below.


Nginx uses ngx_http_ssl_module which is based on OpenSSL and at the moment there are no alternatives.
# semanage port -a -t http_port_t -p tcp 3131


==== Install an existing certificate ====
`semanage` is discussed in the [[#SELinux_Contexts|SELinux Contexts]] section below.
 
== SSL/TLS Configuration ==
 
Nginx uses `ngx_http_ssl_module` to provide secure sockets. You can modify SSL/TLS parameters, like protocol versions and cipher suites.
 
`ngx_http_ssl_module` relies on OpenSSL. At the moment there are no alternatives to OpenSSL.
 
=== Install an existing certificate ===


If you already have a certificate generated on another computer, move the certificate and the key file to the correct folder, and ensure their SELinux contexts, ownerships and permissions are correct:
If you already have a certificate generated on another computer, move the certificate and the key file to the correct folder, and ensure their SELinux contexts, ownerships and permissions are correct:


  # mv key_file.key /etc/pki/tls/private/myhost.com.key
  # mv key_file.key /etc/pki/tls/private/example.com.key
  # restorecon /etc/pki/tls/private/myhost.com.key
  # restorecon /etc/pki/tls/private/example.com.key
  # chown root.root /etc/pki/tls/private/myhost.com.key
  # chown root:root /etc/pki/tls/private/example.com.key
  # chmod 0600 /etc/pki/tls/private/myhost.com.key
  # chmod 0600 /etc/pki/tls/private/example.com.key
  # mv certificate.crt /etc/pki/tls/certs/myhost.com.crt
  # mv certificate.crt /etc/pki/tls/certs/example.com.crt
  # restorecon /etc/pki/tls/private/myhost.com.crt
  # restorecon /etc/pki/tls/private/example.com.crt
  # chown root.root /etc/pki/tls/private/myhost.com.crt
  # chown root:root /etc/pki/tls/private/example.com.crt
  # chmod 0600 /etc/pki/tls/private/myhost.com.crt
  # chmod 0600 /etc/pki/tls/private/example.com.crt


After this [[#tls-configuration| set it up]]
`restorecon` is discussed in the [[#SELinux_Contexts|SELinux Contexts]] section below.


==== Generate a new certificate ====
=== Generate a new certificate ===


How to [https://fedoraproject.org/wiki/Https#openssl generate a new certificate]
If you are managing your own PKI, then see [https://fedoraproject.org/wiki/Https#openssl How to generate a new certificate] using OpenSSL.
 
If you are using Let's Encrypt with Certbot, then see the [[#Certbot|Certbot]] section below.


{{anchor|tls-configuration}}
{{anchor|tls-configuration}}
==== Configuring TLS hosts =====
 
=== Configuring TLS/SSL keys ===


Modify inside the server block of a particular virtual host the following lines or add them, so it looks like this:
Modify inside the server block of a particular virtual host the following lines or add them, so it looks like this:
<pre> listen 443 ssl;
listen 443 ssl;
ssl_certificate /etc/pki/tls/certs/myhost.com.crt
ssl_certificate /etc/pki/tls/certs/example.com.crt
ssl_certificate_key /etc/pki/tls/private/myhost.com.key
ssl_certificate_key /etc/pki/tls/private/example.com.key
</pre>
 
=== Strict Transport Security ===
 
The http Strict-Transport-Security response header (HSTS) tells user agents the site should only be accessed using https. You can add the header using the following option.
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains;";
 
=== Permanent HTTPS Redirect ===
 
A 301 redirect is a permanent server-side redirect that automatically sends users to a new URL when they request an old one. You can provide a permanent redirect from http to https using the following stanza.
if ($scheme = "http") {
    return 301 https://$server_name$request_uri;
}
 
=== Other Hardening ===
 
To further harden the SSL/TLS stack, you should disable session caching, session tickets and early data. Do so with the following options:
 
ssl_session_cache  off;
ssl_session_tickets off;
ssl_early_data      off;
 
Early data, a/k/a 0-RTT, is especially dangerous due to replay attacks. Replay attacks allow attackers to replay existing encrypted traffic -- no decryption is required. The mitigations to defend the attack requires use of global, stateful anti-replay hardening, which means all servers at all locations must remain synchronized to be effective.
 
Also see OpenSSL's [https://wiki.openssl.org/index.php/SSL/TLS_Client#0-RTT TLS Client] example for more information on the options
 
== Certbot ==
 
[https://certbot.eff.org/ Certbot] is a free, open source software tool by the Electronic Frontier Foundation used to  automatically encrypt web traffic using Let’s Encrypt certificates on manually-administrated websites.
 
To install Certbot for Nginx, issue the following commands:
# dnf install certbot python3-certbot-nginx
 
The install script will install Certbot and a Systemd timer to automatically renew the certificate before it expires. Certbot's configuration file is located at {{filename|/etc/sysconfig/certbot}}, and it's logrotate configuration file is located at {{filename|/etc/logrotate.d/certbot}}.
 
Before your run Certbot, setup the Nginx http server. Be sure to specify all the `server_names`, like `example.org` and `www.example.org`. Certbot will use the names in `server_name` to request a certificate for the web server.
 
Once the http server is setup, issue the following command to request a certificate.
# certbot --nginx
 
After Certbot runs the web server will be ready to handle TLS traffic.
 
== File Permissions ==
 
Nginx runs on top of Fedora Linux. The web server is bound by both traditional Unix & Linux permissions, like users and groups with read/write/execute access; and SELinux contexts, like `system_u` and `httpd_sys_content_t`. You have to manage both for a secure system, and you should follow [https://en.wikipedia.org/wiki/Principle_of_least_privilege Principle of Least Privilege] to minimize risk.
 
Note that the first permission checks happen using traditional Unix & Linux permissions to verify object access. If the traditional checks succeed, then the operating system will use SELinux checks to verify object access. If you have trouble, then first examine Unix & Linux permissions. If the traditional permissions are Ok, then move to troubleshooting SELinux contexts.
 
(Please do not perform a `chmod -R 0777 /var/www` like you find at places like Stack Overflow).
 
=== Unix & Linux permissions ===
After you install Nginx, the scriptlets create a `nginx` user and a `nginx` group. You can use the group to provide traditional Unix & Linux permissions, like read-only or read-write access to the files on the web server.
 
The configuration shown below follows the Principle of Least Privilege. `root` owns the documents, and `root` has read-write access. The group `nginx` has read access to the documents. And `other` users have no access to the documents.
# ls -l /var/www
drwxr-x---. 5 root nginx 4096 Nov 18 15:15 html
# ls -l /var/www/html
-rw-r-----. 1 root nginx  1633 Nov 18 15:15 index.html
 
You should use the owner `root:nginx` and resist the urge to use `nginx:nginx`. `nginx:nginx` gives the web server write access to the documents, and there is usually no reason for the web server to have write access to static html files.
 
=== SELinux Contexts ===
Traditional Unix & Linux permissions are only half the recipe. You must also manage SELinux contexts or risk a 403 - the "Forbidden" error.
 
Continuing with the {{filename|/var/www/html}} example, you have to set the SELinux context. To learn the context set by the Fedora maintainers, check {{filename|/usr/share/nginx/html}}:
# ls -Z /usr/share/nginx/html
system_u:object_r:httpd_sys_content_t:s0 index.html
system_u:object_r:httpd_sys_content_t:s0 nginx-logo.png
...
 
So the final task is to change the context to `system_u:object_r:httpd_sys_content_t:s0`:
# restorecon -R /var/www/html
# ls -Z /var/www/html/
system_u:object_r:httpd_sys_content_t:s0 index.html
system_u:object_r:httpd_sys_content_t:s0 nginx-logo.png
...
 
If you are using an unusual directory for server storage, like {{filename|/opt/www/html}}, then you may not be able to use `restorecon` to automatically fix the SELinux context. In this case, set the context using `chcon` and save the change using `semanage` to make the change permanent:
# chcon -R system_u:object_r:httpd_sys_content_t:s0 /opt/www
# semanage fcontext -a -t httpd_sys_content_t "/opt/www(/.*)?"
# restorecon -rv /opt/www
 
Or, since you know you want {{filename|/opt/www/html}} to be like {{filename|/var/www/html}}, you can perform the following:
 
# semanage fcontext --add --equal /var/www/html /opt/www/html
# restorecon -rv /opt/www/html
 
Also see [https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html-single/using_selinux/index#customizing-the-selinux-policy-for-the-apache-http-server-in-a-non-standard-configuration_configuring-selinux-for-applications-and-services-with-non-standard-configurations Customizing the SELinux policy for the Apache HTTP server in a non-standard configuration] in Red Hat's SELinux documentation.

Latest revision as of 18:42, 20 November 2024

Nginx (pronounced "engine-x") is a fast and lightweight web server, http load balancer, reverse proxy and http cache server. The main characteristics are efficiency and scalability which makes Nginx suited for both the small and the busiest servers on the Internet.

You can find more documentation at the Nginx website.

Installation

For Fedora 22 and later versions use DNF:

$ su
# dnf install nginx

Or for older releases use YUM:

$ su
# yum install nginx

To start the server at each boot:

# systemctl enable nginx.service

To start the server now:

# systemctl start nginx.service

Configuration

The main configuration file is located in /etc/nginx/nginx.conf and is structured in the following way. First, there are some very general configuration options about nginx itself and an events block. Notice you should use a semicolon (;) after each option, except for the blocks themselves.

user              nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log;
#error_log  /var/log/nginx/error.log  notice;
#error_log  /var/log/nginx/error.log  info;

pid        /var/run/nginx.pid;

events {
   worker_connections  1024;
}

The web server process will run as root so it can open protected ports. However, worker threads will run under the account specified by user, which is the user nginx shown above. The advised number of processes is the number of cores/threads your cpu has. You can leave it at auto or specify the number of workers.

Second, there is one big http block that contains the general configuration related to this protocol. Notice that inside this block there is the following line:

include /etc/nginx/conf.d/*.conf;

which tells us that the rest of the configuration files are going to be in the configuration directory /etc/nginx/conf.d/ and are going to have a .conf extension.

And inside this http block, either in nginx.conf file or included from the configuration directory /etc/nginx/conf.d/ there is one server block per virtual host. The http block provides the server_name and document root.

Note that the default document root from nginx.conf is /usr/share/nginx/html. If you have questions regarding file permissions, directory permissions or SELinux contexts, you can examine them using the default.

Best practice is leave /etc/nginx/nginx.conf untouched, and provide one configuration file under /etc/nginx/conf.d/ for each site. For example, if you are serving for example.com, then you would create /etc/nginx/conf.d/example.com.conf for the site.

Web Server

Nginx is designed to allow multiple sites. All you need to create a virtual host is to create a new file in the /etc/nginx/conf.d/ directory with a .conf extension and a server block in it. The server block will be automatically included in the http block.

For example, /etc/nginx/conf.d/example.com.conf

server {
	listen 80;
	server_name example.com;
	root /var/www/example.com/public_html;
	index index.php index.html;
}

You can also specify multiple server names in the server_name option:

server {
	listen 80;
	server_name example.com www.example.com;
	root /var/www/example.com/public_html;
	index index.php index.html;
}

You can listen for IPv6 using multiple listen options:

server {
	listen 80;
	listen [::]:80;
	server_name example.com www.example.com;
	root /var/www/example.com/public_html;
	index index.php index.html;
}

You can also change the port Nginx listens on using the listen option:

server {
	listen 3131;
	server_name example.com www.example.com;
	root /var/www/example.com/public_html;
	index index.php index.html;
}

Note that you may need to modify the http_port_t in SELinux as shown below.

# semanage port -a -t http_port_t -p tcp 3131

semanage is discussed in the SELinux Contexts section below.

SSL/TLS Configuration

Nginx uses ngx_http_ssl_module to provide secure sockets. You can modify SSL/TLS parameters, like protocol versions and cipher suites.

ngx_http_ssl_module relies on OpenSSL. At the moment there are no alternatives to OpenSSL.

Install an existing certificate

If you already have a certificate generated on another computer, move the certificate and the key file to the correct folder, and ensure their SELinux contexts, ownerships and permissions are correct:

# mv key_file.key /etc/pki/tls/private/example.com.key
# restorecon /etc/pki/tls/private/example.com.key
# chown root:root /etc/pki/tls/private/example.com.key
# chmod 0600 /etc/pki/tls/private/example.com.key
# mv certificate.crt /etc/pki/tls/certs/example.com.crt
# restorecon /etc/pki/tls/private/example.com.crt
# chown root:root /etc/pki/tls/private/example.com.crt
# chmod 0600 /etc/pki/tls/private/example.com.crt

restorecon is discussed in the SELinux Contexts section below.

Generate a new certificate

If you are managing your own PKI, then see How to generate a new certificate using OpenSSL.

If you are using Let's Encrypt with Certbot, then see the Certbot section below.

Configuring TLS/SSL keys

Modify inside the server block of a particular virtual host the following lines or add them, so it looks like this:

listen 443 ssl;
ssl_certificate /etc/pki/tls/certs/example.com.crt
ssl_certificate_key /etc/pki/tls/private/example.com.key

Strict Transport Security

The http Strict-Transport-Security response header (HSTS) tells user agents the site should only be accessed using https. You can add the header using the following option.

add_header Strict-Transport-Security "max-age=63072000; includeSubdomains;";

Permanent HTTPS Redirect

A 301 redirect is a permanent server-side redirect that automatically sends users to a new URL when they request an old one. You can provide a permanent redirect from http to https using the following stanza.

if ($scheme = "http") {
    return 301 https://$server_name$request_uri;
}

Other Hardening

To further harden the SSL/TLS stack, you should disable session caching, session tickets and early data. Do so with the following options:

ssl_session_cache   off;
ssl_session_tickets off;
ssl_early_data      off;

Early data, a/k/a 0-RTT, is especially dangerous due to replay attacks. Replay attacks allow attackers to replay existing encrypted traffic -- no decryption is required. The mitigations to defend the attack requires use of global, stateful anti-replay hardening, which means all servers at all locations must remain synchronized to be effective.

Also see OpenSSL's TLS Client example for more information on the options

Certbot

Certbot is a free, open source software tool by the Electronic Frontier Foundation used to automatically encrypt web traffic using Let’s Encrypt certificates on manually-administrated websites.

To install Certbot for Nginx, issue the following commands:

# dnf install certbot python3-certbot-nginx

The install script will install Certbot and a Systemd timer to automatically renew the certificate before it expires. Certbot's configuration file is located at /etc/sysconfig/certbot, and it's logrotate configuration file is located at /etc/logrotate.d/certbot.

Before your run Certbot, setup the Nginx http server. Be sure to specify all the server_names, like example.org and www.example.org. Certbot will use the names in server_name to request a certificate for the web server.

Once the http server is setup, issue the following command to request a certificate.

# certbot --nginx

After Certbot runs the web server will be ready to handle TLS traffic.

File Permissions

Nginx runs on top of Fedora Linux. The web server is bound by both traditional Unix & Linux permissions, like users and groups with read/write/execute access; and SELinux contexts, like system_u and httpd_sys_content_t. You have to manage both for a secure system, and you should follow Principle of Least Privilege to minimize risk.

Note that the first permission checks happen using traditional Unix & Linux permissions to verify object access. If the traditional checks succeed, then the operating system will use SELinux checks to verify object access. If you have trouble, then first examine Unix & Linux permissions. If the traditional permissions are Ok, then move to troubleshooting SELinux contexts.

(Please do not perform a chmod -R 0777 /var/www like you find at places like Stack Overflow).

Unix & Linux permissions

After you install Nginx, the scriptlets create a nginx user and a nginx group. You can use the group to provide traditional Unix & Linux permissions, like read-only or read-write access to the files on the web server.

The configuration shown below follows the Principle of Least Privilege. root owns the documents, and root has read-write access. The group nginx has read access to the documents. And other users have no access to the documents.

# ls -l /var/www
drwxr-x---. 5 root nginx 4096 Nov 18 15:15 html
# ls -l /var/www/html
-rw-r-----. 1 root nginx  1633 Nov 18 15:15 index.html

You should use the owner root:nginx and resist the urge to use nginx:nginx. nginx:nginx gives the web server write access to the documents, and there is usually no reason for the web server to have write access to static html files.

SELinux Contexts

Traditional Unix & Linux permissions are only half the recipe. You must also manage SELinux contexts or risk a 403 - the "Forbidden" error.

Continuing with the /var/www/html example, you have to set the SELinux context. To learn the context set by the Fedora maintainers, check /usr/share/nginx/html:

# ls -Z /usr/share/nginx/html
system_u:object_r:httpd_sys_content_t:s0 index.html
system_u:object_r:httpd_sys_content_t:s0 nginx-logo.png
...

So the final task is to change the context to system_u:object_r:httpd_sys_content_t:s0:

# restorecon -R /var/www/html
# ls -Z /var/www/html/
system_u:object_r:httpd_sys_content_t:s0 index.html
system_u:object_r:httpd_sys_content_t:s0 nginx-logo.png
...

If you are using an unusual directory for server storage, like /opt/www/html, then you may not be able to use restorecon to automatically fix the SELinux context. In this case, set the context using chcon and save the change using semanage to make the change permanent:

# chcon -R system_u:object_r:httpd_sys_content_t:s0 /opt/www
# semanage fcontext -a -t httpd_sys_content_t "/opt/www(/.*)?"
# restorecon -rv /opt/www

Or, since you know you want /opt/www/html to be like /var/www/html, you can perform the following:

# semanage fcontext --add --equal /var/www/html /opt/www/html
# restorecon -rv /opt/www/html

Also see Customizing the SELinux policy for the Apache HTTP server in a non-standard configuration in Red Hat's SELinux documentation.