Do you want to set up a webserver but your ISP forces a NAT onto you? Or perhaps you don't have a static IP and don't want to use a dynamic DNS service. Lucky for you, this guide has you covered.
Things you'll need:
- a webserver
- a server not behind a NAT (preferably with a static IP), I am using a free tier t3.nano instance on AWS
Step 1:
Install and setup OpenVPN using this guide.
Optionally use this guide if you want more security and plan to connect additional users to this VPN. In my case I will only connect my webserver to the VPN so I'm using the simpler connection method.
Step 2
After confirming that the connection works, you need to configure a static IP for the webserver inside the VPN.
For this, simply add client-config-dir ccd
at the bottom of your server.conf and create a new file at /etc/openvpn/server/ccd/CommonName
where CommonName is the common name (or CN) you used to generate the client certificate.
Inside this file add the line ifconfig-push 10.8.0.2 255.255.255.0
where the first IP is static IP you want for your webserver. Source.
Step 3
What we want next is a user to hit the public IP of the OpenVPN server, which redirects traffic to our webserver with the internal static IP and vice versa. For this part I referred to an OpenVPN community forum post.
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -d xxx.xxx.xxx.xxx -p tcp --dport 80 -j DNAT --to-dest yyy.yyy.yyy.yyy:80
iptables -t nat -A PREROUTING -d xxx.xxx.xxx.xxx -p tcp --dport 443 -j DNAT --to-dest yyy.yyy.yyy.yyy:443
iptables -t nat -A POSTROUTING -d yyy.yyy.yyy.yyy -p tcp --dport 80 -j SNAT --to-source zzz.zzz.zzz.zzz
iptables -t nat -A POSTROUTING -d yyy.yyy.yyy.yyy -p tcp --dport 443 -j SNAT --to-source zzz.zzz.zzz.zzz
- xxx.xxx.xxx.xxx = public IP of your OpenVPN server
- yyy.yyy.yyy.yyy = internal static IP of web server
- zzz.zzz.zzz.zzz = internal IP of OpenVPN server
Explanation:
- The first line
sysctl -w net.ipv4.ip_forward=1
enables IP forwarding. - The second and third lines filter any incoming TCP packets on port 80 and 443 of the OpenVPN server coming from the internet and then send it to our webserver using the internal static IP.
- The fourth and fifth line filter any TCP packets on port 80 and 443 of the webserver and route it to their destination but change the source address to the public IP of the OpenVPN server, make it look like it came from there.
If you need to understand what IP tables does, read its man page using man iptables
. If you want a more in-depth understanding of what happens, refer to this execellent tutorial by Oskar Andreasson.
Alternatives:
OpenVPN Access Server: The free tier allows max 2 active connections and provides a simple UI for managing access and configuring this portfowarding through a DMZ settings page. I'll probably switch to this method since I don't need more than 2 active connections. But since this is technically a free tier and they can revoke access to the free tier, I first set it up manually so that if needed, I can switch back to this way in the future.
Also instead of setting up iptables, you can potentially set up a reverse proxy to send packets to the webserver over OvenVPN. I have my reverse proxy configured on the webserver end, so I haven't tested if a reverse proxy can work behind another reverse proxy. I don't see any reason why it shouldn't though.