Talos backend API + job processor - self-hosted DevOps control plane for servers, K8s, clouds
391
The API and job processor for Talos, a self-hosted DevOps control plane for managing Frappe/ERPNext infrastructure, servers, containers, Kubernetes, databases and the four major clouds from one place.
This image is not usable on its own. It needs PostgreSQL (with the
pgvectorextension) and Redis. Use the Compose stack below rather thandocker run.
Create docker-compose.yml:
services:
postgres:
image: pgvector/pgvector:pg16 # NOT plain postgres — pgvector is required
environment:
POSTGRES_DB: talos
POSTGRES_USER: talos
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set it in .env}
volumes: [talos_postgres:/var/lib/postgresql/data]
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U talos -d talos']
interval: 10s
retries: 5
redis:
image: redis:7-alpine
volumes: [talos_redis:/data]
backend:
image: talosfleet/talos-backend:latest
restart: unless-stopped
ports: ['3001:3001']
environment:
DATABASE_URL: postgresql://talos:${POSTGRES_PASSWORD}@postgres:5432/talos?schema=public
REDIS_URL: redis://redis:6379
JWT_SECRET: ${JWT_SECRET:?set it in .env}
ENCRYPTION_KEY: ${ENCRYPTION_KEY:?set it in .env}
FRONTEND_URL: http://localhost:3000
volumes: [talos_terraform:/app/infra/terraform/workspaces]
depends_on:
postgres: {condition: service_healthy}
redis: {condition: service_started}
frontend:
image: talosfleet/talos-frontend:latest
ports: ['3000:3000']
environment:
# The backend as the FRONTEND CONTAINER sees it, not the address users type.
BACKEND_INTERNAL_URL: http://backend:3001
depends_on: [backend]
volumes: {talos_postgres:, talos_redis:, talos_terraform:}
Create .env — three values, and the commands to generate them:
POSTGRES_PASSWORD= # openssl rand -base64 24
JWT_SECRET= # openssl rand -base64 32
ENCRYPTION_KEY= # openssl rand -base64 24
Then:
docker compose up -d
Open http://localhost:3000 and complete the first-run setup to create your administrator account and organization.
The first start takes a minute or two — the container applies the database schema and
loads the permission catalogue before accepting traffic. Follow it with
docker compose logs -f backend. You are ready when you see:
[Mode] SELF_HOSTED (self-hosted) — registration=false, multiOrg=false, billing=false
ENCRYPTION_KEY with your databaseEvery SSH key, cloud credential and database password Talos stores is encrypted with it. It cannot be changed once you have data, and there is no recovery path — a database backup without this key is unreadable.
Store it wherever you keep your database backups, not only in .env on the server.
| Variable | Notes |
|---|---|
DATABASE_URL | PostgreSQL 14+ with the pgvector extension |
REDIS_URL | Inside Compose use the service name (redis://redis:6379), not localhost |
JWT_SECRET | The container refuses to start if missing or left at a default |
ENCRYPTION_KEY | Same. See the warning above |
| Variable | Default | Notes |
|---|---|---|
FRONTEND_URL | http://localhost:3000 | Used in links inside emails |
ALLOW_SELF_REGISTRATION | false | Accounts are invitation-only by default |
ALLOW_MULTI_ORG | false | Set true to run several teams on one install |
MAIL_TRANSPORT | log | Without SMTP, invite/reset links go to the container log |
SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASSWORD / MAIL_FROM | — | Outbound email |
OAUTH_GOOGLE_ENABLED / OAUTH_GITHUB_ENABLED | false | Sign in with Google/GitHub |
OAUTH_CALLBACK_BASE_URL | — | Required when a provider is enabled |
Sign-in with Google or GitHub: register the app with the provider first and set the
callback to <your API URL>/auth/oauth/<provider>/callback exactly. A mismatch is the
most common cause of a flow that fails with no useful message. The container refuses to
start if a provider is enabled without credentials, rather than showing a button that
cannot work.
docker compose pull
docker compose up -d
Database migrations run automatically at startup and are idempotent, so this is safe to repeat and safe to interrupt. Take a backup first anyway:
docker compose exec postgres pg_dump -U talos talos > talos-$(date +%F).sql
For production, pin a version rather than tracking latest — otherwise you upgrade
whenever you happen to pull:
image: talosfleet/talos-backend:1.0.0
The backend restarts over and over and nothing answers on port 3001. Almost always
JWT_SECRET or ENCRYPTION_KEY missing or still a placeholder. It refuses to start and,
because it restarts automatically, you see a loop rather than one clear failure:
docker compose logs backend | grep -A 8 "Refusing to start"
The message names which value is wrong and how to generate it. This is deliberate — the fallback values are published, so an install using them has forgeable login tokens and credentials encrypted under a key anyone can look up.
Compose refuses to start, naming a variable. A required value is missing from .env.
Nothing was created, so fill it in and retry.
The frontend loads but every request fails. There is no API address to configure — the
browser calls the frontend on a relative /api and the frontend forwards to this container,
so it works at any hostname. If requests still fail, the frontend cannot reach the backend:
check docker compose ps and that its BACKEND_INTERNAL_URL is the backend's service name.
Set FRONTEND_URL to the address your users type. It does not affect whether the app works,
only the links inside invitation and password-reset emails.
Invite and password-reset emails never arrive. Without SMTP, those links are written to
the log: docker compose logs backend.
Login hangs or returns an empty response. Usually a stale REDIS_URL. Inside Compose
the hostname is redis, not localhost. Recreate rather than restart so the change is
picked up:
docker compose up -d --force-recreate backend
ALLOW_MULTI_ORG=true and
ALLOW_SELF_REGISTRATION=true to run several teams.| Tag | Meaning |
|---|---|
latest | Most recent release. Convenient for a lab, not recommended for production |
1.0.0 | |
1.0.1 | Pinned release. Use this in production |
Images carry the source commit as GIT_SHA — docker run --rm <image> sh -c 'echo $GIT_SHA'.
Runs as a non-root user (nestjs, uid 1001). Health endpoint: GET /api/health.
Content type
Image
Digest
sha256:19b7ba738…
Size
433.1 MB
Last updated
about 1 month ago
docker pull talosfleet/talos-backend:sha-8bf951c