Stunnel for Mac OS

SSL Stunnel

Stunnel is a SSL wrapper for those web services which could not deploy SSL directly. I am using Ratchet for websocket, and it does not support SSL. So I found this wonderful tool!

Stunnel listened SSL connection on the accept ports, then strip the SSL, and forward it to the connect ports. accept and connect are defined in the stunnel.conf.

Download Stunnel


stunnel package download from Rudix, or use homebrew, or mac-port. Very convinient to install!

Running Stunnel


If you use Rudix pacakge to install, the binaries of stunnel and stunnel3 will be installed in /usr/local/bin/.

However, it is not easy to find its installed place. You can’t find it by using ‘whereis’ or ‘which’!

But luckily, you can just run:

$ stunnel

and the prompt will give you enough information. Such as where is the location of the stunnel.conf is /usr/local/etc/stunnel/stunnel.conf.

stunnel.conf


Specify the group priviledge. Add the group ‘stunnel’ and a user ‘stunnel’ in this group. Then change the stunnel.conf.

; A copy of some devices and system files is needed within the chroot jail
; Chroot conflicts with configuration file reload and many other features
chroot = /usr/local/var/lib/stunnel/
; Chroot jail can be escaped if setuid option is not used
setuid = stunnel
setgid = stunnel
$ sudo chown -R stunnel /usr/local/var/lib/stunnel/
$ sudo chgrp -R stunnel /usr/local/var/lib/stunnel/

Specify the location of the certificate and key. We will generate the certificate later.

; Certificate/key is needed in server mode and optional in client mode
cert = /usr/local/etc/stunnel/stunnel.pem

Stunnel is default to run in a daemon mode (which means in the background.) However, for the sake of developers, we can make it run at the foreground and to see the log.

foreground=yes

After all the deployment, we can now test the 443 to 80.

[https]
accept  = 443
connect = 80

If you want to use web socket, you can listen to the 8443 port for imcoming “wss”, and run websocket service at the 8081 which only accept connection from localhost.

client=no
[websockets] 
accept = 127.0.0.1:8443
connect = 127.0.0.1:8081

Generate the certificate


By reference to this blog, I generated the certificate for my localhost websocket server

openssl genrsa -out key.pem 2048
openssl req -new -x509 -key key.pem -out cert.pem -days 1095
cat key.pem cert.pem >> /usr/local/etc/stunnel/stunnel.pem

Note that the Common Name for the certificate is exactly the same as your host address. If you are develop your localhost server, your can specify ‘localhost’.

Add the certificate to the keychain access


Now you can try to connect to the port 8081 in the javascript console of a browser such as Chrome and Safari.

var conn = new WebSocket('wss://localhost:8443');
conn.onopen = function(e) {
    console.log("Connection established!");
};

conn.onmessage = function(e) {
    console.log(e.data);
};

Unfortunately, the connection will not be able to establish at this moment. It is simply because the browser does not trust the certificate. To solved it, let’s add the certificate to the keychain access.

Now that the browsers (Chrome and Safari) will acknowledge the certificate, and the connection will establish. Enjoy. :)