Up until now, we've only been able to access our server while connected to the same network. In this post, we are going to configure OpenVPN so that we can remotely manage it, as well as lay the groundwork for other applications using Cloudflare and Nginx Proxy Manager.
Before we begin, we are going to need to change a couple of settings on our router. Sadly, not all routers are configured the same way so there is no universal guide. Despite that, most will use the same terminology so it's pretty easy to figure it out.
By default, most routers use DHCP which means that they assign dynamic IP addresses to every device that connects to them. However, this makes it difficult to consistently access our server. This is why we are going to give it a static IP.
First, we need to find our server's MAC address. Open a terminal and run
ifconfig -a. The network interface we care about should have a line starting with
lladdr. If you have multiple network interfaces (both Ethernet and WiFI for example), you can run
ip route | grep default to see which one you are using.
Then, open a browser and go to your router's settings by typing the address of its default gateway (the same address that you get when running
ip route | grep default). You should have a section named DHCP, Static leases or something similar. There, you are going to add a new entry, set its IP to whatever you like (in my case
192.168.1.254) and fill in the above MAC address.
You might need to restart your server and/or router, but if everything went well, you should now be able to see the line
inet 192.168.1.254 next to the network interface when running
Next, we need to forward some ports to allow a direct connection from the internet to our server. Again, there's no universal guide on how to do this, so you're going to have to do a bit of digging through your router's settings.
To use OpenVPN, you need to forward port
1194 with the following settings:
- Name: OpenVPN (or anything else you prefer)
- Internal Port: 1194
- External Port: 1194
- Protocol: UDP
- Destination IP: 192.168.1.254 (or the static IP that you chose)
I have also forwarded a port for remote SSH connections (both TCP and UDP) in case the VPN goes down, but you should only do this if you have hardened your SSH server.
Now that we have configured our router, it's time to get a custom domain name for our server. You could use a DDNS service like NoIP, however, most such websites place several restrictions when using the free plan, making it more worth to just rent a real domain. I personally got mine from Google Domains for about 12$ a year.
Next up, we are going to change our nameservers to Cloudflare's in order to take advantage of their caching and security features. This is not mandatory, but it's going to make it easier to fine-tune your domain's settings later on.
After getting your domain, you should create a Cloudflare account using their free tier and configure your new website. Depending on your registrar, the process of changing your nameservers will be a bit different, so you should probably follow the official guide.
To create the VPN, we are going to use the docker container cloudflare-ddns to make a subdomain always point to our real IP.
You first need to create a Cloudflare API key:
- Go to https://dash.cloudflare.com/profile/api-tokens
- Click Create Token
- Provide the token with a name, for example,
- Grant the following permissions:
- Zone - Zone Settings - Read
- Zone - Zone - Read
- Zone - DNS - Edit
- Set the zone resources to:
- Include - All zones
- Complete the wizard and copy the generated token into the API_KEY variable for the container. Make sure to note this down somewhere since you won't be able to access it afterwards.
After getting your API key, go to your Portainer instance, open the stacks tab, and add a new stack named
routing. In the
docker-compose field paste the following and customize to match your API key and domain:
Click deploy the stack and you should notice that a new A record has appeared on the DNS tab of your Cloudflare dashboard.
I have also added a couple of CNAME records pointing to the original A record specifically for SSH and VPN services:
Now it's finally time to start our VPN. For that, we are going to use the kylemanna/openvpn container:
After running these commands, go to Potainer and deploy a new
If everything went well, you should be able to download an OpenVPN client from one of these sources and import your certificate.
- Windows: https://openvpn.net/community-downloads/
- MacOS: https://openvpn.net/client-connect-vpn-for-mac-os/
- Android: https://play.google.com/store/apps/details?id=net.openvpn.openvpn
- iOS: https://apps.apple.com/us/app/openvpn-connect/id590379981
- Linux: use
Then, you simply connect to your server from anywhere in the world and access your local network as if you were at home.
Nginx Proxy Manager
By now you should be able to connect and manage your server remotely. But what happens if you want to simply open a browser, go to
subdomain.example.com and access a self-hosted application? This is where Nginx Proxy Manager comes in.
NPM, like any other reverse proxy, allows you to point all of your subdomains to itself and it will automatically manage how each request is routed. For example, both
blog.example.com can point to the proxy's port but get routed to different local servers, one for your website and one for your blog.
To deploy NPM, we are going to use the container jlesage/docker-nginx-proxy-manager.
Next, we're going to create a custom Nginx config file to change some of the default settings. Make sure to also change the
Local subnets section to match your own network:
We also need to create a Docker network called
proxy which will contain all services that will need to be routed to:
Finally, open the
routing stack you created earlier in Portainer and edit it like so:
After deploying the stack, you can open a browser and go to
[your-server-ip]:81 to access NPM's web UI, or
[your-server-ip]:80 to test your installation. However, you still won't be able to actually use the proxy.
What you first need to do is forward ports 80 and 443 on your router, as well as go to your Cloudflare dashboard and create A, AAAA, or CNAME orange-cloud records for any subdomains you want to use.
The problem is that some ISPs block HTTP ports, making hosting your apps a bit more difficult. This is why we are going to use a Cloudflare Argo Tunnel.
Cloudflare Argo Tunnel
To create a tunnel, we need to first generate our certificate:
Then, follow the instructions on your terminal and save the
cert.pem file at
Finally, edit the
routing stack again and add the following:
After deploying, you should notice a new AAAA record on your Cloudflare dashboard. If you want to use any other subdomain, you simply need to add a CNAME alias pointing to that record.
To test if everything is working correctly, add a new CNAME alias for
whoami.example.com and add a proxy host in NPM with the following settings:
Wait a couple of minutes for the changes to propagate and you should be able to access your new host.
Automatic SSL Certificates
The primary reason why SSL is used is to keep sensitive information sent across the Internet encrypted so that only the intended recipient can access it. One of the main selling points of NPM is automatic SSL certificate management.
In order to create a wildcard certificate for all of your subdomains, you can follow this guide by u/Sunsparc on Reddit. After creating your certificate, you should always select it, as well as turn on Force SSL and HTTP/2 Support on any proxy host you create.
After following this guide you should have your own, self-hosted VPN, as well as a reverse proxy, tunneled through Cloudflare. You can now start setting up various other services such as a Plex stack, a Grafana monitoring dashboard, or even your own personal cloud suite using Nextcloud.