In a previous post I described how to route traffic for a single Linux user through a VPN. For containers, the process is much simpler.
To begin, create a
docker-compose file (or a Portainer stack). This should include the containers you wish to protect, as well as a container connecting to your VPN. I've chosen to use a WireGuard container provided by the Linuxserver group.
version: "3" services: vpn: image: lscr.io/linuxserver/wireguard container_name: wireguard cpus: 4 cap_add: - NET_ADMIN environment: - PUID=1000 - PGID=1000 - TZ=Europe/Berlin volumes: - /opt/wireguard:/config - /lib/modules:/lib/modules ports: # Add ports here of other containers in the stack which you want to expose - 8080:80 # port forward of the whoami testcontainer sysctls: - net.ipv6.conf.all.disable_ipv6=1 # Recomended if using ipv4 only - net.ipv4.conf.all.src_valid_mark=1 restart: unless-stopped testcontainer: image: nginx network_mode: service:vpn depends_on: - vpn container_name: testcontainer restart: always networks: default: name: wireguard # Use this if you created the network elsewhere # external: true
Next, download the WireGuard configuration from your VPN provider. For my setup, I used Mullvad. From the available configurations (usually provided for different locations), select one and save it inside
Afterwards, modify the
wg0.conf file and add the
PreDown rules provided below. Essentially, these rules ensure that communication with internal networks outside the VPN remains intact. Without them, you wouldn't be able to access the exposed ports of your containers, such as dashboards.
I have taken this configuration from Linuxservers' blog.
Note that when using these specific routes in the WireGuard configuration, it's imperative that ports you want to forward for all your containers in the stack are explicitly specified in the VPN container. An example of this is how I specified port
8080 in the configuration above.
To verify your configuration, you can initiate a shell inside the container using:
docker exec -it testcontainer /bin/sh
For those using Portainer, there's a dedicated button for this purpose. Once inside, execute the following commands to test:
curl https://am.i.mullvad.net/connected # If you use mullvad curl ifconfig.me # to get the outgoing IP from the container
Furthermore, from outside your container, you should be able to run
curl 127.0.0.1:8080 to access the container's port.
By following the steps above, you can ensure that your containerized applications communicate securely via a trusted VPN.