Notes on how to configure HTTPS/SSL with Nginx

Without any introduction or discussion, here are the notes I made while learning how to get HTTPS working with Nginx. These are just for me, but if something helps you, cool.

Back to top

Summary

In the end this wasn’t hard, I just needed to find a couple of good resources. It doesn’t take long at all once you know what you’re doing.

Back to top

New Linode Server

  • set up a new server
  • install Ubuntu 16.04
  • turn on firewall
  • create non-root user
  • shut off root ssh access
  • point a domain name at the IP address
Back to top

Update Everything

sudo apt-get update && sudo apt-get upgrade
sudo apt-get upgrade nginx (or 'install')
Back to top

Ubuntu Firewall

  • https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-with-ufw-on-ubuntu-16-04

Initial:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw enable

Later:

sudo ufw allow 80
sudo ufw allow 443

Status:

sudo ufw status verbose

Other:

sudo ufw disable
sudo ufw app list  (output below)
    Available applications:
        Nginx Full
        Nginx HTTP
        Nginx HTTPS
        OpenSSH
sudo ufw allow 'Nginx HTTPS'
Back to top

Add a New User

Command:

sudo adduser username

add to sudo group:

sudo usermod -aG sudo username

or:

sudo adduser username sudo
  • note: sudo does not work, but i can su -
Back to top

Disabling Root Login

sudo vim /etc/ssh/sshd_config
PermitRootLogin no
sudo service sshd restart
Back to top

Limit Login Attempts

simple/naive:

PermitRootLogin no
LoginGraceTime 120
# allow only 1 login attempt per connection
MaxAuthTries 1

more info:

Back to top

Install Nginx

sudo apt-get update
sudo apt-get install nginx ssl-cert

Output:

The following additional packages will be installed:
  fontconfig-config fonts-dejavu-core libfontconfig1 libgd3 libjbig0 libjpeg-turbo8 libjpeg8 libtiff5
  libvpx3 libxpm4 libxslt1.1 nginx-common nginx-core
Suggested packages:
  libgd-tools fcgiwrap nginx-doc openssl-blacklist
The following NEW packages will be installed:
  fontconfig-config fonts-dejavu-core libfontconfig1 libgd3 libjbig0 libjpeg-turbo8 libjpeg8 libtiff5
  libvpx3 libxpm4 libxslt1.1 nginx nginx-common nginx-core ssl-cert
Back to top

Adjust Firewall

Use these commands, as needed:

sudo ufw allow 80
sudo ufw allow 443
sudo ufw allow 'Nginx HTTPS'
Back to top

Nginx Configuration

Conf file:

/etc/nginx/nginx.conf

Commands:

nginx -t
service nginx reload (stop, start)

Can also use these:

systemctl status nginx
sudo systemctl stop nginx
sudo systemctl start nginx

Nginx log files:

/var/log/nginx/access.log
/var/log/nginx/error.log

Basic config:

server {
    server_name  100.200.200.50;
    listen       80;
    root         /var/www/default;
    index        index.html;
}

More:

server {
    server_name  www.fptracker.com;
    rewrite ^(.*) http://fptracker.com$1 permanent;
}

server {
    server_name  fptracker.com;
    listen       80;
    location / {
        root /var/www/html;
    }
    access_log  /var/log/nginx/fptracker_access.log  main;
    error_log   /var/log/nginx/fptracker_error.log  error;
}
Back to top

NOT what I used: Let’s Encrypt on Ubuntu 16.04

  • Has some limitations, like certs are only good for 90 days
  • https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04
  • I didn't use this, I used the openssl commands shown below

“TLS/SSL works by using a combination of a public certificate and a private key. The SSL key is kept secret on the server. It is used to encrypt content sent to clients. The SSL certificate is publicly shared with anyone requesting the content. It can be used to decrypt the content signed by the associated SSL key.”

Back to top

(1) Create a cert (openssl)

  • Common Name (e.g. server FQDN or YOUR name) is most important

$ openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/ssl/private/aja-nginx-selfsigned.key -out /etc/ssl/certs/aja-nginx-selfsigned.crt

Generating a 2048 bit RSA private key
...................................................+++
writing new private key to '/etc/ssl/private/nginx-selfsigned.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:Alaska
Locality Name (eg, city) []:Talkeetna
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Valley Programming
Organizational Unit Name (eg, section) []:Home Office
Common Name (e.g. server FQDN or YOUR name) []: fptracker.com
Email Address []:joe@example.com
Back to top

(2) Create a strong Diffie-Hellman group

  • create a strong Diffie-Hellman group, which is used in negotiating Perfect Forward Secrecy with clients
$ sudo openssl dhparam -out /etc/ssl/certs/aja-dhparam.pem 2048

"this is going to take a long time ..."
  • when it's done you will have a strong DH group at /etc/ssl/certs/aja-dhparam.pem that we can use in our configuration
  • took less than a minute on the new test server
Back to top

(3) Configure Nginx to Use SSL

create a new Nginx configuration snippet in the /etc/nginx/snippets directory:

sudo vi /etc/nginx/snippets/aja-self-signed.conf

    ssl_certificate /etc/ssl/certs/aja-nginx-selfsigned.crt;
    ssl_certificate_key /etc/ssl/private/aja-nginx-selfsigned.key;

Set Nginx up with a strong SSL cipher suite and enable some advanced features that will help keep our server secure. The parameters we will set can be reused in future Nginx configurations, so we will give the file a generic name:

sudo nano /etc/nginx/snippets/aja-ssl-params.conf
  • add our preferred DNS resolver for upstream requests
  • set the ssl_dhparam setting to point to the Diffie-Hellman file we generated earlier
    // sudo nano /etc/nginx/snippets/aja-ssl-params.confssl-params.conf
    # from https://cipherli.st/
    # and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
    ssl_ecdh_curve secp384r1;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    # Disable preloading HSTS for now.  You can use the commented out header line that includes
    # the "preload" directive if you understand the implications.
    #add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
    add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;

    ssl_dhparam /etc/ssl/certs/aja-dhparam.pem;
Back to top

Adjust the Nginx Configuration to Use SSL

(NOT NEEDED FOR ME) back up our current server block file:

sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.bak
sudo vi /etc/nginx/sites-available/default
Back to top

(Alternative Configuration) Allow Both HTTP and HTTPS Traffic

  • allow both encrypted and unencrypted content
  • generally not recommended if it can be avoided, but in some situations it may be necessary
  • just compress the two separate server blocks into one block and remove the redirect
  • TODO: get rid of the "default" file in sites-enabled. i think the default_server config from there is colliding with me
  • note that default is a symlink (default -> /etc/nginx/sites-available/default)
server {
    #listen 80 default_server;
    #listen [::]:80 default_server;
    #listen 443 ssl http2 default_server;
    #listen [::]:443 ssl http2 default_server;

    # these work without "default_server"
    listen 80;
    listen [::]:80;
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name server_domain_or_IP;
    include snippets/aja-self-signed.conf;
    include snippets/aja-ssl-params.conf;

`nginx -t` output is normal:

nginx: [warn] "ssl_stapling" ignored, issuer certificate not found
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Back to top

Adjust the Firewall

sudo ufw allow 'Nginx Full'
sudo ufw status
Back to top

Enable the Changes in Nginx

$ sudo nginx -t
$ service nginx restart
Back to top

Test in Browser

kinda-sorta expected errors:

- "your connection is not secure"
- The certificate is not trusted because it is self-signed. 
~ (GONE THE SECOND TIME) The certificate is not valid for the name fptracker.com.
Back to top

Nginx "default_server"

  • The default_server parameter has been available since version 0.8.21.
  • In this configuration nginx tests only the request’s header field “Host” to determine which server the request should be routed to. If its value does not match any server name, or the request does not contain this header field at all, then nginx will route the request to the default server for this port. In the configuration above, the default server is the first one — which is nginx’s standard default behaviour. It can also be set explicitly which server should be default, with the default_server parameter in the listen directive:

    server { listen 80 defaultserver; servername example.net www.example.net; ... }

Back to top

Can change to a permanent redirect (301)

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name server_domain_or_IP;
    return 301 https://$server_name$request_uri;
}
Back to top

More Security: Preventing Information Disclosure

  • https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-on-ubuntu-14-04#step-2-%E2%80%94-preventing-information-disclosure
  • /etc/nginx/nginx.conf:
http {
    server_tokens off;  <-- ADD THIS (show only 'nginx', no version number)
Back to top

More Security: Fail2Ban

  • https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04
Back to top

Restricting Access by IP Address

server {
...
    location /wp-admin/ {
        allow 192.168.1.1/24;
        allow 10.0.0.1/24;
        deny  all;
    }
...
Back to top

See also

Back to top

Add new comment

The content of this field is kept private and will not be shown publicly.

Anonymous format

  • Allowed HTML tags: <em> <strong> <cite> <code> <ul type> <ol start type> <li> <pre>
  • Lines and paragraphs break automatically.
By submitting this form, you accept the Mollom privacy policy.