How to Set Up OpenVPN with Stunnel on Ubuntu 22.04/20.04 Server
This tutorial is going to show you how to run your own OpenVPN server on Ubuntu 22.04/20.04. OpenVPN is an open-source, robust, and highly flexible VPN solution. Stunnel is a tool that tunnels OpenVPN traffic over TCP port 443 in TLS mode, so as to bypass firewall blocking.
Why Set Up Your Own VPN Server?
- Maybe you are a VPN service provider or a system administrator, which behooves you to set up your own VPN server.
- You don’t trust the no-logging policy of VPN service providers, so you go the self-host route.
- You can use VPN to implement network security policy. For example, if you run your own email server, you can require users to log in only from the IP address of the VPN server by creating an IP address whitelist in the firewall. Thus, your email server is hardened to prevent hacking activities.
- Perhaps you are just curious to know how VPN server works.
Features of OpenVPN Server
- Lightweight and fast. In my test, I can watch YouTube 4K videos with OpenVPN. YouTube is blocked in my country (China).
- Runs on Linux and most BSD servers.
- There is OpenVPN client software for Linux, macOS, Windows, Android, and iOS, and OpenWRT.
- Supports RADIUS accounting.
- Supports virtual hosting (multiple domains).
- Easy to set up
- Supports SSL/TLS security, ethernet bridging, TCP or UDP tunnel transport through proxies or NAT.
- Support for dynamic IP addresses and DHCP
- Scalability to hundreds or thousands of users
- Supports conventional encryption using a pre-shared secret key (Static Key mode) or public key security (SSL/TLS mode) using client & server certificates
Requirements
To follow this tutorial, you will need a VPS (Virtual Private Server) that can access blocked websites freely (Outside of your country or Internet filtering system). I recommend Kamatera VPS, which features:
- 30 days free trial.
- Starts at $4/month (1GB RAM)
- High-performance KVM-based VPS
- 9 data centers around the world, including United States, Canada, UK, Germany, The Netherlands, Hong Kong, and Isreal.
Follow the tutorial linked below to create your Linux VPS server at Kamatera.
Once you have a VPS running Ubuntu 22.04/20.04, follow the instructions below.
Step 1: Install OpenVPN Server on Ubuntu 22.04/20.04
Log into your Ubuntu 22.04/20.04 server. Then use apt
to install the openvpn
package from the default Ubuntu repository.
sudo apt update sudo apt install -y openvpn openvpn-systemd-resolved easy-rsa
Step 2: Set Up Certificate Authentication in OpenVPN
OpenVPN supports password authentication (pre-shared key), but it’s very limited. You can generate only one pre-share key. To support multiple users, we need to use certificate authentication. Each user will have their own certificate.
To accomplish this, we need to set up a public key infrastructure (PKI), which includes:
- Set up a certificate authority (CA)
- Create server key and certificate
- Create client key and certificate
Set up a certificate authority (CA)
A certificate authority issues server certificates and client certificates. For example, Let’s Encrypt is a certificate authority that issues free TLS server certificates. However, Let’s Encrypt doesn’t issue client certificates, so we need to set up a private certificate authority for OpenVPN.
The openssl
utility is widely used to set up a certificate authority, but its command line syntax is complex. Instead, we can use the easy-rsa
utility, which is installed in step 1. As its name implies, it’s easier than openssl
.
First, run the following command to copy the /usr/share/easy-rsa/
directory to /etc/openvpn/
.
sudo make-cadir /etc/openvpn/easy-rsa
Switch to the root user.
sudo su -
Change to the /etc/openvpn/easy-rsa/
directory.
cd /etc/openvpn/easy-rsa/
Initialize a public key infrastructure.
./easyrsa init-pki
Then create a certificate authority.
./easyrsa build-ca
You will be asked to enter a passphrase for the CA. When asked about setting a common name for the CA, you can press Enter
to choose the default name: Easy-RSA CA.
Create server key and certificate
Generate a keypair and certificate request for the OpenVPN server. Replace openvpn.example.com
with a real sub-domain for your OpenVPN server. You will need to enter a common name. Use this subdomain as the common name.
./easyrsa gen-req openvpn.example.com nopass
Generate Diffie Hellman parameters.
./easyrsa gen-dh
Now sign the certificate request. The server certificate will be created.
./easyrsa sign-req server openvpn.example.com
Generate an OpenVPN static key to enhance SSL/TLS security.
openvpn --genkey tls-auth /etc/openvpn/easy-rsa/pki/ta.key
Create client key and certificate
Generate a certificate request for the user user01
.
./easyrsa gen-req user01 nopass
Sign this certificate request. The client certificate will be created. You will need to enter the CA passphrase.
./easyrsa sign-req client user01
Each VPN user should have their own certificate/key.
Step 3: Edit OpenVPN Server Configuration File
Copy the sample server configuration file.
sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf /etc/openvpn/server.conf
Edit this file.
sudo nano /etc/openvpn/server.conf
At the beginning of this file, you can find the following line, which enables UDP port on the server’s public IPv4 address.
proto udp
Add a second directive to support IPv6.
proto udp proto udp6
Then find the following lines.
ca ca.crt cert server.crt key server.key # This file should be kept secret
The 3 lines specify the location of the CA certificate, server certificate, and server private key. We need to use the actual location.
ca /etc/openvpn/easy-rsa/pki/ca.crt cert /etc/openvpn/easy-rsa/pki/issued/openvpn.linuxbabe.com.crt key /etc/openvpn/easy-rsa/pki/private/openvpn.linuxbabe.com.key
Then find the Diffie hellman parameters setting.
dh dh2048.pem
Change it to:
dh /etc/openvpn/easy-rsa/pki/dh.pem
The following line specifies the private IPv4 network for OpenVPN. The OpenVPN server will have the 10.8.0.1
private IP address.
server 10.8.0.0 255.255.255.0
Add a second directive to enable IPv6 private addressing.
server 10.8.0.0 255.255.255.0 server-ipv6 2001:db8:0:123::/64
By default, OpenVPN uses the net30
network topology, which is deprecated. Find the follownig line.
;topology subnet
Uncomment it to use the subnet
network topology.
topology subnet
Find the following line
;push "redirect-gateway def1 bypass-dhcp"
Uncomment it (remove the beginning semicolon) and also add a second push
directive, so the OpenVPN server will become the gateway for VPN clients. They will also use the OpenVPN as the DNS server.
push "redirect-gateway def1 bypass-dhcp" push "route-ipv6 2000::/3"
If you want VPN clients to use a particular DNS server, find the following two lines.
;push "dhcp-option DNS 208.67.222.222" ;push "dhcp-option DNS 208.67.220.220"
Uncomment them and change the DNS server IP address.
;push "dhcp-option DNS 8.8.8.8" ;push "dhcp-option DNS 1.1.1.1"
Find the following line.
;client-to-client
Uncomment it, so VPN clients can ping each other.
;client-to-client
Finally, find the following line.
tls-auth ta.key 0 # This file is secret
Specify the actual location of OpenVPN static key.
tls-auth /etc/openvpn/easy-rsa/pki/ta.key 0
Save and close the file. Start OpenVPN server.
sudo systemctl enable --now openvpn@server
Check its status:
sudo systemctl status openvpn@server
As you can see, it’s active (running) and automatic start at boot time is enabled.
Step 4: Enable IP Forwarding
In order for the VPN server to route packets between VPN clients and the Internet, we need to enable IP forwarding by running the following command.
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/60-custom.conf
Also, run the following two commands to enable TCP BBR algorithm to boost TCP speed.
echo "net.core.default_qdisc=fq" | sudo tee -a /etc/sysctl.d/60-custom.conf echo "net.ipv4.tcp_congestion_control=bbr" | sudo tee -a /etc/sysctl.d/60-custom.conf
Then apply the changes with the below command. The -p option will load sysctl settings from /etc/sysctl.d/60-custom.conf file. This command will preserve our changes across system reboots.
sudo sysctl -p /etc/sysctl.d/60-custom.conf
Step 5: Configure IP Masquerading in Firewall
We need to set up IP masquerading in the server firewall, so that the server becomes a virtual router for VPN clients. I will use UFW, which is a front end to the iptables/nftable firewall. Install UFW on Ubuntu with:
sudo apt install ufw
First, you need to allow SSH traffic.
sudo ufw allow 22/tcp
Then find the name of your server’s main network interface.
ip addr
As you can see, it’s named ens3
on my Ubuntu server.
To configure IP masquerading, we have to add iptables command in a UFW configuration file.
sudo nano /etc/ufw/before.rules
By default, there are some rules for the filter
table. Add the following lines at the end of this file. Replace ens3
with your own network interface name.
# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 10.8.0.0/24 -o ens3 -j MASQUERADE
# End each table with the 'COMMIT' line or these rules won't be processed
COMMIT
In Nano text editor, you can go to the end of the file by pressing Ctrl+W
, then pressing Ctrl+V
.
The above lines will append (-A) a rule to the end of POSTROUTING chain of nat table. It will link your virtual private network with the Internet. And also hide your network from the outside world. So the Internet can only see your VPN server’s IP, but can’t see your VPN client’s IP, just like your home router hides your private home network.
By default, UFW forbids packet forwarding. We can allow forwarding for our private network. Find the ufw-before-forward
chain in this file and add the following 3 lines, which will accept packet forwarding if the source IP or destination IP is in the 10.8.0.0/24
range.
# allow forwarding for trusted network -A ufw-before-forward -s 10.8.0.0/24 -j ACCEPT -A ufw-before-forward -d 10.8.0.0/24 -j ACCEPT
Save and close the file. Then enable UFW.
sudo ufw enable
If you have enabled UFW before, then you can use systemctl to restart UFW.
sudo systemctl restart ufw
Now if you list the rules in the POSTROUTING chain of the NAT table by using the following command:
sudo iptables -t nat -L POSTROUTING
You can see the Masquerade rule.
It can take some time for UFW to process the firewall rules. If the masquerade rule doesn’t show up, then restart UFW again (sudo systemctl restart ufw
).
Step 6: Open Port 1194 in Firewall
Run the following command to open TCP and UDP port 1194.
sudo ufw allow 1194/tcp sudo ufw allow 1194/udp
Now OpenVPN server is ready to accept client connections.
If you run a local DNS Resolver
For those of you who run a local DNS resolver, if you specified 10.10.10.1 as the DNS server for VPN clients, then you must allow VPN clients to connect to port 53 with the following UFW rule.
sudo ufw insert 1 allow in from 10.8.0.0/24
You also need to edit the BIND DNS server’s configuration file (/etc/bind/named.conf.options
) to allow VPN clients to send recursive DNS queries like below.
allow-recursion { 127.0.0.1; 10.8.0.0/24; };
Then restart BIND.
sudo systemctl restart named
How to Install and Use OpenVPN client on Ubuntu 22.04/20.04 Desktop
Run the following command to install OpenVPN command line client on Ubuntu desktop.
sudo apt install openvpn
Then you need to copy the CA certificate, client certificate, client private key, and the static key file from the OpenVPN server to the client’s computer. The path for the files on the OpenVPN server.
- CA cert:
/etc/openvpn/easy-rsa/pki/ca.crt
- Client cert:
/etc/openvpn/easy-rsa/pki/issued/user01.crt
- Client key:
/etc/openvpn/easy-rsa/pki/private/user01.key
- Static key:
/etc/openvpn/easy-rsa/pki/ta.key
I stored them under the /etc/openvpn/client/
directory on the client’s computer.
Next, copy the sample client config file.
sudo cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /etc/openvpn/
Edit the file.
sudo nano /etc/openvpn/client.conf
Find the following lines.
remote my-server-1 1194
Specify the public IP address of your OpenVPN server.
remote 12.34.56.78 1194
Then find the following lines.
ca ca.crt cert client.crt key client.key
Use the actual path for the CA cert, client cert, and client private key.
ca /etc/openvpn/client/ca.crt cert /etc/openvpn/client/user01.crt key /etc/openvpn/client/user01.key
Find the following line.
tls-auth ta.key 1
Use the actual path for the static key.
tls-auth /etc/openvpn/client/ta.key 1
Save and close the file. Then start the OpenVPN client
sudo systemctl start openvpn@client
Check status:
sudo systemctl status openvpn@client
Check if you can ping the OpenVPN server.
ping 10.8.0.1
Then go to https://icanhazip.com. If everything is working properly, you should see the public IP address of the OpenVPN server.
If you are successfully connected to the VPN server, but your public IP address doesn’t change, that’s because IP forwarding or IP masquerading is not working. I once had a typo in my iptables command (using a wrong IP address range), which caused my computer not being able to browse the Internet.
To stop this Systemd service, run
sudo systemctl stop openvpn@client
If you want to use Network Manager to manage OpenVPN connection, then you also need to install these packages.
sudo apt install network-manager-openvpn network-manager-openvpn-gnome
OpenVPN GUI Client for Windows and macOS
You can use the free and open-source Pritunl OpenVPN client: https://client.pritunl.com/
Speed
OpenVPN is pretty fast. I can use it to watch 4k videos on YouTube. As you can see, my connection speed is 63356 Kbps, which translates to 61 Mbit/s.
And here’s the test results on speedtest.net.
Debugging
If there’s problem establishing VPN connection, you can edit the OpenVPN server config file (/etc/openvpn/server.conf
) and increase the level of log file verbosity to 6.
verb 6
This directive is located at the bottom of the file.
Then you can check the logs.
- client:
sudo journalctl -eu openvpn@client
- server:
sudo journalctl -eu openvpn@server
Set Up Stunnel (optional)
If you live in a country like China, or Iran, then your national firewall may block OpenVPN connections. You can wrap the OpenVPN traffic inside a TLS tunnel to hide the fact that you are using OpenVPN.
Configure Stunnel on the OpenVPN server
Edit the OpenVPN server config file.
sudo nano /etc/openvpn/server.conf
Enable the TCP port.
proto tcp proto udp proto udp6
Save and close the file. Then install Stunnel on the OpenVPN server.
sudo apt install -y stunnel4
Copy the sample configuration file:
sudo cp /usr/share/doc/stunnel4/examples/stunnel.conf-sample /etc/stunnel/openvpn.conf
Edit the new file.
sudo nano /etc/stunnel/openvpn.conf
Find the following lines and uncomment them.
;setuid = stunnel4 ;setgid = stunnel4 ;pid = /var/run/stunnel.pid ;output = /var/log/stunnel.log
Change them to:
setuid = stunnel4 setgid = stunnel4 pid = /var/run/stunnel/stunnel.pid output = /var/log/stunnel/stunnel.log
Find the following lines.
[gmail-pop3] client = yes accept = 127.0.0.1:110 connect = pop.gmail.com:995 verifyChain = yes CApath = /etc/ssl/certs checkHost = pop.gmail.com OCSPaia = yes [gmail-imap] client = yes accept = 127.0.0.1:143 connect = imap.gmail.com:993 verifyChain = yes CApath = /etc/ssl/certs checkHost = imap.gmail.com OCSPaia = yes [gmail-smtp] client = yes accept = 127.0.0.1:25 connect = smtp.gmail.com:465 verifyChain = yes CApath = /etc/ssl/certs checkHost = smtp.gmail.com OCSPaia = yes
This enables tunnels for SMTP, IMAP, and POP3 server. Delete them and add the following lines instead, so Stunnel will be able to pass traffic to the OpenVPN server listen on port 1194.
[openvpn] cert=/etc/openvpn/easy-rsa/pki/issued/openvpn.example.com.crt key=/etc/openvpn/easy-rsa/pki/private/openvpn.example.com.key accept = 0.0.0.0:443 connect = 127.0.0.1:1194
Save and close the file.
Create the PID file and log file.
sudo mkdir /var/run/stunnel /var/log/stunnel
Grant permission to the user.
sudo chown stunnel4:stunnel4 /var/run/stunnel/ -R sudo chown stunnel4:stunnel4 /var/log/stunnel/ -R sudo setfacl -R -m u:stunnel4:rx /etc/openvpn/easy-rsa/
Start Stunnel.
sudo /usr/bin/stunnel4 /etc/stunnel/openvpn.conf
You should see that Stunnel is using port 443.
sudo ss -lnpt | grep 443
If it failed to start, then check the log file: /var/log/stunnel/stunnel.log
. If your server has another process listening on TCP port 443, you need to stop it, or Stunnel won’t be able to bind to TCP port 443.
Open TCP port 443 in firewall, so VPN clients will be able to connect to this port.
sudo ufw allow 443/tcp
Configure Stunnel on the OpenVPN client
Install Stunnel on the OpenVPN client.
sudo apt install -y stunnel4
Create Stunnel config file.
sudo nano /etc/stunnel/client.conf
Add the following lines in this file.
output = /var/log/stunnel/stunnel.log pid = /var/run/stunnel/stunnel.pid client = yes [openvpn] sni = openvpn.example.com accept = 127.0.0.1:1194 connect = 12.34.56.78:443
Save and close the file. Create the log directory and pid directory.
sudo mkdir /var/log/stunnel/ /var/run/stunnel/
Start the Stunnel client.
sudo stunnel /etc/stunnel/client.conf
It listens on 127.0.0.1:1194
and passes requests to the Stunnel server.
sudo ss -lnpt | grep 1194
Next, edit the OpenVPN client config file.
sudo nano /etc/openvpn/client.conf
Enable TCP and disable UDP.
proto tcp ;proto udp
Change remote server address to 127.0.0.1:1194.
remote 127.0.0.1 1194
Save and close the file. Then restart OpenVPN client.
Wrapping Up
That’s it! I hope this tutorial helped you install and configure OpenVPN on Ubuntu 22.04/20.04. As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks 🙂
My client is Windows. I think I did not configure the Windows client correctly. Is it possible to help me configure the Windows client? I am from Iran and if you guide me for the correct configuration of the Windows client, you have helped me a lot. I installed the Pritunl and Stunnel software on Windows and put the files related to the client that I downloaded from the server into a folder. I made the configuration settings from the settings you gave for Linux, but unfortunately I cant connect to the server. OpenVpn is active and running on my server without error.
thank you in advance
If you found the following error in the Stunnel log,
It might be that your national firewall is able to detect and block Stunnel traffic. You can try other VPN solutions instead, such as SoftEtherVPN SSTP protocol and OpenConnect VPN protocol.
Some Iran folks report that Stunnel works on Linux client, but fails on Windows client. You might consider switching to Linux?
Thanks for help my friend.
I have 2 Linux virtual servers. Can I set up a OpenVPN+Stunnel server on one of them and then connect to the server from the second Linux (client) and then connect to the second Linux (client) from Windows (my client computer) and bypass the filter? In short, I want to connect to the Linux client from Windows and access the Internet of the main server. Also, I need my connection to be a UDP connection and the SSH tunnel method is not suitable for me. Can you please help me?? I will be very grateful. In the meantime, I am currently running a Wireguard+WSTunnel server, but the download speed is very low and the latency is very fluctuating. A tutorial for the Tunneling over WebSocket would be very helpful. Thank you for all your hard work.
Hi , I am from Iran. I have two linux servers : one in Iran , one outside of Iran. None of UDP based VPN solutions that I have tested so far ( IPsec , Wireguard, OpenVPN in UDP ) didn’t work for me even for connecting to server in Iran. Right now I use SSH Tunnel with OpenVPN in TCP mode and also Openconnect with/without SSH Tunnel. I didn’t test UDP in TCP tunnel solutions but I don’t think these solutions work very well. I suggest you also try TCP based solutions.
The best solution for me was Wireguard over WStunnel and Softether. There are solutions for passing UDP through SSH, but I have not been able to do them so far. Using an IRAN server for SSH Tunneling is not a good option in terms of security and privacy. A solution must be found to connect directly to the main server using tunnels. Like WSTunnel or passing UDP over SSH.
You can set SSH Tunnel directly between Client and Server outside of Iran and run Openvpn over that ( just like Openvpn+stunnel) . I use server in Iran primarily as an intermediate for sharing VPN connections ; Also Internet on mobile devices is more restricted and server in Iran allows me to have access to VPN on mobile devices.
Hello, I am form Iran. I think TLSv1.3 traffic is blocked in Iran so I just
added:
to client’s config file and It worked ( including on Windows ).
I am getting this error
Options error: Unrecognized option or missing or extra parameter(s) in client.conf:17: sslVersionMin (2.5.7)
Can you tell me how to configure it more precisely?
sure ,
server openvpn (version 2.5.5) config :
server stunnel (version 5.63 ) config :
client stunnel (version 5.66) config :
client openvpn (version 2.5.7) config
2022.10.19 10:04:56 LOG6[ui]: Initializing inetd mode configuration
2022.10.19 10:04:56 LOG5[ui]: stunnel 5.63 on x86_64-pc-linux-gnu platform
2022.10.19 10:04:56 LOG5[ui]: Compiled/running with OpenSSL 3.0.2 15 Mar 2022
2022.10.19 10:04:56 LOG5[ui]: Threading:PTHREAD Sockets:POLL,IPv6,SYSTEMD TLS:ENGINE,OCSP,PSK,SNI Auth:LIBWRAP
2022.10.19 10:04:56 LOG6[ui]: Initializing inetd mode configuration
2022.10.19 10:04:56 LOG5[ui]: Reading configuration from file /etc/stunnel/openvpn.conf
2022.10.19 10:04:56 LOG5[ui]: UTF-8 byte order mark detected
2022.10.19 10:04:56 LOG5[ui]: FIPS mode disabled
2022.10.19 10:04:56 LOG6[ui]: Compression enabled: 0 methods
2022.10.19 10:04:56 LOG6[ui]: Initializing service [openvpn]
2022.10.19 10:04:56 LOG6[ui]: OpenSSL security level is used: 2
2022.10.19 10:04:56 LOG6[ui]: Session resumption enabled
2022.10.19 10:04:56 LOG6[ui]: Loading certificate from file: /etc/openvpn/easy-rsa/pki/issued/****.crt
2022.10.19 10:04:56 LOG6[ui]: Certificate loaded from file: /etc/openvpn/easy-rsa/pki/issued/****.crt
2022.10.19 10:04:56 LOG6[ui]: Loading private key from file: /etc/openvpn/easy-rsa/pki/private/****.key
2022.10.19 10:04:56 LOG6[ui]: Private key loaded from file: /etc/openvpn/easy-rsa/pki/private/****.key
2022.10.19 10:04:56 LOG6[ui]: DH initialization skipped: no DH ciphersuites
2022.10.19 10:04:56 LOG5[ui]: Configuration successful
2022.10.19 10:04:56 LOG6[ui]: Service [openvpn] (FD=9) bound to 0.0.0.0:443
2022.10.19 10:04:56 LOG3[main]: Cannot create pid file /var/run/stunnel.pid
2022.10.19 10:04:56 LOG3[main]: create: Permission denied (13)
I just made some changes to the “Configure Stunnel on the OpenVPN server” section. Please re-configure it and the error should be gone.
I have a error when a put this command line –> ./easyrsa init-pki
root@XXXXX:/etc/openvpn/easy-rsa# ./easyrsa init-pki
That’s a warning, not an error.
It means you have previously created a PKI, but now you create a new one, that’s why it displays this warning.
How can use this method in android and IOS ??
Can we use Radius to authenticate users in this mothod?
I am trying to pass OPENVPN+Stunnel through a CDN (Cloudflare) in order to hide server ip from the national firewall, but i haven’t managed yet. It seems like Cloudflare is still able to distinguish Stunnel packages from HTTPS packages and can drop them. Here is the Stunnel log when i try to connect OPN VPN profile through a stunnel whose domain is behind Cloudflare:
SSL_read: ssl/record/rec_layer_s3.c:320: error:0A000126:SSL routines::unexpected eof while reading
Connection reset: 16 byte(s) sent to TLS, 316 byte(s) sent to socket
Do you think there is anyway to pass Stunnel through Cloudflare?
Hello, I’m sorry for this tutorial that you said, how to create a client file for a user with the ovpn extension, what is the command?
Client on macOS here, but the connection resets every few seconds, probably because there is never actually a connection. Any ideas?