Using Docker Compose and Tailscale VPN
This is a guide on how to add a VPN to the GAP docker compose stack.
Tailscale is a VPN solution based on the Wireguard protocol which lets you connect all devices within your virtual private network (tailnet). The Tailscale Docker container exposes the services only via a direct VPN connection, which avoids exposing ports to the open internet to connect to your geo-activity-playground instance on-the-go. It provides a domain with a valid Let's Encrypt certificate which is only accessible via the tailnet. The configuration is based on Docker Tailscale Guide.
The connection also requires an app on your remote device (phone). Install Tailscale
Tailscale Prerequisites
- Active account
- Enabled MagicDNS (in DNS section of admin console)
- Enabled HTTPS (in DNS section of admin console)
- Auth-Key
- ACL policy for tag
Create Auth-Key and ACL policy for tag
More information on generating auth keys Navigate to https://login.tailscale.com/admin/settings/keys and generate an auth key.
Example Auth-Key configuration:
- Description: docker
- Reusable: yes
- Expiration: 7 days
- Ephemeral: No
- Tags: tag:container
In order to use the tag, it must first be defined in your Access control policy in the admin console. Set the same tag as in the Auth-Key.
"tagOwners": {
"tag:container": ["autogroup:admin"],
},When you apply a tag to a device for the first time and authenticate it, the tagged device's key expiry is disabled by default.
Compose stack with Tailscale configuration
Like in the default docker compose install the compose project requires a directory, which includes the defining compose.yaml file. Additionaly a config directory is created for tailscale.
The base directory can also be in this directory e.g., /docker/geo-activity-playground/playground. The location can be changed in the compose.yaml.
The geo-activity-playground service will be made available by using the Tailscale Serve functionality. It routes traffic from other devices on your Tailscale network (known as a tailnet) to a local service, in this case inside the container. It creates a reverse proxy (for VPN-internal routing only) to the geo-activity-playground container internal port 5000 (do not change it). TS_CERT_DOMAIN is composed of a subdomain (hostname set in the compose.yaml) and the tailnet root domain given by Tailscale, eg. https://geo-activity-playground.tail41a3.ts.net/.
mkdir -p /docker/geo-activity-playground/{playground,config}/docker/geo-activity-playground/compose.yaml
configs:
ts-serve:
content: |
{"TCP":{"443":{"HTTPS":true}},
"Web":{"$${TS_CERT_DOMAIN}:443":
{"Handlers":{"/":
{"Proxy":"http://127.0.0.1:5000"}}}},
"AllowFunnel":{"$${TS_CERT_DOMAIN}:443":false}}
services:
geo-activity-playground-ts:
image: tailscale/tailscale:latest
container_name: geo-activity-playground-ts
hostname: geo-activity-playground # set your desired name, which will be the tailscale subdomain
environment:
- TS_AUTHKEY=tskey-auth-yyyyyyyyyyyyyyyyyyyyyyyyyyyy # paste your created Auth-Key
- TS_EXTRA_ARGS=--advertise-tags=tag:container # set the same tag used for the Auth-Key
- TS_STATE_DIR=/var/lib/tailscale
- TS_SERVE_CONFIG=/config/serve.json
configs:
- source: ts-serve
target: /config/serve.json
volumes:
- ts-data:/var/lib/tailscale
- ./config:/config
- /dev/net/tun:/dev/net/tun
cap_add:
- net_admin
- sys_module
restart: unless-stopped
geo-activity-playground:
image: ghcr.io/martin-ueding/geo-activity-playground:latest
container_name: geo-activity-playground
depends_on:
- geo-activity-playground-ts # start container after the VPN network is active
network_mode: service:geo-activity-playground-ts # link container network to tailscale container
volumes:
- /docker/geo-activity-playground/playground:/data # optional: change left side to your desired playground directory
restart: unless-stopped
volumes:
ts-data:
driver: localDownloading the image and running the container
cd /docker/geo-activity-playground
docker compose up -dThis will start the web server and expose it via your tailnet on https://[HOSTNAME].[YourTailnetName].ts.net/, e.g., https://geo-activity-playground.tail41a3.ts.net/. In order to access your instance via that domain, you have to install and authenticate the Tailscale client app on your device you want to open it from. Install Tailscale
If you also want to open GAP to your local network, use the following in the Tailscale container (geo-activity-playground-ts) section:
ports:
- "5000:5000" # access with http://DeviceIP:5000To only expose it to the machine it is running on, use "127.0.0.1:5000:5000" and access it with http://127.0.0.1:5000
Note that port 5000 may not be available on macOS because of AirPlay, so you can map to another host port e.g., "127.0.0.1:8000:5000".
Then you can open http://127.0.0.1:8000/ in your browser.
Stopping the containers
You can temporarily stop the container (it restarts on reboot with the option restart: unless-stopped) with:
docker stop geo-activity-playground
docker stop geo-activity-playground-tsand start again with:
docker start geo-activity-playground-ts
docker start geo-activity-playgroundTo permanently stop the docker compose stack, use:
cd /docker/geo-activity-playground
docker compose downUpdating the image and redeploy the container
cd /docker/geo-activity-playground
docker compose pull
docker compose up -d --force-recreate