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

Enforce Apache security and performance

Production Apache web servers need to be well configured for what regards security and performance. Here below a quick tips to make your servers more secure and performant.

First of all you need to verify if you are using prefork module:

apachectl -V | grep -i mpm

If prefork is enabled, you should see a line like this:

Server MPM:     prefork

If it is, I wrote a simple script to calculate the number of MaxClients your server can support:

Basically this number is calculated with this formula:


So, edit /etc/apache2/apache2.conf on Debian/Ubuntu and /etc/httpd/conf/httpd.conf on RedHat/CentOS and set the prefork section like this:

<IfModule prefork.c>
    StartServer 5
    MinSpareServers 5
    MaxSpareServers 10
    MaxClients 300            # value calculated
    MaxRequestPerChild 3000   # 3000 is a good number, avoid to leave it at 0

Set now some parameters that affects security and performances. Depending on your distribution they can be already set in the following files:


  • /etc/apache2/apache2.conf
  • /etc/apache2/conf.d/security


  • /etc/httpd/conf/httpd.conf
  • /etc/httpd/conf/extra/httpd-default.conf
ServerTokens Prod
ServerSignature Off
HostnameLookups Off
Timeout 45
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 15

Now test apache configuration and if all goes well, restart the web server:

apachectl configtest

/etc/init.d/httpd restart    # RedHat/CentOS
/etc/init.d/apache2 restart  # Debian/Ubuntu

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