9.9 KiB
Forgejo FaceAI Autodeploy Options
Goal
Make the existing Forgejo image publish workflow complete the last step automatically by redeploying the FaceAI runtime after new images are pushed.
Verified Current State
Repository
.forgejo/workflows/publish-faceai-container.ymlalready builds and pushes two images onmasterpushes:faceai-clientfaceai-processor
- The workflow tags both images as:
sha-<short-sha>latest
- The production-style compose definitions in
faceai/docker-compose.ymlandstacks/faceai.ymlcurrently consume the:latesttags.
Target Host
Read-only inspection on root@pve02docker.maddo.science confirmed:
- the host is running Docker and Portainer
- the FaceAI services are already live:
regalami-faceairegalami-faceai-processorregalami-faceai-redis
- the running FaceAI containers are managed by Docker Compose from
/data/compose/4 - the compose file in use is
/data/compose/4/docker-compose.yml - Portainer is present on the host, but the FaceAI containers did not expose an
io.portainer.stack.idlabel during inspection
This matters because the current deployment looks Compose-first. Portainer is available, but the cleanest automation path does not need to depend on Portainer unless we explicitly want it to.
What "automatic deploy" means here
Because the server is already running the correct images and compose stack, the deployment action is simply:
cd /data/compose/4
docker compose pull
docker compose up -d
In practice, the workflow should usually limit this to the services that actually change:
cd /data/compose/4
docker compose pull faceai processor
docker compose up -d faceai processor
That leaves Redis untouched unless the compose definition itself changes.
Options
Option 1: Deploy over SSH directly from the Forgejo workflow
Add a second job after image publish that opens an SSH session from the Forgejo runner to the target server at 192.168.10.69 and runs the compose pull and redeploy commands.
Typical flow:
- build and push images
- SSH to the deployment host
- run
docker compose pull faceai processor - run
docker compose up -d faceai processor - verify with
docker compose psand a health check or recent logs
Why this fits the current setup:
- it matches the host's current Compose-managed reality
- it does not require Portainer-specific features
- it is the smallest change from today's manual rollout
- it is deterministic: deploy happens only when the publish job succeeds
Prerequisites:
- the Forgejo runner must be able to reach
192.168.10.69 - the workflow needs an SSH private key stored as a secret
- the target host needs a user that can run the required Docker Compose commands
- the target host must already have registry credentials that allow
docker compose pull, or the workflow must also perform a remotedocker login
Advantages:
- simplest and most explicit option
- easy to audit in workflow logs
- easy to gate with branch rules or manual approvals later if needed
- easiest option to verify with post-deploy health checks
Disadvantages:
- the CI system receives deployment credentials
- network reachability from runner to host becomes part of deployment reliability
- if
latestis reused, the workflow is still deploying a mutable tag rather than an immutable release reference
Implementation notes:
- use a separate
deployjob withneeds: publish - add a Forgejo
concurrencygroup for production deploys so two pushes do not race each other - prefer a dedicated deploy user over
root - if possible, restrict the SSH key with a forced command or a narrowly scoped sudo rule
Option 2: Trigger Portainer API redeploy from the workflow
Instead of SSH, let the workflow call the Portainer HTTP API after the images are pushed.
Typical flow:
- build and push images
- authenticate to Portainer with an API token
- call the relevant stack redeploy endpoint
- let Portainer pull the latest tagged images and recreate the stack
Why this can work:
- Portainer is already running on the host
- Portainer's API is intended for automation
- this keeps the workflow talking to one control-plane API instead of opening SSH
Advantages:
- clean control-plane integration if Portainer is the intended long-term operations surface
- centralizes stack redeploy operations in Portainer
- avoids distributing shell-level access to the host into CI
Disadvantages:
- requires Portainer API token management
- requires knowing the correct environment and stack identifiers
- if the current FaceAI deployment is not fully Portainer-native, this adds a second management path on top of the existing Compose-first one
- troubleshooting usually becomes more Portainer-specific
Practical caveat for this host:
The current FaceAI containers clearly show Compose management from /data/compose/4, while the inspection did not confirm an active Portainer stack label on them. That does not make Portainer API automation impossible, but it does mean this path should be treated as an intentional operational redesign rather than the smallest incremental step.
Option 3: Trigger a Portainer stack webhook from the workflow
Portainer supports stack webhooks that can redeploy a stack when an HTTP POST is sent to the webhook URL.
Typical flow:
- enable a stack webhook in Portainer
- store the webhook URL as a Forgejo secret
curl -X POSTthe webhook at the end of the publish workflow
Advantages:
- very simple workflow-side integration
- no SSH session needed
- easier to wire than the full Portainer API
Disadvantages:
- Portainer documents stack webhooks as a Business Edition feature
- webhook security is mostly the secrecy of the URL
- still depends on the stack being managed correctly in Portainer
Assessment:
This is attractive only if the host is using Portainer Business Edition and you want the shortest possible HTTP-based trigger. Otherwise it is not the best fit.
Option 4: Host-side auto-updater such as Watchtower
Run a container on the target host that watches for updated image tags and automatically recreates containers when a newer image appears in the registry.
Typical flow:
- Forgejo builds and pushes new
latest - Watchtower notices the new image
- Watchtower pulls and restarts the affected containers automatically
Advantages:
- decouples deployment from Forgejo runner network reachability
- zero extra deploy step in the workflow
- simple mental model if the policy is always "follow latest"
Disadvantages:
- less explicit and less deterministic than a pipeline-controlled deploy
- easier to deploy at unexpected times if tags move
- broader blast radius unless carefully scoped to only the FaceAI containers
- can drift away from the compose-driven operational model
Assessment:
This works, but it is better for "always keep these containers on the newest tag" than for controlled CI/CD. It is not the best match if you want the workflow run itself to be the audited deployment event.
Option 5: Host-side scheduled pull and redeploy
Use a cron job or systemd timer on the host to periodically run:
cd /data/compose/4
docker compose pull faceai processor
docker compose up -d faceai processor
Advantages:
- very small operational footprint
- no Portainer API and no CI-to-host SSH required
- resilient if the Forgejo runner cannot reach the host directly
Disadvantages:
- deploy timing is delayed and approximate
- weak audit trail compared with a pipeline-driven deploy
- no natural coupling between a successful image publish and the rollout itself
Assessment:
This is acceptable as a fallback, but it is not true autonomous CD tied to a specific successful workflow run.
Recommendation
The best fit for the current system is Option 1: direct SSH deploy from the Forgejo workflow.
Reasoning:
- the host is already running the stack through plain Docker Compose
- the required deploy action is just
docker compose pullfollowed bydocker compose up -d - this keeps the delivery path explicit and easy to reason about
- it avoids introducing Portainer-specific coupling when Portainer is not currently the proven source of truth for the FaceAI runtime
If you want the smallest reliable implementation, keep the current :latest tag contract and add a deploy job that runs only after both image pushes succeed.
If you want the more rigorous version later, evolve the stack from :latest to immutable sha-... tags and have the workflow update the deployed tag intentionally before redeploying. That is a second hardening step, not a requirement for getting autonomous CD working now.
Suggested Minimal Rollout Design
- Keep the current publish job.
- Add a
deployjob withneeds: publish. - Store deployment SSH credentials in Forgejo secrets.
- SSH to
192.168.10.69and run:
cd /data/compose/4
docker compose pull faceai processor
docker compose up -d faceai processor
docker compose ps
docker logs --tail 100 regalami-faceai
docker logs --tail 100 regalami-faceai-processor
- Fail the job if the compose update or health verification fails.
- Add workflow concurrency so only one production deploy runs at a time.
Open Questions Before Implementation
- Which host user should the workflow use for deployment?
- Does the target host already have persistent registry credentials for
forgejo.maddoscientisto.net? - Is the Forgejo runner allowed to reach
192.168.10.69directly over SSH, or does it need a different path? - Do you want the initial autonomous version to keep using
latest, or do you want to switch immediately to immutable image tags?
Bottom Line
Yes, full autonomous CD is feasible with the current setup.
The shortest safe path is not "make Portainer do it" but "let the workflow SSH to the Compose host and run the two compose commands after a successful image push". Portainer-based automation is possible, but it is a weaker fit for the current deployment shape unless you specifically want Portainer to become the authoritative deployment control plane.