Docker (recommended)

The recommended way to deploy Tether. Docker Compose starts both the app and MariaDB with one command, handles networking between them, and ensures consistent behaviour across environments.

Only the official image is supported

The only Docker image we provide and support is the one built from the Dockerfile in the repository. Third-party images are not tested and may behave differently.

Prerequisites

Install

1

Clone the repository

Clone into a directory of your choice. The directory name is used as a prefix for container names.

bash
git clone https://github.com/atechlab-am/tether cd tether
2

Create your .env file

Copy the example and edit it. At minimum, set SECRET_KEY, ADMIN_PASSWORD, BASE_DOMAIN, and your database passwords.

bash
cp .env.example .env nano .env
3

Start the application

Compose starts MariaDB first, waits for it to pass a healthcheck, then starts the Tether app. The first boot takes 15–30 seconds.

bash
docker compose up -d
4

Verify it's running

bash
docker compose ps # Both "tether-db" and "tether-app" should show status "Up" docker compose logs -f app # Watch for: "Application startup complete"

What gets started

ServiceContainer nameImagePortPurpose
dbtether-dbmariadb:113306 (internal only)MariaDB database — not exposed outside the server
apptether-appBuilt from Dockerfile8000Tether web application — exposed to your server

The two containers communicate over an internal Docker network. MariaDB port 3306 is not exposed to the internet — only the Tether app container can reach it.

Volumes and data persistence

Tether uses two named Docker volumes to persist data across restarts and container rebuilds:

VolumeContentsLocation on host
tether_dbMariaDB data directory — all database filesdocker volume inspect tether_db
tether_dataApp data directory — SQLite fallback, other app filesdocker volume inspect tether_data
Do not delete volumes unless you want to lose all data

Running docker compose down -v deletes volumes and their contents permanently. There is no confirmation prompt. Use docker compose down (without -v) to stop containers while preserving data.

Useful commands

All commands must be run from the directory containing docker-compose.yml.

bash
# Check container status docker compose ps # Stream app logs docker compose logs -f app # Stream database logs docker compose logs -f db # Stop containers (data preserved) docker compose down # Stop and DELETE all data (irreversible!) docker compose down -v # Restart just the app (after config change) docker compose restart app # Open a shell inside the app container docker compose exec app bash # Connect to MariaDB CLI docker compose exec db mariadb -u tether -ptether tether

Updating Tether

Always back up your database before updating. See Backup & restore.

bash
# 1. Pull the latest code git pull # 2. Stop just the app (keep the database running) docker compose stop app # 3. Rebuild the app image docker compose build --no-cache app # 4. Start the updated app docker compose start app # 5. Check logs to confirm startup docker compose logs -f app

Schema changes (new tables, new columns) are applied automatically on startup by SQLAlchemy. Check the release notes for any version that requires a manual migration step.

Changing the port

By default Tether is exposed on port 8000. To change it, edit the ports section in docker-compose.yml:

yaml
services: app: ports: - "80:8000" # Now accessible on port 80

For production, use a reverse proxy on ports 80 and 443 instead of exposing Tether directly. See Reverse proxy & HTTPS.

Behind a reverse proxy

If you put nginx or Caddy in front of Tether, you must pass the real Host header through to the app — Tether uses this header to determine which tenant to scope requests to. A missing or incorrect Host header will break tenant routing.

nginx
# Critical: pass Host header through proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;

See the full nginx configuration in Reverse proxy & HTTPS.

Last updated: May 2026