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 composeplugin. 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 GNUstat.- 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
-
Sign in and create a small project in Visual Editor.
-
Save it, restart the container, and sign in again:
cd "$HOME/conductor" docker compose --env-file .env -f compose.production.yml restart conductor -
Load the saved project and confirm it persisted.
-
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.