conductor/docs/INSTALL.md
Victor Wiebe ade2b10033
Some checks failed
Release production image / production-image (push) Has been cancelled
Add production packaging and operations
2026-08-07 16:48:40 -04:00

4.4 KiB

Production Installation

Supported installation paths

Conductor supports:

  1. A public container installation using compose.production.yml and a pinned release image.
  2. A reproducible source build using Dockerfile.production and compose.production.build.yml.
  3. SkeletonWorks deployment through setup-conductor.sh in the skeletonworks-scripts repository.

The production distribution is one same-origin service. Express serves the compiled React application, /api, and refreshable published routes such as /apps/inventory/details on internal port 8080. The development-only frontend/backend containers are not production artifacts.

Requirements

  • Docker Engine with Compose v2
  • Approximately 1 GiB memory and 1.5 CPU available by default
  • A persistent Docker volume or host directory for /data
  • TLS reverse proxy for internet-facing deployments
  • Two independently generated persistent keys

Public container installation

Download compose.production.yml and .env.production.example from the same tagged release. Do not mix files from different releases.

mkdir conductor && cd conductor
curl -O https://gitea.skeletonworks.online/vwiebe/conductor/raw/tag/v0.1.0/compose.production.yml
curl -o .env https://gitea.skeletonworks.online/vwiebe/conductor/raw/tag/v0.1.0/.env.production.example

Edit .env:

CONDUCTOR_SECRET_KEY=<output of openssl rand -hex 32>
CONDUCTOR_SESSION_KEY=<different output of openssl rand -hex 32>
CONDUCTOR_IMAGE=gitea.skeletonworks.online/vwiebe/conductor
CONDUCTOR_VERSION=v0.1.0
CONDUCTOR_BIND_ADDRESS=127.0.0.1
CONDUCTOR_PORT=8080

CONDUCTOR_SECRET_KEY encrypts stored REST credentials. Losing or changing it makes those credentials unrecoverable. CONDUCTOR_SESSION_KEY protects sessions; changing it logs everyone out. Neither belongs in source control.

Start and verify:

docker compose --env-file .env -f compose.production.yml pull
docker compose --env-file .env -f compose.production.yml up -d
docker compose --env-file .env -f compose.production.yml ps
curl --fail http://127.0.0.1:8080/api/health

Open the configured URL. A new database presents the browser first-run administrator screen. Conductor never ships a default username or password.

Build from source

Use a tagged source archive or checkout:

git clone https://gitea.skeletonworks.online/vwiebe/conductor.git
cd conductor
git checkout v0.1.0
cp .env.production.example .env
# Replace both key placeholders.
docker compose --env-file .env \
  -f compose.production.yml -f compose.production.build.yml \
  up -d --build

The multi-stage build compiles frontend and backend code, prunes development dependencies, includes the matching project schema, and runs as UID/GID 10001.

Caddy

Bind Conductor to loopback and proxy it through Caddy:

conductor.example.com {
    reverse_proxy 127.0.0.1:8080
    encode zstd gzip
}

Caddy provides TLS automatically when DNS and ports 80/443 are correctly configured.

NGINX

server {
    listen 443 ssl http2;
    server_name conductor.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Configure certificates using the operator's normal NGINX/TLS process.

Internal REST destinations

The proxy denies private/internal destinations by default. CONDUCTOR_PROXY_INTERNAL_ORIGINS is an optional comma-separated allowlist of exact origins. Add only reviewed origins, for example https://api.internal.example.com:443. It does not accept wildcard hosts.

SkeletonWorks

On a prepared SkeletonWorks host:

sudo bash /opt/skeletonworks/scripts/setup-conductor.sh \
  --domain example.com \
  --image gitea.skeletonworks.online/vwiebe/conductor:v0.1.0 \
  --restartcaddy

The script creates /opt/skeletonworks/conductor/conductor.example.com, preserves keys across reruns, joins skeletonworks_net, installs a Caddy block and backup cron entry, waits for health, and emits a JSON result. Prefer immutable version, Git-SHA, or digest references over latest.

Uninstalling

Stopping/removing containers does not remove the named data volume:

docker compose --env-file .env -f compose.production.yml down

Do not add --volumes unless a verified backup exists and permanent data deletion is intended.