Set up a fresh prod host, bootstrap PMA there, wire it into the release flow, and harden it for the real world. The same framework as your dev install; different
.env, different SSH alias, real backups, and a more conservative deploy posture.
Level: 7 · Reading time: 30 min
/asd/internals/tunnels).prod for the rest of the docs.Last rung of the ladder. From here, head to cookbook for single-problem recipes, or internals for the deeper "how the framework actually works" view.
Prod is just dev with three differences:
ASD_ENV=prod in .env, set ONCE per machine. Drives container naming (asd-prod-redmine vs asd-dev-redmine), volume naming, port allocation, and the env-suffix on every backup directory.vsXX clones, see below).The release flow is identical (just release-run TICKET). The prep
work is what's different.
# On the prod host as root or sudoer
sudo useradd -m -s /bin/bash -G docker pma # or use existing user
sudo mkdir -p /opt/asd-pma
sudo chown pma:pma /opt/asd-pma
# Install prerequisites
curl -fsSL https://asd.host/install.sh | bash # asd CLI
sudo apt install just # just
curl -fsSL https://bun.sh/install | bash # bun
# Docker + compose plugin (Debian/Ubuntu)
sudo apt install docker.io docker-compose-plugin
prod in your local SSH configOn your laptop:
# ~/.ssh/config — add an entry:
Host prod
HostName your-prod-host.example.com # or IP
User pma
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 60
prod is the only project-wide alias the PMA docs reference (see
CLAUDE.md's "SSH access" section). All operator runbooks use ssh prod. Personal aliases like vm-01, laptop, home stay in
your own ~/.ssh/config and don't appear in committed artefacts.
# Clone PMA into /opt/asd-pma
ssh prod 'cd /opt && sudo git clone https://github.com/asd-engineering/asd-pma.git && sudo chown -R pma:pma asd-pma'
# Bootstrap in prod mode. The third arg is the env name; the
# script creates /opt/pma-prod (if you used 'prod' as the env
# name in your asd.yaml) and bootstraps there.
ssh prod 'cd /opt/asd-pma && just bootstrap-local enterprise prod'
bootstrap-local <profile> <env> clones a fresh /opt/pma-<env>/
directory and bootstraps there. This avoids accidentally
overwriting /opt/asd-pma's state. The <env> argument becomes
the ASD_ENV of the new directory.
After bootstrap completes (~30-45 min):
ssh prod 'cd /opt/asd-pma && just tunnel-status'
# Shows the public URLs for every service
If you control DNS for your-domain.com:
*.your-domain.com at the prod host'sASD_TUNNEL_HOST=your-domain.com in /opt/asd-pma/.env.just net apply to regenerate Caddy routes with the newIf you use a tunnel server (sish-compatible):
asd net apply --tunnel (the asd-side default for tunnel mode)<svc>-<your-client-id>.<tunnel-host>.Once prod is up, you deploy from your laptop using ssh prod to
invoke the orchestrator on the host:
# On your laptop — make a change, commit, push, get merged to main
git checkout -b feat/1234-tweak-redmine
$EDITOR packages/redmine/manifest.yaml
git commit -am "feat: #1234 bump redmine image"
git push origin feat/1234-tweak-redmine
# Open PR, get reviewed, merge to main
# Now release:
ssh prod 'cd /opt/asd-pma && just release-run 1234'
# The four-phase orchestrator runs on prod
# (see Level 6 — release and rollback for the full phase walk)
Per Golden Rule 13: never ssh prod 'git pull' separately. The
orchestrator handles its own git state.
For testing migrations before they hit real prod, the same host
runs multiple PMA installations side-by-side via different env
names:
# Create a vs43 test environment on the same prod host
ssh prod 'cd /opt/asd-pma && just bootstrap-local minimal vs43'
# Bootstraps a fresh /opt/pma-vs43/ with ASD_ENV=vs43
# Containers named asd-vs43-redmine etc., own port allocation,
# own tunnel subdomains.
# Test your release-script there before running on prod:
ssh prod 'cd /opt/pma-vs43 && just release-run 1234'
# Same orchestrator, isolated state.
# When done:
ssh prod 'cd /opt/asd-pma && just env destroy vs43 --force'
# Cleans up containers, volumes, caddy routes, tunnel registry,
# and removes /opt/pma-vs43/.
A working prod PMA, reachable at stable URLs, deployable from your
laptop via ssh prod 'just release-run TICKET'. Backups taken
automatically per release. Revert path available
(just release-revert TICKET). Side-by-side test envs available
via bootstrap-local <profile> <env>.
$ ssh prod 'cd /opt/asd-pma && just status | grep healthy | wc -l'
12
$ ssh prod 'cd /opt/asd-pma && cat .asd/workspace/releases/$(ls -t .asd/workspace/releases/*.env | head -1)'
TICKET=1234
BRANCH=main
BASE_SHA=...
MERGE_SHA=...
SERVICES="redmine"
BACKUPS="redmine=20260518_153012"
Three things to internalise:
ASD_ENV is the namespace. Every container, volume, port
and tunnel subdomain gets prefixed/suffixed with it. Two PMA
installs (/opt/asd-pma and /opt/pma-vs43) with different
ASD_ENV coexist on the same host without docker-network
conflicts. This is what makes "test the release on a vs43
clone before prod" cheap.
ssh prod is the operator entry point. Always. Locally
you push to GitHub; prod pulls via the orchestrator. The
release-run script captures BASE_SHA, pulls to MERGE_SHA,
diffs, and acts. Never insert manual git pull / git checkout between PR merge and release-run.
Hardening is a checklist, not a script. A prod-grade
PMA install needs (in addition to what bootstrap does):
firewall closing ports you don't expose, scheduled
just backup cron, off-host backup rotation
(asd data push works), monitoring (Grafana + Prometheus
come with the enterprise profile — point them at your other
services), log forwarding to Loki (also in enterprise),
alerting (Grafana alerts → Mattermost via n8n).
The hardening checklist lives in
/pma/cookbook/run-pma-as-a-cooperative (planned) (the
multi-tenant pattern stresses the same concerns) and the
operational recipes under /pma/cookbook.
Reference: /pma/internals/release-orchestrator (planned)
covers the four phases at source-code level;
/pma/internals/bootstrap (planned) covers what
bootstrap-local does in detail.
/pma/cookbook — upgrades, debugging failed releases, integrating an external Authentik, migrating from cloud SaaS./pma/internals — architecture, bootstrap flow, MCP gateway, recovery playbooks, release orchestrator, contract system./pma/compared — vs Cloudron / Yunohost / SaaS stacks. Useful when your team asks "why not X instead?".