Archive for the ‘Linux’ Category

How to automate LetsEncrypt

Friday, December 11th, 2015

A new service is born: Let’s Encrypt. It offers free SSL certificates that you can use for web servers, email servers or whatever service you want to secure with TLS. This blog post presents my strategy to automate certificate creation and renewal. Please, install Let’s Encrypt on your web server box before you start to follow the presented strategy.

The key to success is to have Let’s Encrypt running without any further interaction. I use webroot authentication – which allows me to leave the productive web service up and running while the certificates are being issued or renewed. Therefore, I created a file named “myserver.ini” in folder /etc/letsencrypt. This configuration file contains all details that are required for the certification process;

1
2
3
4
5
6
7
8
rsa-key-size = 4096
authenticator = webroot
webroot-path = /path/to/webroot/
server = https://acme-v01.api.letsencrypt.org/directory
renew-by-default = True
agree-tos
email = <my-email-address>
domains = domain1.com, domain2.com

The second component of my strategy is the central piece: a script called “renewCertificates.pl”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/usr/bin/perl
 
my $DOMAINS = {
    'myserver' => {
        'configFile' => '/etc/letsencrypt/myserver.ini',
        'leSubDir'   => 'domain1.com',
        'certDir'    => '/var/www/domain1.com/certs',
    },
};
 
my $domain;
my $renewed = 0;
chdir ('/usr/local/letsencrypt');
foreach $domain (keys(%{$DOMAINS})) {
    print "INFO  - $domain - START\n";
    my $cmd = '/usr/local/scripts/checkCertExpiry.sh 30 '.$DOMAINS->{$domain}->{'certDir'}.'/cert.pem >/dev/null';
    my $rc = system($cmd);
    if ($rc) {
        $cmd = './letsencrypt-auto certonly --config '.$DOMAINS->{$domain}->{'configFile'}.' --renew-by-default';
        $rc = system($cmd);
        if (!$rc) {
            $cmd = 'cp /etc/letsencrypt/live/'.$DOMAINS->{$domain}->{'leSubDir'}.'/* '.$DOMAINS->{$domain}->{'certDir'}.'/';
            $rc = system($cmd);
            if ($rc) {
                print "ERROR - $domain - Cannot deploy\n";
            } else {
                print "INFO  - $domain - Deployed\n";
                $renewed = 1;
            }
        } else {
            print "ERROR - $domain - Cannot generate certificates\n";
        }
    } else {
        print "INFO  - $domain - Certificate does not expire within 30 days\n";
    }
    print "INFO  - $domain - END");
}
 
if ($renewed) {
   system("/etc/init.d/apache2 reload");
}
 
exit 0;

This scripts allows renewal of multiple certificates by supporting multiple configurations. Lines 3-9 describe these configurations. leSubDir (line 6) is the sub directory that Let’s Encrypt creates in the certification process. It is the name of the first domain specified in the configuration file, here: domain1.com. certDir (line 7) is the target path where the certificates will be deployed to.

A second script supports this procedure by telling whether a certificate will expire within a certain number of days (see line 16 above):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash
 
# First parameter specifies if certificate expire in the next X days
DAYS=$1
 
target=$2
if [ ! -f "$target" ]; then
    echo "Certificate does not exist (RC=2)"
    exit 2;
fi
 
openssl x509 -checkend $(( 86400 * $DAYS )) -enddate -in "$target" >/dev/null 2>&1
expiry=$?
if [ $expiry -eq 0 ]; then
    echo "Certificate will not expire (RC=0)"
    exit 0
else
    echo "Certificate will expire (RC=1)"
    exit 1
fi

This script returns 0 when the given certificate will not expire, otherwise it returns a non-0 value. The Perl script above will renew certificates 30 days before expiration only.

The last piece is the Apache configuration to be used on these domains:

1
2
3
4
    SSLEngine on
    SSLCertificateFile /var/www/domain1.com/certs/cert.pem
    SSLCertificateKeyFile /var/www/domain1.com/certs/privkey.pem
    SSLCertificateChainFile /var/www/domain1.com/certs/fullchain.pem

I run the central Perl script above daily and do not need to worry about certificates anymore 🙂

The next blog post will explain how to configure the script and Apache when you want to use the same certificate on multiple domains that have individual web roots.

Nonblocking sockets and Perl’s Net::Daemon

Friday, June 19th, 2015

I was writing a Perl-based proxy for line-based SMTP protocol. The main reason doing this is because I receive unwanted e-mail bounces that are not filtered out by my SpamAssassin. The idea was to hook into the mail delivery chain and to collect e-mail addresses that I use. The proxy can later then filter out any bounce message that was not originated by myself.

I decided to use the Net::Daemon module which has a quite fancy interface. One just writes a single function which handles the client connection. As I didn’t want to learn every detail of SMTP protocol, I simply use non-blocking sockets. So whoever of the two parties wants to talk, it can do so and my proxy will just listen to the chat. The IO::Select documentation tells you to do this when you have multiple sockets to react on:

1
2
3
4
5
6
7
8
9
10
11
12
# Prepare selecting
$select = new IO::Select();
$select->add($socket1);
$select->add($socket2);
 
# Run until timed out / select socket
while (@CANREAD = $select->can_read(30)) {
    foreach $s (@CANREAD) {
        #... read the socket and do your stuff
    }
}
# Whenever there is a problem (like talk ended) the loop exits here

However, this code doesn’t work as expected. The can_read() function will not return an empty list when the sockets closed. It still returns any socket and the loop goes on forever. In fact, as we are in non-blocking mode, the script now eats up CPU time. 🙁

There are two solutions to it. The first is to check whether the given socket is still connected and then exit the loop:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Prepare selecting
$select = new IO::Select();
$select->add($socket1);
$select->add($socket2);
 
# Run until timed out / select socket
while (@CANREAD = $select->can_read(30)) {
    foreach $s (@CANREAD) {
        if (!$s->connected()) {
            return;
        }
        #... It's safe now to read the socket and do your stuff
    }
}

The second and more clean method is just to remove the closed socket from the IO::Select object:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Prepare selecting
$select = new IO::Select();
$select->add($socket1);
$select->add($socket2);
 
# Run until timed out / select socket
while (@CANREAD = $select->can_read(30)) {
    foreach $s (@CANREAD) {
        if (!$s->connected()) {
            $select->remove($s);
            next;
        }
        #... It's safe now to read the socket and do your stuff
    }
}

Then the selector runs empty and will exit the loop as well.

JavaMail: Sending mails fails

Thursday, April 26th, 2012

Ever stumbled across this?

javax.mail.SendFailedException: Sending failed;
   nested exception is:
      javax.mail.MessagingException: 501 5.0.0 HELO requires domain address

I wasn’t able for a long time to find the solution in the net although many people reported having this problem. The only hint you find is “There was an invalid entry in /etc/hosts”. But noone said exactly what the “invalid entry” was.

I myself found that there was no invalid entry but the configured hostname of the machine (issue “hostname” in a shell) cannot be resolved by DNS. The result is the given error message from the mail server.

What is happening? JavaMail resolves its own hostname by asking for the local hostname. The SMTP protocol requires the sending domain while handshaking. The server will try to resolve the domain by its DNS. If the hostname sent cannot be resolved then the server responds with “HELO requires domain address” as stated above.

I hope that this issue now becomes clearer to all of you.

PS: Solution is make sure your hostname can be resolved by DNS. Fix your hostname if it’s wrong or add the DNS entry.

Ubuntu 11.10 Upgrade Problems

Friday, April 13th, 2012

Grrr, that was nasty. I upgraded my Ubuntu to 11.10 after the 11.04 installation on my Lenovo laptop did not boot anymore with the latest kernel update. I usually install all updates that Ubuntu’s Update Manager proposes and never had problems so far. Until yesterday when the last kernel update was received.

The laptop did not boot anymore. It halted somewhere without any further notice. Switching to the console with Ctrl-Alt-F1 and checking the X11 log at /var/log/Xorg.0.log revealed that NVIDIA graphics driver could not be loaded anymore. Re-installing the driver did not fix the problem :(. Well, at least I could boot the old kernel and check systems out.

However, I wasn’t able to make the newest kernel working with NVIDIA’s kernel module. So I finally tried the distribution upgrade to 11.10. But again, the system stuck in the boot. Even worse, I had a new symptom:

Unable to connect to the system bus: Failed to connect to socket /var/run/dbus/system_bus_socket: Connection refused

An internet research turned up this excellent forum thread which told me that the distribution upgrade had failed to migrate two directories. Following the instructions of #24 – using mv command and setting chmod 1777 /run/lock did finally help me to repair the system.

So guys, if you observe the weird behaviour after upgrading a kernel on an NVIDIA based computer, check out:

  • The X11 log for messages about your kernel module
  • Wiki page http://wiki.ubuntuusers.de/Grafikkarten/NVIDIA/nvidia
  • Wiki page http://wiki.ubuntuusers.de/Grafikkarten/Nvidia
  • and of course, google your boot log error

 

 

Convinient GRUB multi-boot configuration

Sunday, June 19th, 2011

These two lines in /etc/default/grub let grub2 remember what system you booted last time and will automatically start this system when rebooting:

GRUB_DEFAULT=saved
GRUB_SAVEDEFAULT=true

You need to update grub2 afterwards to have the new configuration activated:

update-grub

PDF Printer with Linux

Thursday, October 1st, 2009

I use a PDF Printer on my professional Windows notebook. It enables me to create PDF documents from whatever application. So, how about Linux then. Thanks God, there is cups-pdf. A German tutorial can be found here. If you find a English HowTo, just post the link here.

Switch Off Caps-Lock

Friday, August 21st, 2009

I was always annoyed by CAPS-LOCK key on my Linux notebook. Thanks god, there is a solution:

xmodmap -e "remove lock = Caps_Lock"

will switch this damn thing off. 🙂

Extending filesystem on RHEL with LVM

Tuesday, January 6th, 2009

You need to extend a filesystem on a RedHat box? Check the filesystems with df -H. You might get something like

Filesystem             Size   Used  Avail Use% Mounted on
/dev/mapper/system-root
11G   8.0G   2.0G  81% /
/dev/cciss/c0d0p1      104M    18M    81M  19% /boot
tmpfs                  2.1G      0   2.1G   0% /dev/shm
/dev/mapper/system-tmp
4.2G   146M   3.9G   4% /tmp
/dev/mapper/system-var
4.2G   873M   3.1G  23% /var
/dev/mapper/system-mysqllv
11G   8.1G   1.8G  83% /var/lib/mysql
/dev/mapper/system-srvlv
47G    16G    29G  35% /srv

You need to increase the volume capacity first, e.g. for /srv mount:

lvextend -L +15G /dev/system/srvlv

where +15G tells the command to extend the volume by another 15GB.

Last step is to adjust the filesystem to that volume’s new size:

resize2fs /dev/mapper/system-srvlv

That’s it 🙂

Integrating SpamAssassin with qmail: Part 2

Wednesday, December 24th, 2008

This is a series of articles covering integration of SpamAssassin with qmail on a Linux box.

Part 1: Installing and Configuring SpamAssassin
Part 2: Marking email as spam

Part 2: Marking email as spam

Now, that we setup SpamAssassin to run as a continous process, we are able to change the qmail system to feed all emails into the server daemon. We need the root folder of qmail first. This is usually at /var/qmail. However, you better check with your installation first.

Create a file “qmail-queue.spamd” in subfolder bin that contains a single line:

/usr/bin/spamc -U /tmp/spamd_full.sock| /var/qmail/bin/qmail-queue.orig

Adapt the paths if necessary. Next step is to rename the existing qmail-queue program in subfolder bin. Name it “qmail-queue.orig”, as we have already used that pathname in our script. Make sure that all file permissions of qmail-queue.orig and qmail-queue.spamd match exactly the original qmail-queue binary.

Last step is to replace the existing qmail-queue binary by a link to our qmail-queue.spamd script. That’s it. All your emails do now pass the SpamAssassin daemon. You can check this by viewing all headers of emails passing your system. They should now contain additional SpamAssassin lines.

This is not the end of the story. We just marked email so far as spam or not. The will not get filtered out of the boxes, yet. This however is the topic of part 3 of this series.

Integrating SpamAssassin with qmail: Part 1

Sunday, November 23rd, 2008

This is a series of articles covering integration of SpamAssassin with qmail on a Linux box.

Part 1: Installing and Configuring SpamAssassin
Part 2: Marking email as spam

Part 1: Installing and Configuring SpamAssassin

There are quite a few numbers of HOWTOs at the internet about installing the software itself. So I won’t go very much into details but rather point you to some locations where you can find sufficient information.

You’ll find the latest software package at Apache’s SpamAssassin Homepage. Unpack the archive, preferrably at /usr/local/src. It will produce a directory Mail-SpamAssassin-XXXX. Change into that directory and read the INSTALL file to learn about special features when building the spam recognition tool. Usually you need to issue three commands:

perl Makefile.PL
make
make install

That’s it. Be aware that you might need to enhance your Perl distribution by additional modules from CPAN.

The last step to perform is to make a tool called spamd running continously on your box. We will first configure the daemon according to your Linux distribution. On latest SuSE editions this is done by a file /etc/sysconfig/spamd:

## Path:           Network/Mail/Spamassassin
## Description:    Arguments for the spam daemon
## Type:           string
## Default:        "-d -c -L"
## ServiceRestart: spamd
#
# The arguments passed to spamd.
# See spamd(1) man page.
# Default is "-d -c -L"
SPAMD_ARGS="-d -c -u spamd -g spamd --socketpath=/tmp/spamd_full.sock"

We introduced a user and group called “spamd” here. You might need to configure them first on your system.

Finally, you can add according startup commands in your /etc/rc.d directory to make spamd starting at system boot. Here is a script that I use.

Part 2 of this series will concentrate on the issue how to pass each mail into SpamAssassin.