Some checks failed
Release production image / production-image (push) Has been cancelled
241 lines
9.7 KiB
Markdown
241 lines
9.7 KiB
Markdown
# 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](https://docs.docker.com/engine/install/) and [Compose plugin guide](https://docs.docker.com/compose/install/linux/) 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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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.
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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](https://caddyserver.com/docs/install). Add this site block to `/etc/caddy/Caddyfile`:
|
|
|
|
```caddyfile
|
|
conductor.example.com {
|
|
reverse_proxy 127.0.0.1:8080
|
|
encode zstd gzip
|
|
}
|
|
```
|
|
|
|
Then validate and reload it:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```nginx
|
|
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:
|
|
|
|
```text
|
|
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](ADMIN_GUIDE.md).
|
|
|
|
## 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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```dotenv
|
|
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:
|
|
|
|
```bash
|
|
docker compose --env-file .env -f compose.production.yml up -d
|
|
```
|
|
|
|
Read [Proxy Security](PROXY_SECURITY.md) before adding an exception.
|
|
|
|
## Back up before real use
|
|
|
|
The installation bundle includes the application-owned online backup script:
|
|
|
|
```bash
|
|
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](OPERATIONS.md) 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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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](TROUBLESHOOTING.md).
|