Now that we have our services protected with Authelia I still don't feel too confortable having management stuff like phpmyadmin exposed to the outside. After thinking about this I found a simple solution that ticks two things that I wanted to do:

  • Have a simple way to VPN to my server
  • Access management containers only from VPN

Since our databases are already unplugged from the internet we will do the same for the GUI we use to manage them.

First edit your docker compose file and on phpmyadmin and rediscommander remove all labels and remove the Traefik network leaving them only with the database network.

Wireguard

Wireguard is an extremely simple yet fast and modern VPN. It's also very simple to set up as you'll see below.

Add this to your docker compose file

  wireguard:
    image: linuxserver/wireguard
    container_name: wireguard
    networks:
      - database
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    security_opt:
      - no-new-privileges:true
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - SERVERURL=$WIREGUARD_SUBDOMAIN.$DOMAINNAME1
      - SERVERPORT=51820
      - PEERS=1
      - PEERDNS=auto
      - INTERNAL_SUBNET=10.13.14.0
    volumes:
      - wireguard:/config
      - /lib/modules:/lib/modules
    ports:
      - 51820:51820/udp
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
    restart: unless-stopped

There are some new options in this service that I will try to explain.

By default docker containers are "unprivileged" and can't access anything outside of the container itself. You can however run a container in "privileged mode" (like our socket proxy) to get around this.

You also can specify what they can access in privileged mode in a more granular form by using the option CAP_ADD. This basically adds a new capability to a container so it can access a specific function.

In this service we add NET_ADMIN and SYS_MODULE.

According to docker documentation the NET_ADMIN option adds the ability to perform various network related operations and the SYS_MODULE option adds the ability to load and unload kernel modules.

We also give the container access to those modules by mounting the /lib/modules directory.

The sysctls section is nothing more than allowing the container to add a specific network configuration. The configuration stated is needed for wireguard to fucntion properly. I will not go into much detail because I would have to explain how iptables works and it would not only be off topic but it would make the post extremely long.

Add the WIREGUARD_SUBDOMAIN to your .env file and add the volume wireguard to the volume section on your docker compose file.

After starting Wireguard if you run sudo docker-compose logs wireguard you will see the QR codes that were generated for the number of peers you specified. You can use the codes to set up a connection on your smartphone more easily.

If you need to add more peers later you just edit the PEERS value and recreate the container. If you just want to see the QR again you can run docker exec -it wireguard /app/show-peer 1 or whatever peer number you want and it will be displayed in the command line.

If you want to retrieve the configuration file for a peer change to root and look in the directory /var/lib/docker/volumes, in your wireguard volume directory there is a peer1.conf you can use to set up the service more easily if using a device that does not read QR codes.

To finalize just allow port 51820 UDP on your firewall with

sudo ufw allow 51820/udp 

Run sudo docker-compose up -d and then run sudo docker-compose logs wireguard to see the QR code. Scan it with the wireguard app on your phone, give it a name and that's it.

You can now access your server through VPN easily.

Now we have to configure the apps that we will access only through the VPN.

For now there are only two. PHPMyAdmin and Redis Commander.

First go to your docker compose and delete all the labels for each service. Then change both of them to be on your database network only and finally give each of them a different static IP address. It should look like below:

networks:
  database:
    ipv4_address: 20.20.10.200

You can change the IP address to one of your choosing.

Next we will take advantage of core dns running inside the wireguard container.

Create a new directory in your apps directory called wireguard and create a file called Corefile inside. Enter the following:

. {
    loop
    forward . /etc/resolv.conf
}

phpmyadmin.example.com:53 {
    file phpmyadmin.example.db
    log
    errors
}

redis.example.com:53 {
    file redis.example.db
    log
    errors
}

Replace phpmyadmin.example and redis.example with the url you want for each service.

The first part of this file is what would already exist inside the wireguard docker container and basically it acts as a forwarder to the host's DNS. Next we added a new entry for each of the services you want to access through the VPN. Because it's a more specific entry the domain name specified will be resolved here instead of the host. We have to create one for each service. The reason I didn't use something more generic as the example.com domain is because when connected to the VPN you wouldn't be able to access your public apps without entering them all in the container's DNS records.

Now create a file for phpmyadmin called phpmyadmin.example.db (change it to what you chose above) in the same directory and enter the following:

phpmyadmin.example.com.        IN  SOA phpmyadmin.example.com. youremail.example.com. 20200826 7200 3600 1209600 3600phpmyadmin.example.com.    IN  A   20.20.10.200

Again edit everything above to match what you have. You can also change 20200826 to any code you like. This is just a serial number. I usually use the date I create the file like above.

Do the same for redis commander,  create a file called redis.example.db and enter the following:

redis.example.com.        IN  SOA redis.example.com. youremail.example.com. 20200826 7200 3600 1209600 3600redis.example.com.    IN  A   20.20.10.201

We have a small difference with redis commander because it's not listening on port 80 like phpmyadmin. So we have to add the port number to the URL to reach it. I tried solving this with a SRV file but it didn't work. If you know of a way to do this please let me know.

Change ownership and permissons of these files so they can only be accessed as root.

sudo chown root:root ~/docker/apps/wireguard 
sudo chmod 600 ~/docker/apps/wireguard

Finally add this directory as a bind mount to your wireguard container in the volumes section:

- $DOCKERDIR/apps/wireguard:/config/coredns

Run sudo docker-compose up -d and that's it.

If you go to a browser after connecting the VPN and input the URL you defined above you can reach your management containers.

For more information on Wireguard please visit their website.

We now have three different ways of accessing our services. No authentication (only for services that have built in 2FA), 2FA with Authelia and through VPN with Wireguard.

Actually four because you can also access container via browser by their container name. The DNS entry is just so you don't have to know all container names by heart.

Happy VPNning. Until we meet again...