Getting a SSL certificate from Let’s Encrypt

Using Certbot from the CLI.

Installing certbot

$ sudo apt-get install software-properties-common
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install certbot

Obtaining a certificate

Starting certbot is next:

certbot certonly --webroot -w /var/www/ -d

The website tells me, that my server architecture (Ubuntu 17.04) does not provide automated installation. It worked after some configuration changes for nginx (the challenge is written into a hidden directory within the webroot) in /etc/nginx/global/common.conf:

location ^~ /.well-known/acme-challenge/ {
    default_type "text/plain";
    root /var/www/;

location = /.well-known/acme-challenge/ {
    return 404;

It was a good idea to create a simple textfile within this directory and trying to access it via the browser.

Configuring ngnix to use the certificate

file /etc/nginx/snippets/

ssl_certificate /etc/letsencrypt/live/;
ssl_certificate_key /etc/letsencrypt/live/;
openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

File /etc/nginx/snippets/ssl-params.conf:

# from
# and

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver valid=300s;
resolver_timeout 5s;
# disable HSTS header for now
#add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

ssl_dhparam /etc/ssl/certs/dhparam.pem;



There were too many attacks against the sshd (thousands on a single day), so I decided to install fail2ban. Installation is a simple apt-get install fail2ban. Next, a copy of the file /etc/fail2ban/jail.conf with the name jail.local is created. A possible configuration could be:

before = paths-debian.conf

ignoreip = # more networks if needed
bantime  = 86400
findtime  = 3600
maxretry = 3
backend = auto
usedns = warn
logencoding = auto
enabled = false

enable  = true
port    = ssh
filter  = sshd
logpath = /var/log/auth.log
backend = %(sshd_backend)s

This configurations bans an attacking ip address, if there are more than 3 failed login requests within an hour (findtime = 3600). The attacker is banned for 24 hours (bantime = 86400).

Continue reading “fail2ban”

Creating a firewall (iptables)

Make sure that iptables are installed (otherwise call apt-get install iptables). A very basic rule set that allows http, https, and ssh (via default port 22) access:


# Define default policies

# Allows all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d -j REJECT

# Accepts all established inbound connections
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Drop invalid packets
-A INPUT -m conntrack --ctstate INVALID -j DROP

# Allows HTTP and HTTPS connections from anywhere
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

# Allows SSH connections 
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT

# Allow DNS lookups
-A INPUT -p udp --sport 53 -j ACCEPT
-A INPUT -p tcp --sport 53 -j ACCEPT

# Allow NTP
-A INPUT -p udp --sport 123 -j ACCEPT

# Allow ping
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT

# log iptables denied calls (access via 'dmesg' command)
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7


Installing these rules – according to

iptables-restore < /etc/iptables.test.rules
iptables -L # Are these my rules?
iptables-save > /etc/iptables.up.rules

Activating iptable rules at boot time requires a file /etc/network/if-pre-up.d/iptables (as a shell script, it requires x permissions):

/sbin/iptables-restore < /etc/iptables.up.rules

Nowadays, the same is needed for IPv6 with some minor changes because ICMP plays a far more important role in this version:



# -A INPUT -m rt --rt-type 0 --rt-segsleft 0 -j DROP
# -A FORWARD -m rt --rt-type 0 --rt-segsleft 0 -j DROP
# -A OUTPUT -m rt --rt-type 0 --rt-segsleft 0 -j DROP


-A INPUT -p ipv6-icmp -j ACCEPT

-A INPUT -i lo -j ACCEPT

-A INPUT -m state --state NEW -m udp -p udp --dport 546 -d fe80::/64 -j ACCEPT

-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT

# -A INPUT -j REJECT --reject-with icmp6-port-unreachable
# -A FORWARD -j REJECT --reject-with icmp6-port-unreachable


Enabling these rules goes the same way as with IPv4 with the sole exception that ip6tables, iptables-restore and ip6tables-save must be called.

A pair of keys for ssh

ssh-keygengenerates the key pair (private key keyname and public key The easiest but somewhat more dangerous way is to use passphrase-less keys. Keys may be hardened against brute force attacks by increasing the number of rounds (-a 128) and by making the keys longer (-t rsa -b 4096). Don’t forget to add a comment -C "comment" to the public key which makes it easier to be recognized:

ssh-keygen -a 128 -t rsa -b 4096 -C "comment" -f "keyname"

The private key is needed on any host used as a source for logging in. Any target system needs a .ssh subdirectory in the home of the user allowed to login remotely with rwx permissions for the owner (chmod 700). A file called authorized_keys is needed which holds the public keys of all remote hosts from where a login happens (rw permissions for owner (chmod 600) and make sure that the owner actually owns this file). The public key can be appended by using cator it can be copied from a remote machine using ssh-copy-id -i @. ssh-copy-id works with localhost in case the keys are generated on the target machine.