One jail to contain them all and with automatic certificate renewal. This setup is tied to Loopia as a DNS provider, but you may be able to adjust it to whatever floats your boat :D

FIX naxi rules & bad bot blocker, fastcgi.conf, ssl dhparams

Make sure to adjust the IP adress to suit your network schema.

fastcgi.conf

fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name;

Create Jail

iocage create -n "www" -r 12.2-RELEASE ip4_addr="vnet0|10.0.0.25/24" defaultrouter="10.0.0.1" vnet="on" allow_raw_sockets="1" boot="on" 

Install the packages

iocage exec www pkg install -y python37 py37-certbot py37-pip openssl nano nginx-naxsi wget git
iocage exec www pip install certbot-loopia

ADD Credentials from an API generated user from your dns supplier, this instance loopia.
Source for certbot-loopia https://github.com/runfalk/certbot-loopia

For Loopia API user, login to account, on the control panel you will find API users, add these credentials for that API user.

  • addSubdomain
  • addZoneRecord
  • getZoneRecords
  • removeSubdomain
  • removeZoneRecord

Then we create the credentials file and paste the content below.

iocage exec www nano /root/credentials.ini
certbot_loopia:auth_user = user@loopiaapi
certbot_loopia:auth_password = passwordgoeshere

Adjust the credentials and the save with CTRL+X then Y

Make the file inaccessible to outside users, just in case.

iocage exec www chmod 600 /root/credentials.ini

You may have to generate some acme fields on the DNS provider, but unsure if it is needed and will be notified by the first tutorial user if it is :P

Generate ssl certificate

Wildcard generation is just as well to do, sooner or later you may have multiple domain names and multiple subdomains.
So a wildcard generation is preffered.

This is an example, please modify to your preference!

iocage exec www certbot certonly --authenticator certbot-loopia:auth --certbot-loopia:auth-credentials /root/credentials.ini --server https://acme-v02.api.letsencrypt.org/directory -d "*.domainname.se" -d "*.someotherdomain.nu"

You can add how many (-d "*.domain.com") you may want.

Webroot

Where all webfiles/sites will reside, even if you will mostly use a reverse proxy or so, we might just aswell set one up. I do prefer to make another dataset where we can have all those files so they will not reside inside the jail!

Create a dataset in TrueNAS.

Then we will set it up for the Jail.

iocage exec www mkdir -p /mnt/wwwroot
iocage fstab -a www /mnt/Jailer/www /mnt/wwwroot nullfs rw 0 0

PHP is something we will always have a need for, so let's set it up also.

PHP

iocage exec www pkg install -y php74-bz2 php74-ctype php74-curl php74-dom php74-exif php74-fileinfo php74-filter php74-ftp php74-gd php74-gmp php74-iconv php74-imap php74-intl php74-json php74-ldap php74-mbstring php74-mysqli php74-opcache php74-openssl php74-pcntl php74-pdo php74-pdo_mysql php74-pdo_sqlite php74-phar php74-posix php74-session php74-simplexml php74-sqlite3 php74-tokenizer php74-xml php74-xmlreader php74-xmlwriter php74-xsl php74-zip php74-zlib

We also need to setup the standard php ini file.

iocage exec www cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini

PHP configuration

iocage exec www nano /usr/local/etc/php-fpm.d/www.conf

Find the row with listen = 127.0.0.1:9000 and replace it with listen = /var/run/php-fpm.sock

Uncomment the following line:
listen.owner = www
listen.group = www
listen.mode = 0660 CTRL+X then Y

Quick'n'easy php settings file

iocage exec www nano /usr/local/etc/php/99-custom.ini  

Paste the content below.

display_errors=Off
safe_mode=Off
safe_mode_exec_dir=
safe_mode_allowed_env_vars=PHP_
expose_php=Off
log_errors=On
error_log=/var/log/nginx/php.scripts.log
register_globals=Off
cgi.force_redirect=0
file_uploads=On
allow_url_fopen=Off
sql.safe_mode=Off
disable_functions=show_source, system, shell_exec, passthru, proc_open, proc_nice, exec
max_execution_time=60
memory_limit=60M
upload_max_filesize=2M
post_max_size=2M
cgi.fix_pathinfo=0
sendmail_path=/usr/sbin/sendmail -f webmaster@cyberciti.biz -t

This file can later be used to do quick modifications for the most used parameters.

We need to have php activated, lets add

iocage exec www sysrc php_fpm_enable="YES"

Lets restart the php service.

iocage exec www service php-fpm restart

So we are now going to setup nginx.
The beauty with nginx is the possibilites! Also a sort of downside too, when it comes to configuration.
Configuration wise it can look almost like anything, one installer nerd to another, everyone does it different.
Mine is based on several different tutorials and concluded in some lazy mans fasion. But it works and it is easy.

So, lets get to it then!

In nginx.conf i change some stuff.

iocage exec www cp /usr/local/etc/nginx/nginx.conf /usr/local/etc/nginx/nginx.original.conf
iocage exec www nano /usr/local/etc/nginx/nginx.conf

In this file we add and remove some info. At the top we have user nobody commented, uncomment and set iser to user www

user www;

I like for it to have a run location, lets add near the similar line like this.

pid /var/run/nginx.pid;

After that line lets add the NAXSI module

load_module /usr/local/libexec/nginx/ngx_http_naxsi_module.so;

Then in the http block add

    ##
    # Nginx Bad Bot Blocker
    ##
    include nginx-badbot-blocker/blacklist.conf;
    include nginx-badbot-blocker/blockips.conf;

I like logs, so enable them, uncomment or add these lines in http block.

    ##
    # Logging Settings
    ##
    log_format compression '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" "$gzip_ratio"'; 
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

SSL, were going to be (ab)using it! Also in the http block.

    ##
    # SSL Settings
    ##
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;

Now the boring part, remove the complete server {} block and replace it with this.

    ##
    # Virtual Host Configs
    ##
    include /usr/local/etc/nginx/naxsi_core.rules;
    include /usr/local/etc/nginx/conf.d/*.conf;
    include /usr/local/etc/nginx/sites-enabled/*;

We are going to use this instead, having a DEFAULT site/configuration and all other future subdomain configs in sites-available. We then symlink the ones we want active into sites-enabled
NAXSI rules and also any configuration files we would like to add in conf.d folder.

Setting up Bad Bot blocker

iocage exec www git -C /usr/local/etc/nginx clone https://github.com/mariusv/nginx-badbot-blocker.git

We included this file earlier, it is a list of commonly known bad addresses, so nginx will automatically just block them.

Setting up the default server.

iocage exec www mkdir /usr/local/etc/nginx/sites-available
iocage exec www mkdir /usr/local/etc/nginx/sites-enabled
iocage exec www mkdir /usr/local/etc/nginx/conf.d
iocage exec www mkdir /usr/local/etc/nginx/ssl
iocage exec www nano /usr/local/etc/nginx/sites-available/default

This is the default server config file. It catches the request for all other domains not set in other config files and also redirects immediately to https protocol.

server {
    listen 80 default_server;
    server_name DOMAINNAME.eu;
    return 301 https://DOMAINNAME.eu$request_uri;
}

server {
    server_name DOMAINNAME.eu;

    # Ensure these lines point to your SSL certificate and key
    ssl_certificate /usr/local/etc/letsencrypt/live/SET THIS TO THE CORRECT PATH/fullchain.pem;
    ssl_certificate_key /usr/local/etc/letsencrypt/live/SET THIS TO THE CORRECT PATH/privkey.pem;
    # Ensure this line points to your dhparams file
    ssl_dhparam /usr/local/etc/nginx/ssl/dhparams.pem;

    # These shouldn't need to be changed
    listen 443 ssl default_server;
    add_header Strict-Transport-Security "max-age=31536000; ";
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;

    root /mnt/wwwroot/DATASET_domainname; #example /mnt/wwwroot/domain.se
        index index.php index.html index.htm;
    client_max_body_size 5m;
    error_page   500 502 503 504 401 403 404 405 /50x.html;
    #This is where the blocked requests are going
    location = /50x.html {
    return 418; #I'm a teapot \o/
    }

    # This order might seem weird - this is attempted to match last if rules below fail.
    # http://wiki.nginx.org/HttpCoreModule
    location / {
        #Enable naxsi
        SecRulesEnabled;
        #Enable learning mode
        LearningMode;
        #Define where blocked requests go
        DeniedUrl "/50x.html"; 
        include /usr/local/etc/nginx/naxsi.rules;
        try_files $uri $uri/ /index.php?$query_string;
    }
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
        fastcgi_pass unix:/var/run/php-fpm.sock;
        fastcgi_index index.php;
        include fastcgi.conf;
    }
}

Finalize NAXSI

iocage exec www wget -P /usr/local/etc/nginx/ https://raw.githubusercontent.com/nbs-system/naxsi/master/naxsi_config/naxsi_core.rules
iocage exec www nano /usr/local/etc/nginx/naxsi.rules

Paste this content for some basic firewall rules.

SecRulesEnabled;
DeniedUrl "/error.html";

## Check for all the rules
CheckRule "$SQL >= 8" BLOCK;
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 4" BLOCK;
CheckRule "$EVADE >= 4" BLOCK;
CheckRule "$XSS >= 8" BLOCK;

We gotta have an error page for all the bad stuff coming at us. Modify the path to refelct your own.

iocage exec www nano /mnt/wwwroot/DATASET_domainname/50x.html
<html>
  <head>
    <title>Blocked By NAXSI</title>
  </head>
  <body>
    <div style="text-align: center">
      <h1>Malicious Request</h1>
      <hr>
      <p>This Request Has Been Blocked By NAXSI.</p>
    </div>
  </body>
</html>

Generate dhparams file

We need to generate a Diffie-Hellman key.
The regular command does not work so we need to tweak it a little so it will work, notably the -out parameter which exec from iocage interprets the u in -out as a paramter. (Source)

iocage exec www -- openssl dhparam -out /usr/local/etc/nginx/ssl/dhparams.pem 4096

Enable the default site/config

We gotta put a symlink for the available sites to enabled. This has to be done for each and every site/virtual server you create.

iocage exec www ln -s /usr/local/etc/nginx/sites-available/CONFIGFILE /usr/local/etc/nginx/sites-enabled/

Fixing the last things

Change the system user to own everything in the wwwroot folder.

iocage exec www chown -R www:www /mnt/wwwroot

Lets enable the services.

iocage exec www sysrc nginx_enable="YES"

Now we have to go into the console for the cron job.
Cronjob will ensure that we always have a certificate that is not expired, so it will automagically update everything and restart/reload nginx and serve the fresh certificate, set'n'forgett!

iocage console www
setenv EDITOR nano
crontab -e

Add this line

0 0,12 * * * /usr/local/bin/python -c 'import random; import time; time.sleep(random.random() * 3600)' && /usr/local/bin/certbot renew --quiet --deploy-hook "/usr/sbin/service nginx reload"

then we exit

exit
iocage restart www

DONE with setup!

Now you can configure and customize ALOT with this, we are merely just touching a basic setup.

For more neat functions and also references, i need to redirect you to these awesome sources.

Resources:

https://github.com/nbs-system/naxsi

Sources:

https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-naxsi-on-ubuntu-16-04

Will update qwith mysql at a later date!