Stunnel Setup


This document describes how I use Stunnel on the Arda Network. Stunnel allows third-party programs to communicate across a network through a secure channel (using SSL) without requiring the programs to incorporate SSL code themselves. It is a way to secure inherently insecure programs against packet sniffing eavesdroppers.


You will find an overview, including a very nice diagram, of the Arda Network here.

I have Stunnel running on Callisto and Io. In both cases, I’m using version 4.15. Both machines are running versions of FreeBSD and I installed Stunnel from the ports tree using the standard ‘make’, ‘make install’ procedure.

The Stunnel configuration files I describe reference a machine called Mail. This is an alias for Callisto that I’ve set up in DNS. See my DNS & DHCP Setup Doc for more information.

Configuration Files


Here is the configuration file of the stunnel instance running on Callisto. It lives in /usr/local/etc/stunnel/etc.


; Certificate/key is needed in server mode and optional in client mode
cert = /usr/local/share/certs/stunnel-mailkeycert.pem
key = /usr/local/share/certs/stunnel-mailkeycert.pem

; Some security enhancements for UNIX systems - comment them out on Win32
chroot = /usr/local/etc/stunnel/
setuid = stunnel
setgid = stunnel
; PID is created inside chroot jail
pid = /var/run/

; Some performance tunings
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1
;compression = rle

; Workaround for Eudora bug

; Authentication stuff
;verify = 2
; Don't forget to c_rehash CApath
; CApath is located inside chroot jail
;CApath = /certs
; It's often easier to use CAfile
CAfile = /usr/local/share/certs/cacerts.pem
; Don't forget to c_rehash CRLpath
; CRLpath is located inside chroot jail
;CRLpath = /crls
; Alternatively you can use CRLfile
;CRLfile = /usr/local/etc/stunnel/crls.pem

; Some debugging stuff useful for troubleshooting
;debug = 7
;output = stunnel.log

; Use it for client mode
;client = yes

; Service-level configuration

accept  = mail:106
connect = localhost:106
verify = 3

accept = mail:465
connect = localhost:25

On Callisto, Stunnel runs in daemon mode. When run in daemon mode, Stunnel requires a server certificate which is specified by the cert parameter. If a client is configured to ask for a server certificate, this is the certificate Stunnel will present to it.

The CAfile parameter specifies the file where client certificates and Certificate Authority root certificates are located. If Stunnel is configured to ask for a client certificate, clients must present a certificate when connecting. Stunnel will then check the certificate against the certificate chain located in CAfile. If Stunnel cannot verify the client certificate, it will refuse the connection. See the Certificates section for more information on the certificates I use with Stunnel.

Stunnel runs with reduced privileges under the user and group ‘stunnel’ in a chroot jail. Since Stunnel is accepting connections from remote locations, I thought this only prudent.

I used to need two instances of Stunnel. Prior to version 4.15, the verify parameter could only be set as a global option in the configuration file. Since the two services I run require different verify levels, I needed to run two Stunnel instances. With version 4.15, I’m able to set verify on a per service basis allowing me to define both services in the same configuration file. You will notice in the configuration file that verify is set to 3 for the pop3pw service. The smtp service does no verification of peer certificates.

Notice that I’ve used a hostname in the accept parameter in both configuration files. An IP address would also work here. I’m using the alias hostname ‘mail’ in my configuration files but I could have used ‘callisto’ if I had wished. The same applies to the connect parameter in Io’s configuration file.

One tricky bit I found when setting up the chroot jail is that the configuration file is not consistent in its use of pathnames. The pid parameter uses a path relative to that specified by the chroot parameter. However, the CAfile, cert, and key parameters require absolute paths. It took some playing with the configuration file before I realized this.


On Io, Stunnel’s configuration file is also located in /usr/local/etc/stunnel/etc.


; Certificate/key is needed in server mode and optional in client mode
cert = /etc/ssl/certs/io-keycert.pem
;key = /etc/ssl/certs/io-keycert.pem

; Some security enhancements for UNIX systems - comment them out on Win32
chroot = /usr/local/etc/stunnel/
setuid = stunnel
setgid = stunnel
; PID is created inside chroot jail
pid = /var/run/

; Some performance tunings
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1
;compression = rle

; Workaround for Eudora bug

; Authentication stuff
verify = 2
; Don't forget to c_rehash CApath;  CApath is located inside chroot jail:
;CApath = /certs
; It's often easier to use CAfile:
CAfile = /etc/ssl/certs/cacert.pem
; Don't forget to c_rehash CRLpath;  CRLpath is located inside chroot jail:
;CRLpath = /crls
; Alternatively you can use CRLfile:
;CRLfile = /usr/local/etc/stunnel/crls.pem

; Some debugging stuff useful for troubleshooting
;debug = 7
;output = stunnel.log

; Use it for client mode
client = yes

; Service-level configuration

accept  = localhost:106
connect = mail:106



Like Callisto, this file descibes two services for which Stunnel sets up port forwardings.

On Io, Stunnel runs in client mode. This means what you might expect; programs on Io will be initiating connections with Callisto. Client mode can be a little misleading, however, since even in this mode there is still a long lived Stunnel process always running on Io.

The configuration file specifies a verification level of 2 which means that Stunnel will always look for a server certificate and check it against the Certificate Authority root certificate specified by the CAfile parameter. If the server certificate can’t be verified, Stunnel will drop the connection.

Because Stunnel is running in client mode, the cert parameter in this case specifies Io’s client certificate. This is the certificate presented if a server asks Stunnel for a client certificate.

For each of the two services listed in the file, Stunnel is forwarding connections from a port on the loopback interface to the server Mail (my alias for Callisto).

You’ll notice that there is a third service, called imaps, listed in the config file but that it is commented out. At one time, SquirrelMail, the webmail package I use, used Stunnel to talk to my IMAP server on Callisto. Now I use SquirrelMail’s native SSL code for IMAP communication. See the SquirrelMail section of my Mail Setup Doc for more details.

As on Callisto, Stunnel is running with reduced privileges and in a chroot jail.

Stunnel in a Chroot Jail

Here is what the chroot directory looks like on Io. The directory structure is the same on Callisto; the only difference between the two machines being the Stunnel configuration files.

drwxr-x---  4 stunnel  stunnel  512 Feb 20 20:54 stunnel/
drwxr-x---  3 stunnel  stunnel  512 Feb 20 20:55 stunnel/etc/
-rw-r-----  1 root     stunnel  525 Feb 20 22:53 stunnel/etc/stunnel.conf
drwxr-x---  3 stunnel  stunnel  512 Feb 20 20:53 stunnel/var/
drwxr-x---  2 stunnel  stunnel  512 Feb 20 22:53 stunnel/var/run/

ot to the jail. One thing that isn’t here is a directory for the certificates used by Stunnel. I keep these outside the jail because on Callisto, the same directory contains certificates used by my mail server and I wanted to keep all my certificates in one place. I set up Io the same way to keep things consistent. I describe the certificates used by Stunnel in the Certificates section below.

Take a careful look at the ownership and permissions of the Stunnel configuration file. They are set up the way they are so that Stunnel can read the file, but only a root owned process can modify it. Since Stunnel doesn’t modify its own configuration file under normal operation, this is a simple measure to limit the potential damage caused if a malicious user manages to compromise Stunnel is some way.

Startup Scripts

Installing Stunnel from the FreeBSD ports tree automatically installed a startup script in the /usr/local/etc/rc.d directory and I was able to use it unmodified. Here it is.

# $FreeBSD: ports/security/stunnel/files/,v 1.6 2006/04/21 10:51:49 roam Exp $

# PROVIDE: stunnel
# KEYWORD: shutdown

# Add some of the following variables to /etc/rc.conf to configure stunnel:
# stunnel_enable (bool):        Set to "NO" by default.
#                               Set it to "YES" to enable stunnel.
# stunnel_config (str):         Default "/usr/local/etc/stunnel/stunnel.conf"
#                               Set it to the full path to the config file
#                               that stunnel will use during the automated
#                               start-up.
# stunnel_pidfile (str):        Default "/usr/local/var/stunnel/"
#                               Set it to the value of 'pid' in
#                               the stunnel.conf file.

. /etc/rc.subr


[ -z "$stunnel_enable" ]                && stunnel_enable="NO"

load_rc_config $name



run_rc_command "$1"

I needed to add these three lines to /etc/rc.conf to have stunnel start when the machine boots.


The reason the config and pidfile parameters are needed is because I’ve customized the locations of these files.

Programs Secured using Stunnel


Courierpassd is the program I use to allow mail users to change their passwords through SquirrelMail, the webmail package I use. Courierpassd is installed on Callisto and listens on port 106 for connections from clients. In my case, the client is always Io, my web server. As is, using courierpassd means my mail users are sending clear text user IDs and passwords between my web and mail servers.

Courierpassd does not speak SSL, and neither does the SquirrelMail plugin located on Io that constitutes the client. This made courierpassd a prime candidate for using Stunnel at both ends of the connection to secure the transfer of user IDs and passwords between my mail and web servers.

The secure tunnel used by courierpassd is described by the pop3pw service found in the configuration files listed above. On Io SquirrelMail tries to connect to courierpassd on localhost port 106. Stunnel accepts the connection and forwards it to port 106 on Mail, an alias for Callisto. On Callisto, Stunnel accepts the connection from Io and forwards it to localhost port 106 where courierpassd is listening.

Because the client in this case is always the same machine, I decided to be really paranoid and set Stunnel to not only require a server certificate but also a client certificate. That’s what the verify parameter in the pop3pw service description in Callisto’s configuration file is for. Read the Certificates section of this document for a description of the certificates I had to install to make this work.


Besides the plugin that allows users to change their password, SquirrelMail itself talks to my mail server via SMTP. Once again, network communication is involved as my mail server is Callisto while SquirrelMail is installed on Io.

As you can read about in my Mail Setup Doc, qmail is the MTA I use on my mail server. qmail-smtpd, the part of qmail that handles SMTP requests, is patched and configured to offer the starttls protocol to connecting clients. Although SquirrelMail can use SSL with SMTP, it doesn’t do starttls. SquirrelMail only handles the older SMTPS protocol. All other clients that connect to qmail-smtpd can take advantage of starttls. So, if I wanted to use SquirrelMail’s native SSL capability, I’d have to configure and run a second instance of qmail-smtpd on my mail server; one that does SMTPS just for SquirrelMail and a second that does regular SMTP with starttls for everything else. I didn’t feel like managing a second qmail-smtpd instance so I opted to use Stunnel instead.

On Callisto, Stunnel is configured to accept connections from the network on port 465 and to forward these connections to localhost port 25. Port 465 is the well-known port for SMTPS service and I’ve chosen that port for a specific reason. You’ll notice that in the smtp service on Callisto, I have the protocol parameter set to smtp. What this means is that mail clients can use SMTPS to connect to Callisto and send mail. I know I already said that all mail clients on my network except SquirrelMail use SMTP with starttls but the world is a chaotic place and things change. Now if I need to accomodate mail clients that use SMTPS, I’m all set. And I didn’t have to create a second qmail-smtpd instance to do it.

As I did with pop3pw, on Io I configured SquirrelMail to look for my SMTP server on localhost. Stunnel accepts the connections to localhost port 465 on Io and forwards them to Mail port 465 where my Stunnel daemon process is waiting. Take note that since I set the protocol parameter on Callisto to smtp, I needed to do the same thing on Io.

The astute among you have probably realized that I don’t need an smtp service running on Io at all. I can use SquirrelMail’s native SSL capability to connect to the Stunnel process listening on port 465 on Callisto. However, I’m already running Stunnel on Io for the pop3pw service so I thought I might as well use it for SMTP as well.

Unlike pop3pw, SMTP traffic will not always be coming from the same client at the same location. Therefore, implementing client certificates would have been much more complicated for this service. I didn’t feel the need to go through the effort so I’ve configured Stunnel to not check for client certificates in this case.


The sole purpose of certificates is to allow computers (and people) to verify the identity of remote machines they are communicating with. I use three types of certificates with Stunnel; root, server, and client certificates. The three categories describe functional differences between each type more than anything else. The procedure for creating each type is largely the same and in their PEM encoded form, all three types of certificate look identical. A PEM encoded certificate file looks like this:

		<more of the same here>

A PEM encoded certificate file that includes a private key looks like this:

		<more of the same here>
		<more of the same here>

For anyone whose’s interested, PEM stands for Privacy Enhanced Mail.

All the certificates I describe were created from my own Certificate Authority (CA) which I set up using OpenSSL. Exactly how I set up the CA and the commands I used to create the certificates and associated private keys will have to wait for a future document. Here I describe how I use the various certificates I created for Stunnel.

On Callisto, certificates used by Stunnel are kept in /usr/local/share/certs. Here is what the directory looks like.

-r--r--r--  1 root  wheel  221734 Mar 12 15:55 ca-root.crt
-r--r--r--  1 root  wheel    3367 Apr 15 10:16 cacerts.pem
-r--------  1 root  wheel    2566 Apr  1 23:42 stunnel-mailkeycert.pem

On Callisto, Stunnel is running in daemon mode which is to say that on Callisto, Stunnel is acting as the server side of a client-server connection. The stunnel-mailkeycert.pem file holds Stunnel’s server certificate and private key. This is the file that allows Stunnel clients to verify that they are, in fact, talking to Callisto. Remember that Mail is an alias for Callisto.

The cacerts.pem file is used to verify client-side certificates. This file holds Io’s client certificate and the root certificiate of the CA that signed Io’s certificate, which happens to be my OpenSSL based CA. This file holds the certificate chain that Stunnel can use to verify Io’s identity. The root certificate appears first in the file. If I had additional client machines that used client-side certificates, I would append those certificates to this file.

The ca-root.crt file has nothing to do with Stunnel. It was installed by FreeBSD when I built the machine. It’s here because I like to keep my certificates in one place when I can.

And here is what the /etc/ssl/certs directory looks like on Io.

-rw-r--r--  1 root  wheel  1679 Oct 10  2005 cacert.pem
-rw-r--r--  1 root  wheel  1688 Oct  1  2005 io-cert.pem
-rw-------  1 root  wheel  2575 Oct  1  2005 io-keycert.pem

The io-keycert.pem file is Io’s client certificate and private key. Stunnel uses this to prove to a server that requires client certificates that it really is Io that the server is talking with. The io-cert.pem file is the same certificate without the private key. I keep this file handy because it is what I need to copy to any server that will be asking Io for a client certificate, such as Callisto for example.

The cacert.pem file holds the root certificate of a CA. In this case, it is the root certificate of the CA that signed the certificate of the server Io will be connecting to. In my case, this certificate is the same as the root certificate in the cacerts.pem file found on Callisto since I used my CA to sign both Callisto’s and Io’s certificates. The cacert.pem file can hold multiple certificates. This would happen if a Stunnel client needed to connect to multiple servers that used server certificates signed by different CAs. The cacert.pem file would hold one root certificate for each of the involved CAs. Io will only ever connect to Callisto so, in my case, the cacert.pem file contains only one root certificate.

Take note of the permissions on these files. Any file that contains a private key is set with permissions of 400. If someone gets a hold of the private key, then the certificate is rendered useless as that someone could masquerade as one of my servers.

Callisto and CApath

Before I set Stunnel to run in a chroot jail, I used the CApath parameter in Callisto’s configuration files instead of the CAfile parameter. The CApath parameter allows root and client certificates to reside in separate files in the directory specified by the parameter. The reason I switched to CAfile is because the CApath parameter points to a location within the chroot jail while CAfile uses a path not confined to the jail. I like to keep all my certificates in one place on a machine so I decided to use CAfile rather than be forced to move certificates used by Stunnel to another directory.

Here is what /usr/local/share/certs used to look like on Callisto.

-r--r--r--  1 root  wheel  221734 Jan 19 15:55 ca-root.crt
lrwxr-xr-x  1 root  wheel    14 Jan 19 13:20 3cf80a92.0 -> io-cert.pem
lrwxr-xr-x  1 root  wheel    10 Jan 19 13:20 52b74daf.0 -> cacert.pem
-rw-r--r--  1 root  wheel  1363 Jan 19 13:11 cacert.pem
-rw-r--r--  1 root  wheel  1196 Jan 19 03:59 io-cert.pem
-r--------  1 root  wheel  2079 Jan 19 16:12 stunnel-mailkeycert.pem

The io-cert.pem file contains Io’s client certificate and the cacert.pem file contains the root certificate of the CA that signed Io’s certificate. The two *.0 symlinks are what Stunnel actually looks for when reading a client’s certificate chain. The names of these symlinks represent hashes of the *.pem files they point to. They were generated using the c_rehash Perl script which is distributed with the OpenSSL package. The cacert.pem and io-cert.pem files contain the same certificates that are combined in the cacerts.pem file discussed in the previous section.

The ca-root.crt and stunnel-mailkeycert.pem files are also the same files that appear in Callisto’s /usr/local/share/certs directory discussed in the previous section.

Software Home Sites