As privacy concerns grow, I’ve been running a self-hosted OpenVPN server to protect my traffic on untrusted networks: hotel Wi-Fi, airport connections, and the like. Some networks, however, are aggressively filtered:

  • Traffic to non-standard ports is blocked
  • Only 80/tcp and 443/tcp are allowed outbound
  • DNS is locked to the local resolver, which can cause DNS leaks

To work around this, I set up two OpenVPN configurations on the same host: one over TCP (to survive port-restricted networks) and one over UDP (preferred for performance when there are no restrictions). Here are the implementation notes.

Subnet separation Link to heading

TCP and UDP VPN clients must be on separate subnets. OpenVPN needs distinct IP ranges to route traffic correctly when both servers are running simultaneously. I use a /24 for each. Refer to IANA reserved address ranges when choosing your subnets.

Both servers can share the same tun adapter.

Configuration files Link to heading

Place one .conf file per OpenVPN instance under /etc/openvpn:

/etc/openvpn # ls *.conf
tcp-server.conf  udp-server.conf

Each file defines its own proto, port, server subnet, and any instance-specific settings.

Telling systemd which configurations to start Link to heading

Open /etc/default/openvpn and set AUTOSTART to list the names of the configurations to start automatically (the name corresponds to the .conf filename without the extension):

# Start only these VPNs automatically via init script.
# Allowed values are "all", "none" or space separated list of
# names of the VPNs. If empty, "all" is assumed.
AUTOSTART="tcp-server udp-server"

Reload systemd after making changes:

systemctl daemon-reload

Verify both servers are running Link to heading

Restart OpenVPN and check the logs:

systemd[1]: Starting OpenVPN connection to tcp-server...
systemd[1]: Starting OpenVPN connection to udp-server...
systemd[1]: Started OpenVPN connection to tcp-server.
systemd[1]: Started OpenVPN connection to udp-server.

Confirm both are listening with netstat or ss:

# netstat -plunt | grep -i openvpn
tcp   0  0  0.0.0.0:1194  0.0.0.0:*  LISTEN  1635/openvpn
udp   0  0  0.0.0.0:1194  0.0.0.0:*          1644/openvpn

With this setup, clients can connect over UDP for the best performance, and fall back to TCP automatically when UDP is blocked.