Deployment
This guide shows how to run TokTagger on a shared server with Docker Compose. The file docker-compose.yml is the production stack.
What the stack contains
| Service | Purpose |
|---|---|
caddy |
Reverse proxy. It gets TLS certificates and it is the only service that publishes ports (80 and 443). |
api |
TokTagger, in the production image. It runs under uvicorn. |
keycloak |
The identity provider. It keeps the user accounts. |
postgres |
The database of Keycloak. |
mongo |
The database of TokTagger. |
TokTagger uses the oidc provider in this stack. The managed Canaille server is not used. For the sign-in flow, read the User Management guide.
Before you start
You need:
- A server with Docker and Docker Compose.
- Two DNS names that point to the server, for example
toktagger.example.comandauth.example.com. - Ports 80 and 443 open to the users. Caddy uses them to get and renew the certificates.
Install
-
Copy the example settings:
cp .env.example .env -
Edit
.env. Set the two host names. Replace each value markedCHANGEwith a long random string. Use letters and digits only. You can make a string withopenssl rand -hex 32.Warning
You cannot change these values after the first start. The databases keep the first values in their volumes, and
docker compose downdoes not remove the volumes. If you change a value and start the stack again, the stack stops working and it does not show a clear error. To change a value, stop the stack withdocker compose down -v. This command deletes all your data. -
Start the stack:
docker compose up -d --buildThe first start takes some minutes. Keycloak imports the realm
toktaggerat the first start. -
Open
https://<TOKTAGGER_HOST>and make sure that the page loads.
Create the first administrator
The realm has no users. Make the first user in Keycloak:
- Open
https://<KEYCLOAK_HOST>. Sign in with the useradminand the passwordKEYCLOAK_ADMIN_PASSWORD. - Click Manage Realms, then select the realm
toktagger. - Open Users and click Create new user. Enter the user name and the email address.
- Open the Credentials tab and set a password.
- Open the Groups tab and add the user to
toktagger-admins.
The user can now sign in to TokTagger as a global admin. To add other users, do the same steps without the group. See User Management for the roles.
Settings
| Variable | Meaning |
|---|---|
TOKTAGGER_HOST |
The public name of TokTagger |
KEYCLOAK_HOST |
The public name of Keycloak |
AUTH_SECRET_KEY |
The key that signs the TokTagger sessions. All workers use the same key. |
KEYCLOAK_CLIENT_SECRET |
The secret of the Keycloak client toktagger |
KEYCLOAK_ADMIN_PASSWORD |
The password of the Keycloak administrator |
POSTGRES_PASSWORD |
The password of the Keycloak database |
MONGO_USERNAME, MONGO_PASSWORD |
The credentials of the TokTagger database |
MONGO_VERSION |
The tag of the mongo image. The default is 8.0. MongoDB 8.x does not start on Linux kernels 6.19 to 7.0.13 (see SERVER-125742). On these kernels, set 7.0 before the first start. You cannot go back to an older version after MongoDB writes data to the volume. |
SERVER_WORKERS |
The number of uvicorn workers. The default is 4. |
TOKTAGGER_EXTRAS |
Set to models to install the optional machine learning packages in the image |
The api service sets SERVER_FORWARDED_ALLOW_IPS to *. Only Caddy can reach the api service, so this is safe. Do not publish the port of the api service.
Machine learning workers
When TOKTAGGER_EXTRAS is models, TokTagger starts Ray workers. The workers train models, load weights and make predictions. The server writes the predictions to the database when each task ends.
Each worker has an internal token. The token can only update the status and the progress of a model. It cannot read projects, and it cannot change samples, annotations or users.
Code runs in a worker when a weights file uses pickle. This code can read the data that the worker loads, and it can send a wrong model status. To decrease this risk on a shared server, do these steps:
- Set
MODELS_LOAD_SAFETENSORS_ONLY=true. Then the workers do not loadpicklefiles. - Set
MODELS_LOCAL_LOAD_ENABLED=false. The default istrue. - Keep the Ray workers on the same host as the
apiservice. If a worker is on a different host, use TLS between the worker and the API. The token goes in each request.
For the model settings, read Configuration.
Add custom data loaders and models
The production stack in docker-compose.yml runs the api service from the image toktagger:latest. That image does not contain your custom data loaders or custom models. To add them, make a new image from toktagger:latest, and use a Compose override file to run your script in the api service.
Step 1: Put your files in one folder
Make a folder custom next to docker-compose.yml. Put your modules and the script that starts the server in it. For example, for the database loader in Custom Data Loaders:
custom/
├── Dockerfile
├── loader.py
├── run.py
└── settings.py
You do not need to set the host or the port in run.py. The image sets SERVER_HOST=0.0.0.0 and SERVER_PORT=8002.
Step 2: Write the Dockerfile
FROM toktagger:latest
USER root
# Install the packages that your code needs
RUN pip --python /opt/venv/bin/python install --no-cache-dir sqlalchemy
COPY . /opt/custom
USER toktagger
CMD ["python", "/opt/custom/run.py"]
If your code needs no other packages, remove the RUN line.
Step 3: Write the Compose override file
services:
api:
build: !override
context: ./custom
image: toktagger-custom:latest
environment:
SQL_URL: ${SQL_URL:?}
Add the settings of your code to environment, and add their values to .env. For example, add SQL_URL=<Your URL> to .env.
Step 4: Start the stack
Build the TokTagger image first. Your image starts from it. For custom models, set TOKTAGGER_EXTRAS=models in .env before you build:
docker compose build api
docker compose -f docker-compose.yml -f docker-compose.custom.yml up -d --build
Do these two steps again after each update of TokTagger.
Warning
run.py starts the server with server.run(), which uses one Uvicorn process. The stack ignores SERVER_WORKERS for this server. Uvicorn workers import toktagger.api.cli:create_app and do not import your script, so they do not know your data loaders or models.
Data and backups
The stack keeps its data in these Docker volumes:
| Volume | Content |
|---|---|
mongo_data |
Projects, samples, annotations and users of TokTagger |
postgres_data |
The Keycloak accounts |
toktagger_data |
The TokTagger cache and the session signing key |
caddy_data |
The TLS certificates |
Back up mongo_data and postgres_data on a schedule.
Update
git pull
docker compose up -d --build
Test on one machine
Set TOKTAGGER_HOST=localhost and KEYCLOAK_HOST=keycloak.localhost. Caddy then makes certificates with its own authority, and the browser shows a warning. The script scripts/compose_smoke_test.sh starts the stack with these names and checks that the proxy, the sign-in redirect and the Keycloak issuer work. It removes the stack when it ends.
Warning
The test names are for tests only. Use real DNS names and valid certificates for a shared server.
Add test data
To make sure that the stack works, add test data with the setup scripts. The scripts write the data files into the data/ folder of the repository, and the server must read these files. The file docker-compose.test.yml attaches this folder to the api container as read-only. Start the stack with the two files:
docker compose -f docker-compose.yml -f docker-compose.test.yml up -d --build
Warning
Use docker-compose.test.yml only for tests. Do not attach the repository to a shared server.
Then sign in to TokTagger and make an API token (read User management). Then send the HTTPS address of TokTagger with --url.
On a server with a valid certificate:
TOKTAGGER_API_TOKEN=<API token> python scripts/create_mock_data.py --url https://<TOKTAGGER_HOST>
On one machine, Caddy signs the certificate with its own authority, and Python does not trust that authority. Copy the root certificate of Caddy from the container, and give it to Python with REQUESTS_CA_BUNDLE:
docker compose cp caddy:/data/caddy/pki/authorities/local/root.crt caddy-root.crt
REQUESTS_CA_BUNDLE=caddy-root.crt TOKTAGGER_API_TOKEN=<API token> python scripts/create_mock_data.py --url https://localhost
scripts/setup.py uses the same options.