Matteo Mattei

Hello, my name is Matteo Mattei and this is my personal website. I am computer engineer with a long experience in Linux system administration and web software development.

linkedin rss twitter google+ github facebook

Enable SSH authentication using RSA key-pair without password

If you have to manage multiple servers, if you want to enforce the security of your servers, if you want to run remote script using SSH in crontab, or simply if you don’t want to remember the SSH password everytime, this is the guide for you!

First of all you need to generate a RSA keypair in your PC/Mac:

ssh-keygen -t rsa -b 2048 -C "" -f ~/.ssh/id_rsa
  • -t is the type of algorithm to use (RSA)
  • -b is the length of the key to generate (2048 is sufficient)
  • -C is the comment/identification of the key (you can use your email address)
  • -f is the path of the private key to generate (the public will be stored in the same folder with .pub suffix)

When you are asked for a passphrase just press Enter to not input any passphrase. At the end a couple of keys will be stored in ~/.ssh folder with the correct permissions and they will be called respectively id_rsa (the private key) and (the public key).

In case you are copying the keys from somehow to your ~/.ssh folder make sure the permissions are correct:

-rw-------  1 matteo matteo  1679 Aug 15  2015 id_rsa
-rw-r--r--  1 matteo matteo   398 Aug 15  2015

Now from your PC/Mac copy the private key to the remote server:

ssh-copy-id remoteuser@remoteserver-ip

This time you will need to provide the password because the remote server is still not aware of your key. Even if the best approach is the this, the same operation could also be done manually using scp:

scp ~/.ssh/ remoteuser@remoteserver-ip:/tmp/
ssh remoteuser@remoteserver-ip
mkdir ~/.ssh
cat /tmp/ >> ~/.ssh/authorized_keys
rm /tmp/

Now try to connect to the remote server via SSH:

ssh remoteuser@remoteserver-ip

If all goes well, the password should not be asked and you can access to the server directly. But it is not finished… now we want to block the password authentication for all users and allow root login, so login to the server as root and change /etc/ssh/sshd_config in this way:

PermitRootLogin without-password
RSAAuthentication yes
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no

Restart ssh daemon (/etc/init.d/ssh restart) and from another shell try to connect again. You should be able to access to the server without enterning any password. I suggest to use another shell because if something went wrong you can always recover the issue using the first shell.

Remember to copy the public key in the authorized_keys file of every remote user that can accept remote connections via ssh.

Enable MySQL slow query and query not using indexs logs

Sometimes, expecially in production, is important to monitor how your database is performing and in general, when you see the websites are loading slow and/or there is high picks of CPU/RAM on MySQL, a good idea is to enable slow queries and queries not using indexes log. To do it, edit /etc/mysql/my.cnf on Debian (and derivates) or /etc/my.cnf on RedHat (and derivates) and add the following lines:

slow_query_log_file = /var/log/mysql/mysql-slow.log
slow_query_log = 1
long_query_time = 2

Before restarting MySQL server, create the log file and set the correct permission on it:

touch /var/log/mysql/mysql-slow.log
chown mysql.mysql /var/log/mysql/mysql-slow.log

Now you can restart MySQL server and check that the new log file (/var/log/mysql/mysql-slow.log) is correctly populated:

/etc/init.d/mysql restart

NOTE: I suggest to keep the slow query log enabled only on debugging because it consumes lot of resources and, depending on your application code, the log file might become huge in just few days.

HTTP/HTTPS GET and POST requests in Python3 including file upload with builtin modules

The following script performs GET and POST requests to [] using only builtin python 3 modules. There is also a class to support file encoding for upload.

Cross compile wget statically for ARM

The following script can be used to statically cross compile wget for ARM.


  • You need openssl and zlib already present in the current $ROOTPATH directory with related libraries and included respectively inside libs and include folders.
  • You need a glibc compiled with --enable-static-nss flag so that getaddrinfo and gethostbyname cannot complain at link time.

The resulting binary will be placed into the build folder.

Share internet connection to the the LAN, protect everything with a firewall and setup dhcp server on Linux.

I have a router with a public static ip address provided by the ISP and I need to share internet access to all pc in the LAN. To do it I need a server with two ethernet interfaces (eth0 and eth1) that will act as a firewall and dhcp server. That server will also be used as a web server to publish some contents in the LAN and in internet.

My configuration is this:

  • eth0 with public static IP address provided by the ISP.
  • eth1 with private static IP address assigned by me and connected to a switch.

Install shorewall:

apt-get install shorewall

Start configuration with two interface shorewall example:

cd /usr/share/doc/shorewall/examples/two-interfaces/
cp interfaces /etc/shorewall/
cp masq /etc/shorewall/
cp policy /etc/shorewall/
cp rules /etc/shorewall/
cp zones /etc/shorewall/
cp stoppedrules /etc/shorewall/

Now configure /etc/network/interfaces (I am using Debian jessie):

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
netmask yyy.yyy.yyy.yyy
gateway zzz.zzz.zzz.zzz

auto eth1
iface eth1 inet static


  • is the public IP address provided by the ISP
  • yyy.yyy.yyy.yyy is the netmask provided by the ISP
  • zzz.zzz.zzz.zzz is the gateway provided by the ISP

And /etc/resolv.conf:

# Google DNS

Now configure shorewall to act as firewall and share internet to all LAN devices.

File: /etc/shorewall/interfaces

net     eth0            dhcp,tcpflags,nosmurfs,routefilter,logmartians,sourceroute=0
loc     eth1            dhcp,tcpflags,nosmurfs,routefilter,logmartians

File: /etc/shorewall/zones

#ZONE   TYPE    OPTIONS                 IN                      OUT
#                                       OPTIONS                 OPTIONS
fw      firewall
net     ipv4
loc     ipv4

File: /etc/shorewall/policy

#SOURCE         DEST            POLICY          LOG LEVEL       LIMIT:BURST

$FW             net             ACCEPT
$FW             loc             ACCEPT
loc             net             ACCEPT
net             all             DROP            info
all             all             REJECT          info

File: /etc/shorewall/rules


#       Don't allow connection pickup from the net
Invalid(DROP)   net             all             tcp
#       Accept DNS connections from the firewall to the network
DNS(ACCEPT)     $FW             net
DNS(ACCEPT)     loc             $FW
#       Accept SSH connections from the local network for administration
SSH(ACCEPT)     loc             $FW
#       Allow Ping from the local network
Ping(ACCEPT)    loc             $FW

# Drop Ping from the "bad" net zone.. and prevent your log from being flooded..

Ping(DROP)      net             $FW

ACCEPT          $FW             loc             icmp
ACCEPT          $FW             net             icmp

# custom rules
SSH(ACCEPT)     net             $FW
Web(ACCEPT)     net             $FW
Web(ACCEPT)     loc             $FW

# DNAT rules (useful for natting a service on a device)
# this rule opens port 8080 from internet to port 80 of in TCP
#DNAT            net             loc:     tcp     8080

The above configuration allows SSH connections from local and from remote as well as Web access.

File: /etc/shorewall/masq

#                                                                                       GROUP           DEST
eth0                    eth1

File: /etc/shorewall/stoppedrules

#ACTION         SOURCE          DEST            PROTO   DEST            SOURCE
#                                                       PORT(S)         PORT(S)
ACCEPT          eth1            -
ACCEPT          -               eth1

Now edit /etc/shorewall/shorewall.conf and set:


In particular the last line is necessary to share internet to the LAN. Edit now /etc/default/shorewall and set:


Now start shorewall:

/etc/init.d/shorewall start

And try to configure a pc in the LAN with a static ip address, for example:


Yeah, the pc should be able to access internet! But we need to go a little bit ahead because given we don’t want to assign a static ip address to all pc (or devices) in the LAN. So we have to install a DHCP server.

apt-get install dnsmasq

Now backup the default configuration of dnsmasq and create a new /etc/dnsmasq.conf with something like this:


The first line specifies the interface where the DHCP server is running (eth1 for me1). The second line (dhcp-range) is the range of IP addresses that the DHCP server will provide with a lease of 12 hours. In this case from address to address All other lines are used to define devices with static IPs. The syntax is:


Dnsmasq beyond dhcp and DNS caching provides also another interesting feature… every entry you set in /etc/hosts of the server is automatically forwarded to all devices in the LAN. This means that if we want to set a simple name for accessing the webserver from the LAN it’s just a matter of editing /etc/hosts and add the server’s name:       localhost     myserver

This allows all devices in the LAN to access the server using myserver.

Now restart dnsmasq:

/etc/init.d/dnsmasq restart

To list all devices that have received a new IP address the file to look at is /var/lib/misc/dnsmasq.leases


Full web server setup with Debian 8 (Jessie)

Setup bash and update the system

cp /etc/skel/.bashrc /root/.bashrc
apt-get update
apt-get dist-upgrade

Configure hostname correctly

Make sure to have the following two lines (with the same format) at the top of your /etc/hosts file       localhost.localdomain localhost web1

Note: is the public IP address assigned to your server.

Install all needed packages

apt-get install php5 mysql-server mysql-client apache2 iptables phpmyadmin varnish shorewall vsftpd php5-cli php5-curl php5-dev php5-gd php5-imagick php5-imap php5-memcache php5-pspell php5-recode php5-sqlite php5-tidy php5-xcache php5-xmlrpc php-pear php-xml-rpc postfix apg ca-certificates heirloom-mailx


  • mysql root password: xxx
  • repeat mysql root password: xxx
  • web server to reconfigure automatically: apache2
  • configure database for phpmyadmin with dbconfig-common? Yes
  • Password of the database’s administrative user: xxx
  • Password for phpmyadmin: xxx
  • Password confirmation: xxx


  • Select Internet Site
  • System mail name: (insert here the FQDN, for example

Setup FTP

Stop VSFTP server:

/etc/init.d/vsftpd stop

Create backup configuration:

mv /etc/vsftpd.conf /etc/vsftpd.conf.backup

Add new configuration:

ftpd_banner=Welcome to my ftp server

Create an empty chroot_list file:

mkdir /etc/vsftpd
touch /etc/vsftpd/chroot_list

Install PAM module for virtual users:

apt-get install libpam-pwdfile

And configure it creating the file /etc/pam.d/vsftpd_local_and_virtual with this content:

# Standard behaviour for ftpd(8).
auth    required item=user sense=deny file=/etc/ftpusers onerr=succeed

# first try to authenticate local users
auth    sufficient

# if that failed, login with virtual user
auth    required  pwdfile /etc/vsftpd/passwd

# pam_pwdfile doesn't come with account, so we just permit on success
account required

Start VSFTP server:

/etc/init.d/vsftpd start

Setup Apache

Stop Apache web server:

/etc/init.d/apache2 stop

Backup Apache configuration:

cp /etc/apache2/apache2.conf /etc/apache2/apache2.conf.backup

Edit the following lines in /etc/apache2/apache2.conf

  • From Timeout 300 to Timeout 45
  • From KeepAliveTimeout 5 to KeepAliveTimeout 15

Edit /etc/apache2/mods-enabled/mpm_prefork.conf:

<IfModule mpm_prefork_module>
        StartServers             5
        MinSpareServers          5
        MaxSpareServers          10
        MaxRequestWorkers        150
        MaxConnectionsPerChild   10000

Edit /etc/apache2/ports.conf and change the port 80 with 8080 since we are going to use Varnish:

Listen 8080

Change the port (from 80 to 8080) also in the default virtual host /etc/apache2/sites-enabled/000-default.conf Now restart Apache:

/etc/init.d/apache2 restart

Setup Varnish

Stop Varnish daemon:

/etc/init.d/varnish stop

Open /etc/varnish/default.vcl and make sure the backend section is like this:

backend default {
    .host = "";
    .port = "8080";
    .connect_timeout = 600s;
    .first_byte_timeout = 600s;
    .between_bytes_timeout = 600s;

Now edit /etc/default/varnish and set the DAEMON_OPTS variable like this:

DAEMON_OPTS="-a :80 \
             -T localhost:6082 \
             -f /etc/varnish/default.vcl \
             -S /etc/varnish/secret \
             -s malloc,256m"

Now we have to make some changes also to systemd scripts (this step is mandatory for Debian Jessie!) since systemd does not consider /etc/default/varnish settings:

cp /lib/systemd/system/varnish.service /etc/systemd/system/

Edit /etc/systemd/system/varnish.service and change port 6081 with port 80:

Description=Varnish HTTP accelerator

ExecStartPre=/usr/sbin/varnishd -C -f /etc/varnish/default.vcl
ExecStart=/usr/sbin/varnishd -a :80 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,256m


Restart Varnish:

systemctl daemon-reload
systemctl restart varnish.service

Setup MySQL

Correct the MySQL configuration warning:

sed -i "{s/^key_buffer/key_buffer_size/g}" /etc/mysql/my.cnf

Enable MySQL slow query logging (often useful during slow page load debugging):

sed -i "{s/^#slow_query_log_file /slow_query_log_file /g}" /etc/mysql/my.cnf
sed -i "{s/^#slow_query_log /slow_query_log /g}" /etc/mysql/my.cnf
sed -i "{s/^#long_query_time /long_query_time /g}" /etc/mysql/my.cnf
sed -i "{s/^#log_queries_not_using_indexes/log_queries_not_using_indexes/g}" /etc/mysql/my.cnf

MySQL is now configured, so restart it:

/etc/init.d/mysql restart

Configure Shorewall firewall rules

Copy the default configuration for one interface:

cd /usr/share/doc/shorewall/examples/one-interface
cp interfaces /etc/shorewall/
cp policy /etc/shorewall/
cp rules /etc/shorewall/
cp zones /etc/shorewall/

Now open /etc/shorewall/policy file and change the line:

net             all             DROP            info

removing info directive given it fills the system logs:

net             all             DROP

Now open /etc/shorewall/rules and add the following rules at the bottom of the file:

HTTP/ACCEPT     net             $FW
SSH/ACCEPT      net             $FW
FTP/ACCEPT      net             $FW

# real apache since varnish listens on port 80
#ACCEPT         net             $FW             tcp             8080

NOTE: in case you want to allow ICMP (Ping) traffic from a specific remote hosts you need to add a rule similar to the following where is the remote IP address, before the Ping(DROP) rule:

Ping(ACCEPT)       $FW

Now edit /etc/default/shorewall and change startup=0 to startup=1 You are now ready to start the firewall:

/etc/init.d/shorewall start

Setup Postfix

Stop postfix server:

/etc/init.d/postfix stop

Edit /etc/mailname and set your server domain name, for example:

Then, in order to monitor mail traffic coming from PHP you need to edit /etc/php5/apache2/php.ini. Go to [mail function] section and set the following two options:

sendmail_path = /usr/local/bin/sendmail-wrapper
auto_prepend_file = /usr/local/bin/env.php

Now create the two files above in /usr/local/bin:


logger -p site=${HTTP_HOST}, client=${REMOTE_ADDR}, script=${SCRIPT_NAME}, pwd=${PWD}, uid=${UID}, user=$(whoami)
/usr/sbin/sendmail -t -i $*



Now make they both have executable flag:

chmod +x /usr/local/bin/sendmail-wrapper
chmod +x /usr/local/bin/env.php

Add also /usr/local/bin/ to the open_basedir php list in /etc/apache2/conf-enabled/phpmyadmin.conf

php_admin_value open_basedir /usr/share/phpmyadmin/:/etc/phpmyadmin/:/var/lib/phpmyadmin/:/usr/local/bin/

Restart Postfix:

/etc/init.d/postfix start

Prepare environment

Create all needed directories and files

mkdir /root/cron_scripts
mkdir -p /var/www/vhosts
mkdir -p /etc/vsftpd/users
touch /etc/vsftpd/passwd

Now download all tools to manage the server locally:

chmod 770 *.sh

Download also the tools that will be used with cron:

cd /root/cron_scripts
chmod 770 *.sh
  • Edit /root/ and change ADMIN_EMAIL variable with your email address.
  • Edit /root/ and change the variable MYSQL_ROOT_PASSWORD with your MySQL root password.
  • Edit /root/cron_scripts/ and change the variable DB_PASSWORD with your MySQL root password and MAIL_NOTIFICATION with your email address.
  • Edit /root/cron_scripts/ and change the variable MYSQL_ROOT_PASSWORD with your MySQL root password.

Configure CRON

Edit /etc/crontab and add the following lines at the bottom:

# mysql optimize tables
3  4  *  *  7   root    /root/

# mysql backup
32 4  *  *  *   root    /root/