onion-service
Creates a Tor .onion service for your Co-op Cloud applications
- Category: Apps
- Status: 3
- Image:
onimages/tor:alpine, 4, upstream - Healthcheck: Yes
- Backups: Yes
- Email: N/A
- Tests: No
- SSO: N/A
Basic Usage
- Set up Docker Swarm and [
abra] - Deploy [
coop-cloud/traefik] abra app new onionabra app config <onion-app>- You must at least set$TRAEFIK_SERVICEto the name of your traefik service. For example, if traefik's URL istraefik.example.com, this variable should be set totraefik_example_com_appabra app deploy <onion-app>- Retrieve the hostname of the created onion service:
abra app cmd <onion-app> app show_hostname - If your app's recipe supports an onion service, run
abra app config <app-name>on the app you would like the onion service to point to, and setONION_DOMAINto the output of the previous command. You can use sub-domains, likechat.xxx.onion
Backup and restore
Backups are disabled by default for this recipe because any meaningful backup will include the sensitive private key for your onion service. If this is stolen, an attacker could impersonate you to users of your service. To enable backups, set ENABLE_BACKUPS=true.
Fortunately, this key will not change unless you generate a new .onion, so regular automated backups are likely unnecessary; it should be perfectly fine to let backup bot take one snapshot to store in a secure location and then disable backups again.
Other useful data included in the backup includes the authorized_clients directory, so clients can still access your service after a restore.
After restoring a backup, make sure to run abra app restart <onion-app> app so Tor can advertise the restored hostname.
Enabling client authorization
Onion services allow you to use client authorization to prevent just anyone from accessing your service without your permission. To set this up, you need to first create a public/private keypair and then copy it to the authorized_clients folder in your app's HiddenServiceDir (in this case, /var/lib/tor/traefik/authorized_clients.
Assuming you followed the instructions from the linked tutorial to create your keypair, you can do this with echo "descriptor:x25519:$(cat /tmp/k1.pub.key)" > pubkey.auth && abra app cp <onion-app> pubkey.auth /var/lib/tor/traefik/authorized_clients/1.auth. You can replace 1.auth with any descriptive name as long as it ends in .auth. You may see a couple Operation not permitted errors, but this is expected, and the key will have been successfully copied.
After copying the file, run abra app restart <onion-app> app
Add support to another recipe
On a networking level, adding support for an onion service to your recipe is fairly simple. Add a file called compose.onion.yml to your recipe with the following lines:
services:
app:
labels:
- "traefik.http.routers.${STACK_NAME}-onion.rule=Host(`${ONION_DOMAIN}`)"
- "traefik.http.routers.${STACK_NAME}-onion.entrypoints=onion"
And, in .env.sample, add the following:
## Uncomment and set ONION_DOMAIN to enable onion service access
## Subdomains can also be used for ONION_DOMAIN, for example, chat.< ... >.onion
# COMPOSE_FILE="$COMPOSE_FILE:compose.onion.yml"
# ONION_DOMAIN=<56-char onion address>.onion
This creates a new traefik router for your recipe that recognizes the .onion domain requested by the client and routes requests to your application, bypassing forced SSL.
On the application level, there may sometimes be some tinkering required to get an app to truly work with an onion service. Common issues relate to apps themselves forcing SSL, or expecting a specific domain name.