conductor/docs/INSTALL.md
Victor Wiebe 498003f83d
Some checks failed
Release production image / production-image (push) Has been cancelled
Prepare Conductor v1.0.0 release
2026-08-08 14:21:40 -04:00

9.7 KiB

Install Conductor on Your Own Server

This guide is for independent self-hosters installing Conductor on an ordinary internet-connected server. It uses the public source bundle, public container image, Docker Compose, and a reverse proxy you control. No SkeletonWorks tooling or registry account is required.

The recommended path runs the published container. The tagged source bundle supplies the matching Compose file, environment template, backup/restore scripts, and documentation.

Use the v1.0.0 commands below only after the public Gitea Release entry exists. Before publication, do not substitute an older release candidate and treat a missing source tag or image as an incomplete release rather than an installation problem.

What you need

  • A GNU/Linux x86_64/AMD64 server. Conductor v1.0.0 is not published for ARM64.
  • Docker Engine with the docker compose plugin. Use Docker's Engine installation guide and Compose plugin guide if needed.
  • Permission to run Docker commands.
  • curl, openssl, tar, bash, realpath, find, sha256sum, and GNU stat.
  • About 1 GiB of memory and 1.5 CPU available with the default limits.
  • A domain name whose DNS points to the server.
  • Inbound ports 80 and 443 for TLS, and outbound HTTPS access for image pulls and REST destinations.
  • Caddy, NGINX, or another reverse proxy on the same host.

These commands assume docker version and docker compose version succeed without sudo. If your Docker installation requires elevated access, apply your normal server policy consistently.

Confirm the architecture before continuing:

uname -m

Continue only if it prints x86_64 or the equivalent AMD64 name for this release.

1. Download the pinned installation bundle

Choose a directory that will remain on the server. The example uses the current user's home directory:

mkdir -p "$HOME/conductor"
cd "$HOME/conductor"

CONDUCTOR_RELEASE=v1.0.0
curl --fail --location --show-error \
  "https://gitea.skeletonworks.online/vwiebe/conductor/archive/${CONDUCTOR_RELEASE}.tar.gz" \
  --output conductor-source.tar.gz
tar -xzf conductor-source.tar.gz --strip-components=1
rm conductor-source.tar.gz

The v1.0.0 source tag and the container image's OCI revision label must identify the same release commit. The authoritative commit, archive checksums, and image digests are recorded in the Gitea v1.0.0 Release entry after publication. Keep compose.production.yml, .env, and scripts/production/ together so the documented backup and restore commands work.

2. Create the persistent configuration

Run this block once. If .env already exists from an earlier installation, stop and keep it; overwriting its encryption key can make stored credentials unreadable.

cd "$HOME/conductor"
test ! -e .env || { echo '.env already exists; leaving it unchanged.' >&2; exit 1; }

umask 077
secret_key="$(openssl rand -hex 32)"
session_key="$(openssl rand -hex 32)"

{
  printf 'CONDUCTOR_SECRET_KEY=%s\n' "$secret_key"
  printf 'CONDUCTOR_SESSION_KEY=%s\n' "$session_key"
  printf 'CONDUCTOR_IMAGE=gitea.skeletonworks.online/vwiebe/conductor\n'
  printf 'CONDUCTOR_VERSION=v1.0.0\n'
  printf 'CONDUCTOR_BIND_ADDRESS=127.0.0.1\n'
  printf 'CONDUCTOR_PORT=8080\n'
  printf 'CONDUCTOR_MEM_LIMIT=1g\n'
  printf 'CONDUCTOR_CPUS=1.5\n'
  printf 'CONDUCTOR_PROXY_INTERNAL_ORIGINS=\n'
} > .env

unset secret_key session_key
chmod 600 .env

CONDUCTOR_SECRET_KEY encrypts stored REST credentials. The database and this exact key are one recovery set. CONDUCTOR_SESSION_KEY protects login sessions; changing it signs everyone out. Never commit .env, paste its values into tickets, or include them in screenshots.

The loopback bind keeps port 8080 off the public network. Only the reverse proxy should accept internet traffic.

3. Pull and start Conductor

cd "$HOME/conductor"
docker compose --env-file .env -f compose.production.yml pull
docker compose --env-file .env -f compose.production.yml up -d

for _ in $(seq 1 60); do
  if curl --fail --silent http://127.0.0.1:8080/api/health >/dev/null; then
    break
  fi
  sleep 2
done

docker compose --env-file .env -f compose.production.yml ps
curl --fail --show-error http://127.0.0.1:8080/api/health

The final command should return healthy JSON. If it fails, inspect:

docker compose --env-file .env -f compose.production.yml logs --tail=200 conductor

The v1.0.0 release is complete only after this pull succeeds without a Gitea username, password, or token. Check the Gitea v1.0.0 Release entry for the published OCI index and AMD64 manifest digests. Do not substitute latest or an older release-candidate digest.

4. Configure HTTPS

Production login and setup cookies are Secure, so finish HTTPS before creating the first administrator. Plain HTTP is suitable for the loopback health check, not for normal browser use.

Choose one reverse proxy. The examples assume the proxy runs directly on the Docker host. Replace conductor.example.com with your real hostname and create its DNS record first.

Caddy

Install Caddy using its official installation guide. Add this site block to /etc/caddy/Caddyfile:

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

Then validate and reload it:

sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

Caddy obtains and renews TLS certificates automatically when DNS and inbound ports 80/443 are correct.

NGINX

Provision a valid TLS certificate using your normal NGINX process, then proxy every path to Conductor:

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

    # Configure ssl_certificate and ssl_certificate_key for this hostname.

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

Validate and reload NGINX after placing the block in the configuration used by your distribution. Configure the port-80 server to redirect HTTP to HTTPS.

If the reverse proxy runs on another host, do not expose port 8080 to the whole internet. Bind it to a private interface and restrict that port to the proxy host with network and firewall rules.

5. Create the first administrator

Open the final URL, for example:

https://conductor.example.com

The first-run screen asks for a username and a password of at least 12 characters. Display name and contact email are optional. Conductor creates that administrator and closes first-run setup permanently. There are no default credentials.

Create a second administrator from Users before relying on the installation. Application administration is covered in the Administrator Guide.

6. Smoke-test persistence and routing

  1. Sign in and create a small project in Visual Editor.

  2. Save it, restart the container, and sign in again:

    cd "$HOME/conductor"
    docker compose --env-file .env -f compose.production.yml restart conductor
    
  3. Load the saved project and confirm it persisted.

  4. Publish it and open both /apps/<app-slug> and a direct /apps/<app-slug>/<page-slug> URL in new browser tabs.

The editor, API, and published routes should all use the same HTTPS origin. A direct deep link must not return the reverse proxy's 404 page.

Internal REST destinations

Conductor allows public HTTP/HTTPS destinations that pass its proxy policy and denies private or internal networks by default. If an application must call an internal API, add only its reviewed exact origin to .env, for example:

CONDUCTOR_PROXY_INTERNAL_ORIGINS=https://api.internal.example.com:443

Multiple origins are comma-separated. Wildcards, URL paths, credentials, and IP literals are not accepted. Apply a configuration change with:

docker compose --env-file .env -f compose.production.yml up -d

Read Proxy Security before adding an exception.

Back up before real use

The installation bundle includes the application-owned online backup script:

cd "$HOME/conductor"
scripts/production/backup-conductor.sh \
  --compose-file compose.production.yml \
  --env-file .env \
  --backup-dir ./backups \
  --retention-days 7

Copy the resulting archive off the server and protect it like a password; it includes the database and recovery keys. Follow Production Operations for verified restore, upgrade, rollback, health, and log procedures.

Build from source instead

The downloaded tag is a complete source tree. To build the production image locally rather than pull the public image, create .env as above and run:

docker compose --env-file .env \
  -f compose.production.yml \
  -f compose.production.build.yml \
  up -d --build

This multi-stage build downloads Node packages, compiles the React frontend and TypeScript backend, and runs the same non-root production service. AMD64 is the validated release architecture; an ARM64 source build is not yet a supported release path.

Do not use docker-compose.yml for production. It is the two-container development environment.

Stop or uninstall

Stop and remove the application container while preserving its named data volume:

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

Do not add --volumes unless permanent data deletion is intentional and a verified off-host backup exists. Retain .env with the backup set even after removing the container.

For common failures, see Troubleshooting.