This guide uses the production environment and main branch. Prepare the server and environment profile following shared CI/CD instructions.
1. Create CI files
Enable Docker and Production deployment in Deployment. Choose GitLab as CI provider. In Deployment environments, create a production profile, enter servers and domains, and choose Archive or Registry delivery. Save settings, run Generate, and commit the generated profile and custom file without secrets to Git.
The project gets .gitlab-ci.yml, .gitlab/admingen.yml, and deploy/custom/gitlab.yml. The generator updates the first two; add your own jobs in deploy/custom/gitlab.yml.
Create a GitLab repository, upload the project, and protect main.
2. Prepare the runner
You need GitLab Runner with Docker executor and Docker-in-Docker. The template uses docker:29.3.1-cli and docker:29.3.1-dind with TLS.
In runner settings, allow privileged mode for DinD, shared certificate directory /certs/client, and shared /builds between the job and DinD. The runner must accept project jobs, including protected-branch jobs; the template assigns no tags. Check availability in GitLab Settings → CI/CD → Runners.
3. Add build settings
By default, the pipeline uses the production profile from Git. For another name, set ADMINGEN_ENVIRONMENT with scope *. The generated and custom files for this profile must be committed.
If you need complete configuration outside Git, create ADMINGEN_BUILD_ENVIRONMENT_JSON as File with scope *, and ADMINGEN_ENVIRONMENT_JSON as File with the desired environment scope. Paste the complete manual JSON contents. These fully override UI/custom; do not create them for a normal profile.
Add other variables in Settings → CI/CD → Variables.
For Registry delivery, add protected Variable entries with scope *:
| Key | Value |
|---|---|
ADMINGEN_BUILD_REGISTRY_USER |
Registry user |
ADMINGEN_BUILD_REGISTRY_PASSWORD |
Token with image-publishing permissions |
For this GitLab's registry, automatically supplied CI_REGISTRY_USER and CI_REGISTRY_PASSWORD can be used: the template inserts them if the registry host matches CI_REGISTRY and no custom pair is set. For another registry, set both variables. Archive does not need them.
4. Add release settings
Create environment production and restrict who may deploy. Configure available project approvals if needed.
Add protected File variables, now with scope production:
| Key | Contents of Value |
|---|---|
ADMINGEN_SSH_KEY |
Deployment user's private key |
ADMINGEN_KNOWN_HOSTS |
Prepared known_hosts for environment servers |
Use the key and known_hosts prepared for manual server management. Preserve line breaks. Do not add PostgreSQL passwords or application signing keys to these variables.
For Registry, set ADMINGEN_REGISTRY_USER and ADMINGEN_REGISTRY_PASSWORD as Variable entries with production scope if needed. This is runner access to release images; use a read token. Built-in GitLab credentials work only for a matching registry host. The server uses its own persistent token configured during provisioning.
Build and deploy configurations must describe the same environment and delivery method. Archive needs no registry variables for build or release. Enable masking for tokens when their value format supports it.
5. Build and release the application
- Push code to
main. - Open Build → Pipelines and the pipeline for that push.
- Wait for admingen-build to succeed.
- For first installation, download artifacts and perform provision following Archive or Registry. No rebuild of the downloaded release is needed.
- In the same pipeline, manually start admingen-deploy. Complete approval if configured.
- Wait for success and open the application.
Registry build publishes images and saves release.json. Archive also saves *.images.tar. Artifacts are available for 90 days. Deploy takes the prepared build from the same pipeline and verifies its commit; release involves no rebuild.
6. Add scheduled maintenance
Create environment production-maintenance, allow operation from main, and add the same File variables from step 4 with this scope. For Registry, add read credentials if needed. Manual confirmation of every run is not required here.
Maintenance jobs use the production profile: a separate CI environment restricts access but does not create another database or server.
Create a pipeline schedule for main, set the time and variables:
ADMINGEN_ENVIRONMENT=production
ADMINGEN_OPERATION=maintenance
Maintenance creates a backup, then maintains certificates. With backup.kind: none, backup is skipped. For a separate schedule, choose ADMINGEN_OPERATION=backup or certificates; explicit backup with None fails.
Create the GitLab schedule manually. Push runs build; schedule runs maintenance. New code is not automatically deployed on schedule.
If a job does not start
| Symptom | Check |
|---|---|
| Pending | Runner available and accepts untagged/protected jobs |
| Cannot connect to Docker daemon | DinD, privileged mode, /certs/client, and shared /builds |
| Profile not found | Name matches ADMINGEN_ENVIRONMENT; generated/custom files exist in Git; for manual JSON, variable has Type=File |
| No manual deploy | Pipeline must come from a push to main |
| Registry access error | Registry host and token permissions for the specific failed step |
| Unresolved reservation after job cancellation | See operation recovery |