At Loadbalancer.org we love open source. It exposes us to great software such as Stunnel. And, if you're using our load balancer appliance, you may well want to use it to add TLS encryption to your service, without the need for any code changes.
Here I'll explain how you can use Stunnel to secure not only your web servers, but also any TCP-based service.
What is Stunnel?
Stunnel is a piece of software that has the unique ability to "wrap" various services in TLS, offering an additional layer of encryption and functionality. It listens on the port specified in its configuration file, encrypts the communication with the client, and forwards the data to the original daemon listening on its usual port.
As such, Stunnel's architecture is finely tuned for security, portability, and scalability, making it an ideal choice for large-scale deployments. And, while its utility extends beyond this, many users leverage Stunnel for SSL/TLS termination on our Loadbalancer.org appliance.
Stunnel v NGINX reverse proxy
For what it's worth, if you're wondering whether you should consider using NGINX instead as your TLS-terminating reverse proxy, here are a few points to consider:
When to use Stunnel
- Pros: Lightweight for basic needs, good for non-HTTP protocols.
- Cons: Doesn't provide load balancing capabilities, but can also be used as a client.
When to use NGINX
- Pros: A high performance web server with strong TLS termination, offering caching, and load-balancing
- Cons: It requires more resources.
Where does that leave you?
My suggestion would be to choose Stunnel for basic TLS termination with few apps and limited resources. Less is more, after all!
And choose NGINX for most web servers where TLS termination is needed alongside features like caching and load balancing.
It also depends on which software you're more accustomed to, as well as which works better for what you need to achieve.
Anyway. For the purposes of this blog I'm going to assume you're using Stunnel...
Getting started with Stunnel software
The first step towards Stunnel configuration involves installing Stunnel on your server. You can download Stunnel here if you don't already have it.
Next, follow these steps (note, that the installation process may differ depending on your Linux distribution):
# RHEL and derivatives
yum install stunnel
# Debian and derivatives
apt install stunnel
# Alpine Linux
apk add stunnel
After the installation, you should then be able to locate the Stunnel configuration at:
/etc/stunnel/stunnel.conf
Stunnel configuration
Stunnel configuration requires you to edit the text file to include some general configurations, as well as the configuration for particular services.
Global configuration options
I recommend that you drop root privileges if Stunnel is started by the root user:
setuid = stunnel
setgid = stunnel
If it's enabled, A PID file is then created inside the chroot jail:
pid = /var/run/stunnel.pid
Debugging and logging options such as these can also be useful for troubleshooting:
foreground = yes
debug = info
output = /var/log/stunnel.log
If you need to enable support for the insecure SSLv3 protocol, then use this (although very few people should need this anymore):
options = -NO_SSLv3
Stunnel example services
Here are some example pop3s, ssmtp, and HTTPS services...
pop3s
[pop3s]
accept = 995
connect = 127.0.0.1:110
cert = /etc/stunnel/stunnel.pem
ssmtp
[ssmtp]
accept = 465
connect = 127.0.0.1:25
cert = /etc/stunnel/stunnel.pem
HTTPS
[https]
ciphers=ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256
accept = 443
connect = 127.0.0.1:80
cert = /etc/stunnel/stunnel.pem
TIMEOUTclose = 0
Alternatively, here's a slightly more interesting example.....
MySQL-over-TLS encapsulation connecting the Unix socket
[mysql]
cert = /etc/stunnel/stunnel.pem
accept = 3307
connect = /run/mysqld/mysqld.sock
Don't forget your SSL/TLS certificate
To use Stunnel on your server, you'll need an SSL certificate. For anyone confused about how to do this in Linux, check out this blog: How to create an SSL certificate in Linux.
This could be a self-signed certificate or one obtained from providers like Let's Encrypt. In the examples shown above, a self-signed certificate and private key are used. They also require a PEM file, which should contain the server certificate as well as the key.
Alternatively, you can provide the certificate and the key in separate files, like so:
cert = /etc/stunnel/server.crt
key = /etc/stunnel/server.key
Bonus section! How to configure SSH over TLS with Stunnel
Here is another example of a more “exotic” Stunnel configuration. Most people, and rightly so, will ask “but why?” -“Well, because we can!”
In seriousness, it has a few real-life uses. You can expose your SSH server via port 443 if the firewall blocks port 22. It allows you to use mTLS as a method of limiting access to the SSH server, which might be useful if you use mTLS for other services already. You can block access to all the services by revoking a single certificate.
Also, so-called security by obscurity. You can “hide” your SSH server on the post 443 that your web server already uses and use SNIs to determine if the client should be seeing the website or perhaps should be given an SSH prompt.
Unlike the previous examples, SSH does not support TLS natively, which means we need to use a proxy to be able to connect to such service. Luckily, Stunnel can be configured in client mode, which means it can serve that purpose.
Client configuration
The below example uses a domain of the remote SSH server.
[ssh-client]
client = yes
accept = 127.0.0.1:2222
connect = ssh.example.com:443
Server configuration
The below example shows how to use SNI in order to make both your web and SSH server available on port 443 at the same time:
[webserver]
ciphers=ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256
accept = 443
connect = 127.0.0.1:80
cert = /etc/stunnel/stunnel.pem
TIMEOUTclose = 0
[ssh]
sni = webserver:ssh.example.org
accept = 443
connect = 127.0.0.1:80
cert = /etc/loadbalancer.org/certs/server.pem
And that's it!
I hope the Stunnel configurations I've outlined are useful to you, and help you safeguard your network communications.
We've seen how Stunnel works as a versatile solution for securing non-TLS services, offering encryption for various protocols with minimal effort, making it a valuable tool for your arsenal.
In the meantime, if you have any questions, feel free to drop me a message in the comments below.