Octopize Avatar Deployment Tool
octopize-deploy-tool configures, generates and operates a self-hosted Octopize
Avatar deployment. It asks you a questionnaire, renders a complete Docker
Compose stack (.env, docker-compose.yml, nginx config, secrets, SSO blueprints) into a
versioned directory tree, and manages that stack's lifecycle. Deployment templates for each
release ship inside the package, so nothing is fetched at runtime.
Requirements
On the host that will run Avatar:
- A Linux server — Ubuntu 22.04 LTS or later is recommended.
docker(with the Compose plugin) andcurl.- The deploying user in the
dockergroup — see Docker's post-installation steps. - A domain name pointing at the host, plus a TLS certificate and private key for it. Both are
required for HTTPS; for internal or test deployments the tool can generate a self-signed
certificate (see
tasks). - Inbound access to port
443when TLS is enabled, or toNGINX_HTTP_PORT(default8080) when it is not.
To run the CLI itself you need Python 3.12 or newer, or the published Docker image (see Running via Docker). Older Python versions fail with an opaque dependency resolution error. The published image ships Python 3.14; the wider floor is kept so the CLI still installs on the older interpreters an operator is likely to already have.
Docker proxy gotcha. If your Docker daemon or client is configured with an HTTP proxy, the Avatar containers silently fail to reach each other. Exclude the Compose subnet by adding
"noProxy": "172.18.0.0/16"to theproxies.defaultblock of/etc/docker/daemon.jsonor~/.docker/config.json. The setting applies to newly created containers only.
Quick start
Install uv if you do not have it, then run the tool straight from PyPI — no permanent install needed:
curl -LsSf https://astral.sh/uv/install.sh | sh
uvx octopize-deploy-tool --help
Alternatively, pip install octopize-deploy-tool inside a virtual environment (most
distributions refuse installs into the system Python, per PEP 668) puts octopize-deploy-tool on
your PATH — the form used below. A complete first deployment:
# Answer the questionnaire and generate all deployment files.
octopize-deploy-tool install --app-root ./app/avatar
# Bring the stack up.
octopize-deploy-tool start --app-root ./app/avatar
# Create the accounts your users will log in with.
octopize-deploy-tool tasks create-users --app-root ./app/avatar \
--admins admin@company.com --users alice@company.com,bob@company.com
# Provision the admin API key that `verify` reads.
octopize-deploy-tool tasks provision-admin --app-root ./app/avatar
# Check the API is healthy and email delivery works.
octopize-deploy-tool verify --app-root ./app/avatar --test-email you@company.com
These are the five commands the end-to-end suite runs, in this order, before tearing the
deployment down with uninstall. Two ordering constraints matter: create-users needs Authentik
to be up, and provision-admin must run before verify. Both hold once start has finished.
Command reference
--app-root defaults to the current directory everywhere it is accepted, and must be a directory
the invoking user can read, write and enter — every command refuses a root-owned or otherwise
inaccessible root up front rather than failing part-way through. It does not have to exist yet, as
long as its parent is writable. Every command and tasks sub-command takes --verbosity {1,2},
where 1 is essential (the default) and 2 is verbose. Every command's --help lists its full
option set.
Everyday commands
Which of install, update and migrate you need is decided by what your deployment
directory already contains, so the table names that rather than a term only this tool uses:
| Command | Use when |
|---|---|
install |
Setting up a new Avatar deployment for the first time, in an empty directory |
update |
Upgrading to a newer Avatar release, or changing a configuration value, on a deployment that already has a .deployment_states/ directory |
migrate |
Adopting a deployment that has .env and .secrets/ at its top level and no .deployment_states/ — anything set up by hand, or by the deploy command of a tool older than 2.7.0 |
start |
Bringing a configured deployment live, or restarting it after a host reboot |
stop |
Suspending the stack temporarily — containers and volumes are preserved |
uninstall |
Permanently destroying the deployment and all of its data |
If you point update or install at a directory of the second shape they stop and tell you to
run migrate — running install there would generate a fresh configuration instead of adopting
the one you already have.
install
Runs the full questionnaire, generates every deployment file, and leaves the stack ready to
start. It starts nothing — run start afterwards.
--app-root PATH Deployment root directory (default: current directory)
--from-config PATH Seed configuration from a YAML config file
--non-interactive Run without prompts; uses defaults or the config file
--verbosity {1,2} 1 = essential (default), 2 = verbose
Before doing anything, install checks the app root itself. If it holds .env and .secrets/
at the top level and no .deployment_states/, that is a deployment predating the versioned
layout, and installing over it would generate a fresh configuration rather than adopt it, so the
run stops:
✗ /app/avatar looks like a pre-versioned deployment (.env and .secrets/ at the top level, no
.deployment_states/). Import it once with:
octopize-deploy-tool migrate --app-root <new-app-root> --from-legacy /app/avatar
then use 'update' for subsequent releases.
⚠ Install aborted during pre-flight checks.
Next, install looks for Avatar Docker volumes left over from an earlier
deployment. If it finds any it refuses to run, in both interactive and non-interactive mode:
⚠ Volume 'avatar_postgres_data' already exists.
✗ A fresh install generates new credentials, and Postgres ignores them on a volume that already
holds a database — the API and Authentik would not be able to start. Choose one of:
• Keep the data — you need the deployment that created it. Run 'update' against its app root,
or 'migrate --from-legacy' if it predates the versioned layout. Without its .secrets/ the
data cannot be read.
• Discard the data — run 'uninstall' against the old app root, or remove the volumes by hand:
docker volume rm avatar_postgres_data
⚠ Install aborted during pre-flight checks.
There is deliberately no override. A fresh install writes new secrets, but Postgres only applies
POSTGRES_USER/POSTGRES_PASSWORD while initialising an empty data directory — on a volume
that already holds a cluster they are silently ignored, so nothing can authenticate and the stack
never comes up. The volume names are fixed, so a collision is always this deployment's own data.
The expert commands (configure, render, apply) do not run this check.
update
Re-runs the configuration from your current state, re-renders every file with the templates
bundled in the installed version of this tool, shows a diff, and applies it. Values you already
answered are carried forward, so you are not asked again. --from-config PATH layers a YAML file
over the current state (see Changing a configuration
value). It needs a .deployment_states/ directory to read that
state from; against a directory that has .env and .secrets/ at the top level instead, it stops
and points you at migrate.
octopize-deploy-tool update --app-root ./app/avatar
octopize-deploy-tool start --app-root ./app/avatar # restart with the new files
That start also re-applies the Authentik blueprint, so a changed SSO configuration takes
effect — see tasks reconcile-blueprint.
If you edited anything under generated_files/ by hand, update shows the diff and asks per
file. The default is no — your file is kept — and keeping any file blocks the apply, so
update exits non-zero:
Accept new render for '.env' and discard your manual changes? [y/N]
⚠ .env: keeping your manual changes — apply aborted for this file.
⚠ One or more files were kept. Apply is blocked until conflicts are resolved.
Merge manually, then run: octopize-deploy-tool apply --version <vX>
Merge your edits into the rendered copy in .deployment_states/<vX>/generated/, then run
apply --version <vX>. Anything that should survive future updates belongs in a config file, not
in generated_files/.
Two files never come from a render, so apply carries them across untouched rather than
replacing them with the copy: the API key and the two JWTs that tasks provision-admin writes to
generated_files/.secrets/avatar_api_key, avatar_access_token and avatar_refresh_token.
Anything else you leave in generated_files/ is replaced.
Python client compatibility
install, update and migrate each deploy a specific Avatar API version, and no single python
client works with every one of them — so an update can break the notebooks and scripts your users
already have. Each of those commands ends by naming the clients that work with the version it just
deployed:
Python client compatibility
This deployment now runs Avatar API 3.2.3.
Latest compatible python client: 1.28.0 (pip install 'octopize.avatar==1.28.0')
Clients older than 1.26.0 will stop working — tell your users before they next run a job.
When an update does not move the API version at all — a tool-only bump — this collapses to a
single reassuring line instead.
The table is fetched from COMPATIBILITY_MAPPING_URL (see
config.example.yaml; point it at your own mirror if you are
air-gapped). This is advisory output: if the URL cannot be reached the command warns once and
carries on — a deployment never fails because a version table was unavailable. To check
compatibility as a hard gate, use verify.
start and stop
start creates any missing Docker volumes and brings all services up. It is idempotent, so it is
also how you restart after a reboot or after update. stop suspends the services without
removing containers or volumes.
octopize-deploy-tool stop --app-root ./app/avatar
uninstall
Destructive and irreversible. Stops and removes all containers and networks, deletes every
Docker volume including the database and uploaded files, and removes generated_files/,
.deployment_states/ and user_config/. You are asked to confirm first; --force skips the
prompt for scripted use, and --non-interactive requires --force.
octopize-deploy-tool uninstall --app-root ./app/avatar
migrate
Adopts a deployment whose directory holds .env and .secrets/ at the top level and has no
.deployment_states/ — anything set up by hand, or by the deploy command of a tool older than
2.7.0. Point --from-legacy at that directory; values readable from there are carried over and
you are prompted for the rest. If --from-legacy is omitted the tool asks for it interactively.
octopize-deploy-tool migrate --app-root ./app/avatar-new --from-legacy ./app/avatar-old
octopize-deploy-tool start --app-root ./app/avatar-new
Before applying anything, migrate shows you the diff between your existing directory and the new
render, led by the service versions that change:
Service versions (5 changing):
AVATAR_API_VERSION 2.55.0 → 3.2.3
AVATAR_PDFGENERATOR_VERSION 0.2.0 → (removed)
AVATAR_WEB_VERSION 0.38.0 → 0.65.1
Expect a large first diff — the layout itself changes, pdfgenerator goes away (the report
generator is now embedded in the API), and the services jump every release at once. Conflicts
default to accepting the new render, since the legacy directory is what migrate replaces;
answering "keep" for a file is still honoured and still blocks the apply.
migrate also creates user_config/ under the new app root, so a migrated deployment is shaped
exactly like an installed one and update --from-config works the same way on both.
Before migrating non-interactively, make sure the legacy
.envsetsSMTP_HOST(or passUSE_AWS_SMTP_PRESET: true), and setsNGINX_SSL_CERTIFICATE_PATHandNGINX_SSL_CERTIFICATE_KEY_PATHto paths that exist. Otherwise the run falls back to a relative built-in default and keeps it with a warning that the path is "not usable yet" — the migration completes, but nginx will not start until a certificate and key exist at those paths, and--non-interactiveoffers no way to supply one. A path you set that does not exist is a hard error instead.A relative path in that
.env—./tls/server.fullchain.crt— is read relative to the--from-legacydirectory it was written for, whichever directory you runmigratefrom, and is recorded as an absolute path in the new deployment. The exception is running the tool from the Docker image, where those paths belong to the host and are recorded exactly as written; see Running via Docker.
See Upgrading from a pre-SSO deployment for what happens to existing user accounts.
tasks
One-off operational sub-commands. All are idempotent and safe to re-run.
| Task | Purpose |
|---|---|
provision-admin |
Creates the Avatar API key that verify reads |
create-users |
Creates Authentik accounts and emails each user a setup link |
reconcile-blueprint |
Re-applies the deployed Authentik blueprint to the running stack |
create-self-signed-cert |
Generates a self-signed TLS certificate and key |
authentik-migrate |
Imports users and organizations from Avatar into Authentik SSO |
tasks provision-admin
Waits for Authentik and the Avatar API to become healthy, grants akadmin the admin role, logs
in through Authentik's flow executor, creates an Avatar API key and writes it to
generated_files/.secrets/avatar_api_key. verify fails without it. Re-running when the key
file exists is a no-op; delete the file to force a rotation.
tasks reconcile-blueprint
Forces Authentik to apply the blueprint deployed under generated_files/authentik/ and waits for
that apply to succeed. start runs it after an update, so you normally never call it yourself —
run it if that step failed or was interrupted, which is when start prints this command.
octopize-deploy-tool tasks reconcile-blueprint --app-root ./app/avatar
An update changes what Authentik should be serving in two ways it cannot pick up by itself. A
rewritten blueprint file is invisible to the containers that are already running, because a
bind-mounted file stays pinned to the one they started with — so start recreates them after an
update. A changed value the blueprint reads from the environment leaves the file untouched, and
Authentik only re-applies a blueprint whose content changed — so the apply has to be forced.
Either way nothing is reported as failed, which is why this runs unprompted. Applying an
already-correct blueprint changes nothing.
tasks create-users
Creates accounts in Authentik using the bootstrap token from generated_files/.env, assigns each
to the right group, and sends a branded recovery email so users set their own password without
server-side browser access. Run it once the stack is up: the command does no readiness wait of
its own, so Authentik must already be running with its blueprint applied. Existing users are
detected and skipped.
Account creation and email delivery are independent — if the mail fails the account still exists,
so a re-run skips that user. --no-email creates accounts silently. --authentik-url and
--authentik-token override the values read from .env.
tasks create-self-signed-cert
Writes fullchain.crt (0644) and server.key (0600) for a domain, one or more IP addresses,
or both. At least one of --domain or --ip-address is required — with neither, the command
fails with Either --domain or --ip-address must be provided. --output-dir is created if
missing (default: current directory) and existing files are overwritten after a warning.
--valid-days defaults to 365.
octopize-deploy-tool tasks create-self-signed-cert \
--domain avatar.company.com --ip-address 192.168.1.10 --output-dir /etc/nginx/certs
tasks authentik-migrate
Imports users, organizations and licenses from an existing Avatar database into Authentik. For a
supported migrate you normally never run this by hand — see Upgrading from a pre-SSO
deployment.
Expert commands
install, update and migrate are compositions of three lower-level commands. Use them
directly when you want to inspect or stage a change before it goes live.
| Command | What it does |
|---|---|
configure |
Answers the questionnaire, saves .deployment_states/vX/deployment_state.yaml |
render |
Turns a saved state into files under .deployment_states/vX/generated/ |
apply |
Copies a rendered version into generated_files/ and moves currently_deployed |
diff |
Shows what would change between two rendered versions |
verify |
Checks the running stack: API health plus a live email test |
Each configure run creates a new version slot, so previous answers are never overwritten.
Nothing you do with configure or render touches the running deployment until apply runs.
octopize-deploy-tool configure --app-root ./app/avatar --from-state v1
octopize-deploy-tool render --app-root ./app/avatar --latest
octopize-deploy-tool diff --app-root ./app/avatar deployed latest
octopize-deploy-tool apply --app-root ./app/avatar --version v2
configure also accepts --from-config PATH, --from-legacy DIR, --resume (continue an
interrupted session) and --fresh (force a new slot). render takes --version vX or
--latest; apply requires --version vX. diff prints a per-file unified diff and prompts
for each conflict exactly as update does; it takes positional refs — diff v3, diff v2 v3,
diff deployed latest — or raw paths via --from / --to, and exits 0 when the versions are
identical or every conflict was resolved, 1 when any file was skipped.
verify hits the Avatar API /health/config-full-check endpoint and sends a test email through
the authentik_worker container. --test-email is required, the stack must be running, and
tasks provision-admin must have run first — otherwise it reports API key not found in .../generated_files/.secrets/avatar_api_key. Run 'tasks provision-admin' first. Use --api-key
to supply a key instead of reading one from disk.
Changing a configuration value
Put the values you want to change in a YAML file and hand it to update. They are layered over
your current configuration: the keys you list win, everything else is carried forward unchanged.
# change.yaml holds only NGINX_SSL_CERTIFICATE_PATH and NGINX_SSL_CERTIFICATE_KEY_PATH
octopize-deploy-tool update --app-root ./app/avatar --from-config change.yaml
octopize-deploy-tool start --app-root ./app/avatar
Do not edit files under generated_files/ — they are regenerated on every update, and an edit
there becomes a conflict prompt that blocks the next apply.
Configuration file
install writes a commented reference to user_config/config.example.yaml under the app root.
Copy it and fill in what you need: only the keys you set are used, everything else falls back to
the built-in defaults. Its sections are PUBLIC_URL and ENV_NAME, then commented-out blocks for
TLS and nginx, SMTP, service image versions, logging and telemetry.
Two things the example does not tell you:
ORGANIZATION_NAMEis missing from it and is required. A--non-interactiverun without it stops atORGANIZATION_NAME is required but not provided in configuration file. Add it yourself, as below.SMTP_HOSTis required too, unless you setUSE_AWS_SMTP_PRESET: trueto take the AWS SES settings Octopize provides. The example sets it; a--non-interactiverun with neither stops at'SMTP_HOST' is required and no value was provided.- The TLS keys the tool reads are
NGINX_SSL_CERTIFICATE_PATHandNGINX_SSL_CERTIFICATE_KEY_PATH. Use those spellings.
Storage credentials are not configurable at all — the encryption key and the S3 admin keys are
generated for you into generated_files/.secrets/.
A minimal file that installs unattended, and how to use it:
PUBLIC_URL: avatar.example.com
ENV_NAME: company-prod
ORGANIZATION_NAME: MyCompany
NGINX_SSL_CERTIFICATE_PATH: /etc/ssl/avatar/server.crt
NGINX_SSL_CERTIFICATE_KEY_PATH: /etc/ssl/avatar/server.key
octopize-deploy-tool install --app-root ./app/avatar \
--from-config ./app/avatar/user_config/config.yaml --non-interactive
If exactly one *.yaml or *.yml file other than config.example.yaml sits in user_config/
and --from-config was not given, install and update behave identically: interactively
they ask whether to use it, non-interactively they print a notice and ignore it. Automated
runs should always pass --from-config explicitly.
Generated files layout
./app/avatar/
├── .deployment_states/
│ ├── currently_deployed -> v1 # symlink, moved by `apply`
│ └── v1/
│ ├── deployment_state.yaml # the answers, with the source of each value
│ └── generated/ # render staging area; `apply` copies out of here
├── user_config/ # operator-owned; never overwritten by the tool
│ ├── config.example.yaml
│ ├── config.yaml # optional, yours to create
│ └── hooks/ # reserved for future lifecycle hooks
└── generated_files/ # what Docker Compose actually uses
├── .env
├── docker-compose.yml
├── nginx/nginx.conf
├── authentik/
│ ├── octopize-avatar-blueprint.yaml
│ ├── translations.json
│ ├── custom-templates/
│ └── branding/
└── .secrets/ # 18 generated secret files
Every update and migrate adds a new version slot (v2/, v3/, …), so previous states and
renders stay on disk for reference and rollback.
Running via Docker
If Python 3.12+ is unavailable, or PyPI is blocked while quay.io is not, use the published
image:
docker pull quay.io/octopize/deploy-tool:latest
Each block below is complete. Copy it as-is, changing only avatar (your deployment
directory) and any value in <angle brackets>. The first line reads your Compose plugin path,
which must be mounted at the same location inside the container.
Install — interactive
export CP=$(docker info -f '{{range .ClientInfo.Plugins}}{{if eq .Name "compose"}}{{.Path}}{{end}}{{end}}')
docker run -it --rm --user "$(id -u):$(id -g)" --group-add "$(stat -c '%g' /var/run/docker.sock)" \
-v "$(pwd)/avatar:/app-root" -v /var/run/docker.sock:/var/run/docker.sock \
-v "$(which docker):/usr/local/bin/docker:ro" -v "$CP:$CP:ro" \
quay.io/octopize/deploy-tool:latest install --app-root /app-root
Install — no prompts
export CP=$(docker info -f '{{range .ClientInfo.Plugins}}{{if eq .Name "compose"}}{{.Path}}{{end}}{{end}}')
docker run --rm --user "$(id -u):$(id -g)" --group-add "$(stat -c '%g' /var/run/docker.sock)" \
-v "$(pwd)/avatar:/app-root" -v /var/run/docker.sock:/var/run/docker.sock \
-v "$(which docker):/usr/local/bin/docker:ro" -v "$CP:$CP:ro" \
quay.io/octopize/deploy-tool:latest install --app-root /app-root \
--from-config /app-root/user_config/config.yaml --non-interactive
Start
start pulls the images the deployment needs, and two of them are private. The
credentials docker login writes belong to the Docker client, so the login you did on
the host is invisible to the client in this container: the extra DOCKER_CONFIG mount
below is what gives them to it.
export CP=$(docker info -f '{{range .ClientInfo.Plugins}}{{if eq .Name "compose"}}{{.Path}}{{end}}{{end}}')
docker run --rm --user "$(id -u):$(id -g)" --group-add "$(stat -c '%g' /var/run/docker.sock)" \
-v "$(pwd)/avatar:/app-root" -v /var/run/docker.sock:/var/run/docker.sock \
-v "$(which docker):/usr/local/bin/docker:ro" -v "$CP:$CP:ro" \
-e DOCKER_CONFIG=/docker-config -v "$HOME/.docker:/docker-config:ro" \
quay.io/octopize/deploy-tool:latest start --app-root /app-root
If the host keeps its registry credentials in a credential helper — a credsStore entry
in ~/.docker/config.json — that mount carries no usable credential, because the helper
is a program the container does not have. Write a configuration that holds the token
itself, and mount that one instead:
mkdir -p ~/avatar-registry-login
DOCKER_CONFIG=~/avatar-registry-login docker login quay.io
# ... -e DOCKER_CONFIG=/docker-config -v "$HOME/avatar-registry-login:/docker-config:ro"
Stop
export CP=$(docker info -f '{{range .ClientInfo.Plugins}}{{if eq .Name "compose"}}{{.Path}}{{end}}{{end}}')
docker run --rm --user "$(id -u):$(id -g)" --group-add "$(stat -c '%g' /var/run/docker.sock)" \
-v "$(pwd)/avatar:/app-root" -v /var/run/docker.sock:/var/run/docker.sock \
-v "$(which docker):/usr/local/bin/docker:ro" -v "$CP:$CP:ro" \
quay.io/octopize/deploy-tool:latest stop --app-root /app-root
Verify
export CP=$(docker info -f '{{range .ClientInfo.Plugins}}{{if eq .Name "compose"}}{{.Path}}{{end}}{{end}}')
docker run --rm --user "$(id -u):$(id -g)" --group-add "$(stat -c '%g' /var/run/docker.sock)" \
-v "$(pwd)/avatar:/app-root" -v /var/run/docker.sock:/var/run/docker.sock \
-v "$(which docker):/usr/local/bin/docker:ro" -v "$CP:$CP:ro" \
quay.io/octopize/deploy-tool:latest verify --app-root /app-root --test-email <you@company.com>
Uninstall — destroys the deployment and all its data
export CP=$(docker info -f '{{range .ClientInfo.Plugins}}{{if eq .Name "compose"}}{{.Path}}{{end}}{{end}}')
docker run -it --rm --user "$(id -u):$(id -g)" --group-add "$(stat -c '%g' /var/run/docker.sock)" \
-v "$(pwd)/avatar:/app-root" -v /var/run/docker.sock:/var/run/docker.sock \
-v "$(which docker):/usr/local/bin/docker:ro" -v "$CP:$CP:ro" \
quay.io/octopize/deploy-tool:latest uninstall --app-root /app-root
Update
Needs no Docker access, so no socket or plugin mounts.
docker run -it --rm --user "$(id -u):$(id -g)" \
-v "$(pwd)/avatar:/app-root" \
quay.io/octopize/deploy-tool:latest update --app-root /app-root
Migrate
Mount the old flat deployment read-only and pass its container path.
docker run -it --rm --user "$(id -u):$(id -g)" \
-v "$(pwd)/avatar-new:/app-root" -v "$(pwd)/avatar-old:/legacy:ro" \
quay.io/octopize/deploy-tool:latest migrate --app-root /app-root --from-legacy /legacy
Notes:
- The Docker CLI is not bundled in the image; the mounts above supply it and the Compose plugin. The official binary is statically linked and works across distributions.
- Anything outside the app root needs its own mount, always passed as its container path —
e.g.
-v "$(pwd)/config:/input:ro"with--from-config /input/config.yaml. - Enter host paths at the prompts. Paths you type — TLS certificate, private key — are used by Docker Compose on the host, so give the host path even though you are typing it inside a container. The tool detects that it is running in a container, skips the existence check for those paths and prints a notice saying so.
- The app root has to come from a mount. The deployment files are read by the Docker daemon
on the host, and the tool works out their host path from the container's own mounts, so
-v "$(pwd)/avatar:/app-root"needs no path to match. A directory that belongs to the container itself (/tmp/avatar, say) is reachable by nothing but the tool, andstartrefuses it rather than bring up a stack that cannot read its own secrets. - Anything outside the app root needs its own mount:
-v "$(pwd)/config:/input:ro"with--from-config /input/config.yaml, or-v "$(pwd)/avatar-old:/legacy:ro"with--from-legacy /legacyformigrate. Always pass the container-side path.
Upgrading from a pre-SSO deployment
Older Avatar deployments kept users in the Avatar API database. migrate records that they still
need importing into Authentik, and the first start after a migrate offers to do it for
you: it asks Run it now? and runs the import. Nothing has to be run by hand.
Add --verbosity 2 to review before committing: the plan — every group and every user the import
would create — is printed, and a second prompt asks whether to go ahead with it. At the default
--verbosity 1 nothing is printed beforehand, so Run it now? is the only question asked.
If you decline, the same import is available later:
octopize-deploy-tool tasks authentik-migrate --from-docker --app-root ./app/avatar
--from-docker reads users, organizations and licenses straight from the running api container's
database, so there is no CSV export to produce; the extracted data is held in memory and never
written to disk. The Authentik URL and token come from generated_files/.env. --dry-run
prints the plan — every group and every user that would be created — and writes nothing to
Authentik (with --from-docker it still brings the stack up to read the database); a real run
prints that plan only under --verbosity 2. Users that already carry an authentik_id are
skipped, so the import is safe to re-run.
Every run that is not a --dry-run does write an operation log — migration_log.jsonl unless
--log PATH says otherwise — recording what was attempted and how it ended.
--from-log migration_log.jsonl --failed-only replays just the failures, into
migration_log_retry.jsonl so the original is not overwritten.
If you are importing into an Authentik instance this tool did not deploy, or the api container is
not running, export the three tables to CSV and pass them with --users, --orgs, --licenses,
--authentik-url and --authentik-token instead. That path — the SQL to run, and how to mint an
Authentik API token with the right permissions — is written up in
Migrating users into Authentik.
Troubleshooting
Services fail to start. Inspect the stack directly:
docker compose -f ./app/avatar/generated_files/docker-compose.yml ps
docker compose -f ./app/avatar/generated_files/docker-compose.yml logs -f
Containers start but cannot reach each other. Almost always a Docker HTTP proxy — see the
noProxy note under Requirements. Recreate the containers after fixing it; the
setting does not affect existing ones.
install warns "Volume 'avatar_postgres_data' already exists". The host still holds data from
a previous deployment. Use update to keep it or uninstall to destroy it. Answering y at the
prompt installs on top of it with fresh credentials that will not match that data. A
--non-interactive run does not offer the choice: it stops with Install aborted by operator during pre-flight checks.
update exits with "Apply is blocked until conflicts are resolved". You have manual edits
under generated_files/. Merge them into .deployment_states/<vX>/generated/ and run
apply --version <vX> — see update.
verify reports "API key not found". Run tasks provision-admin first.
An install was interrupted with Ctrl+C. Run install again: it reports the incomplete
configuration and asks Resume the in-progress configuration (vN)? Answering y continues
where it stopped, keeping the answers already given; answering n starts the questionnaire
again in a new version slot and leaves the interrupted one on disk. A --non-interactive run
cannot answer, so it stops instead.
start reports that an image registry refused the credentials. The credentials
docker login writes belong to the Docker client, so a start run from the deploy-tool
container does not have the ones you created on the host. The message names the mount to add —
see Running via Docker.
Something needs a closer look. Add --verbosity 2 for detailed progress and template output.
Starting over. uninstall is the supported teardown: it is confirmation-gated and removes
containers, volumes and deployment files together. Running docker compose down --volumes by
hand deletes the Postgres volume — and every avatar, dataset and user account in it — while
leaving the deployment files behind, so the two fall out of sync. Prefer uninstall.
Further information
- Deployment documentation: https://docs.octopize.io/docs/deploying/self-hosted/self_installation
- Package on PyPI: https://pypi.org/project/octopize-deploy-tool/
- Report a problem: https://github.com/octopize/avatar/issues
Reference documents live in the repository rather than in the published package, so they need access to https://github.com/octopize/avatar:
- Migrating users into Authentik — CSV export path, foreign Authentik instances, API tokens
- Telemetry — what is sent, and how to enable, rotate or disable it
- Debugging Authentik blueprints — when SSO configuration does not take effect
- Network topology — the Compose networks and which services sit on which
Metadata
Release files for octopize.deploy_tool 3.5.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| octopize_deploy_tool-3.5.1.tar.gz | 783.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| octopize_deploy_tool-3.5.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.1 MB
Release files / octopize_deploy_tool-3.5.1.tar.gz
| Download URL | octopize_deploy_tool-3.5.1.tar.gz |
|---|---|
| Size | 783.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
932624371c4e8e0d32b0bbc53f0494ed414f797573cddbc76830658477c7644b
|
|
BLAKE2b-256 checksum How to use checksums |
55c6d01a5b22e006819624325a7e40a3ee419426cba81811db1a39e6c0f3ac87
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.18 {"installer":{"name":"uv","version":"0.12.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / octopize_deploy_tool-3.5.1-py3-none-any.whl
| Download URL | octopize_deploy_tool-3.5.1-py3-none-any.whl |
|---|---|
| Size | 352.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0841c18351dabf3acac0262a002cabe1329fb9bff4b3435ddd3c8aaae50b063a
|
|
BLAKE2b-256 checksum How to use checksums |
dc13cadbbbe77a858fb81ff59ce3cca28f71281fa88fce961a1173d3b4a22348
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.18 {"installer":{"name":"uv","version":"0.12.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for octopize.deploy_tool 3.5.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.