Security

This is a brief guide to securing your web/mail server, with a focus on FreeBSD. Some of this is simply links to other blogs, and the rest is my own setup.

HTTP(S)

The first thing you should do is get a SSL certificate (it’s less than $10 per year). I bought Comodo PositiveSSL from Namecheap, so this guide will assume you did the same, although it will work without much difference with any SSL certificate.

SSL (TLS) with Nginx

Keys

Your SSL key and certificate should be names something like mtbentley.us.key and mtbentley.us.crt, and go in /usr/local/etc/nginx/keys/. This directory should only be readable by root, as nginx will read the keys before dropping privileges. The other file is ssl-bundle.crt. This is simply the combination of your website’s certificate (mtbentley.us.crt), the intermediate certificates, and finally the root certificate, in that order from the beginning of the file to the end.

Nginx config

FreeBSD’s Nginx config is in /usr/local/etc/nginx/. My config is based on my previous Debian system.

Here in my nginx.conf, commented as necessary:

user www; ### Make sure the user 'www' exists ### 
worker_processes auto;
events {
        worker_connections 768;
}

http {
        ### Cache. This assumes your content won't change too often.     ### 
        ### /var/nginx/cache should exist, and should be writable by www ### 
        proxy_cache_path /var/nginx/cache keys_zone=one:10m
                loader_threshold=300 loader_files=200
                max_size=200m;
        ### Make ssl a bit faster ### 
        ssl_session_cache   shared:SSL:10m;
        ssl_session_timeout 10m;
        
        ## 
        # Basic Settings
        ## 
        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;
        include /usr/local/etc/nginx/mime.types;
        default_type application/octet-stream;
        
        ## 
        # Logging Settings
        ## 
        ### /var/log/nginx should be writable by www ### 
        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;
        
        ## 
        # Gzip Settings
        ## 
        gzip on;
        gzip_disable "msie6";
        gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

        ## 
        # Virtual Host Configs
        ## 
        ### Includes. Extra conf in conf.d and sites in sites-enabled. ### 
        include /usr/local/etc/nginx/conf.d/*.conf;
        include /usr/local/etc/nginx/sites-enabled/*;
}

I have two sites enables: default, and default-ssl. default simply 302 redirects to the https site.

sites-enabled/default:

server {
    listen 80;
    server_name mtbentley.us; ### Replace with your domain name ### 

    rewrite ^ https://$server_name$request_uri? permanent;
}

default-ssl is where most of the magic takes place.
sites-enabled/default-ssl:

server {
    ### SSL and SPDY.  More on this later ### 
    listen              443 ssl spdy; 
    server_name         mtbentley.us; ### Again, replace w/ your domain ### 
    
    ### STS. Tells the browser to require all future connections to ### 
    ### this site to be over HTTPS                                  ### 
    add_header Strict-Transport-Security "max-age=31536000";
    
    ### Public key pinning. More on this later ### 
    add_header Public-Key-Pins 'pin-sha256="3OoyaaPUGXSUVoyFRpnE9K/LfG7UVt2g0cz9sEWE5zA="; max-age=15768000';
    
    ### The location of the ssl certificate and key. ### 
    ### Change as necessary for your key names.      ### 
    ssl_certificate     keys/ssl-bundle.crt;
    ssl_certificate_key keys/mtbentley.us.key;
    
    ### Don't use old protocols (SSLv3).                ### 
    ### This breaks some compatibility with Windows XP. ### 
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    
    ### Only use good ciphers.  Also breaks some XP support ### 
    ssl_ciphers         'AES128+EECDH:AES128+EDH';
    ssl_prefer_server_ciphers on;
    
    ### Prevent putting your site in an iframe ### 
    add_header X-Frame-Options "SAMEORIGIN";
    
    ### Proxy headers, for the server you are proxying to ### 
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    
    keepalive_timeout   70;
    
    ### Allow uploads up to 1G. You may not want it this large. ### 
    client_max_body_size 1G;
    
    ### Enable cache #### 
    proxy_cache one;
    
    ### Everything to /cv comes from /var/www                      ### 
    ### If you run a static site, this should be / rather that /cv ### 
    ### /var/www is the location of the content, and should be     ### 
    ### readable by the user www                                   ### 
    location /cv {
        root /var/www/;
    }
    
    ### For my website, I reverse-proxy to another server, running ### 
    ### on 10.7.0.1. Caching is enabled for this server.           ### 
    location / {
        proxy_cache_valid any   10m;
        proxy_cache_bypass $cookie_nocache $arg_nocache$arg_comment;
        proxy_pass http://10.7.0.1:2368;
    }
}

HSTS

HTTP Strict Transport Security, or HSTS, tells the browser to only allow connections to your site over HTTPS. This might pose a problem if you need to switch away from HTTPS at some point in the future, but it can prevent MITM protocol downgrade attacks.

HPKP

More info on HPKP (Public Key Pinning) here. You should think twice before doing this, because your website can become un-reachable if you lose or have to revoke your SSL private key.

SPDY

SPDY is what will eventually become HTTP/2. It’s a bit faster than HTTP/1.1, but requires you to specifically enable it when compiling. The easiest way to do this with FreeBSD is to compile Nginx from ports, selecting SPDY when configuring. How to do this:
#portsnap fetch extract to get the ports tree.
#cd /usr/ports/www/nginx
#make rmconfig (if you have compiled nginx previously)
#make install clean
When the configure menu comes up, be sure to select ‘SPDY’, along with any modules you may want.

Now just make sure you enable nginx by adding nginx_enable="YES" to /etc/rc.conf, and run service nginx start to start it up.