Before you begin
- A Linux x64/amd64 host with Docker Engine
- A pinned Community Edition image reference from /download
- An initial organization-admin email and a long random password
- For access from another device: a stable HTTPS public origin plus the required DNS, proxy, and firewall configuration
- Before rollout: a compatible Orchestris Admin build or Admin origin supplied through the release handoff or Orchestris support
Know the Community Edition boundary
- Community Edition is free and does not require a license key or licensing-portal connection.
- The server enforces one organization and up to 8 organization users.
- The Docker image is a single-node SQLite deployment. Its database and generated secrets live together under /data.
- The current Docker target is Linux x64/amd64. Use /download for the published tag and immutable digest.
- The image includes hosted Chat at /app/ but does not include the Orchestris Admin UI.
Prepare the pinned image and persistent volume
export ORCHESTRIS_IMAGE="ghcr.io/orchestris-inc/orchestris-server-community:<VERSION>"
export ORCHESTRIS_PUBLIC_URL="http://localhost:8080"
export ORCHESTRIS_ADMIN_EMAIL="<ADMIN_EMAIL>"
docker pull "$ORCHESTRIS_IMAGE"
docker volume create orchestris-dataThe template is intentionally local-only. Before allowing another device to connect, set ORCHESTRIS_PUBLIC_URL to the stable HTTPS origin those clients will open and finish the DNS, reverse-proxy or server TLS, and firewall configuration for that origin.
Validate configuration and create the first administrator
docker run --rm \
-v orchestris-data:/data \
-e ORCHESTRIS_SERVER__PUBLIC_BASE_URL="$ORCHESTRIS_PUBLIC_URL" \
"$ORCHESTRIS_IMAGE" config-checkread -rsp "Initial admin password: " ORCHESTRIS_ADMIN_PASSWORD
printf '\n'
docker run --rm \
-v orchestris-data:/data \
-e ORCHESTRIS_SERVER__PUBLIC_BASE_URL="$ORCHESTRIS_PUBLIC_URL" \
-e ORCHESTRIS_LOCAL_INIT_ADMIN_PASSWORD="$ORCHESTRIS_ADMIN_PASSWORD" \
"$ORCHESTRIS_IMAGE" \
local-init --admin-email "$ORCHESTRIS_ADMIN_EMAIL"
unset ORCHESTRIS_ADMIN_PASSWORDA successful run prints orchestris-local-init completed, the organization ID, and the organization-admin user ID. The entrypoint also creates /data/orchestris.env with encryption, API-key pepper, sync cursor, and hashing secrets and protects it with restrictive permissions.
Start the server and verify it
docker run -d \
--name orchestris-ce \
--restart unless-stopped \
-p 8080:8080 \
-v orchestris-data:/data \
-e ORCHESTRIS_SERVER__PUBLIC_BASE_URL="$ORCHESTRIS_PUBLIC_URL" \
"$ORCHESTRIS_IMAGE"curl --fail --silent --show-error "http://127.0.0.1:8080/health"
docker logs --tail 100 orchestris-ce- 1
Open hosted Chat
Append /app/ to the ORCHESTRIS_PUBLIC_URL value and open it in a browser. For the local-only template, use http://localhost:8080/app/. Sign in with the organization-admin email and password created during local-init.
- 2
Connect desktop Chat
In the desktop application, open Servers, choose Add Server, select Custom server, enter ORCHESTRIS_PUBLIC_URL, and sign in.
- 3
Configure administration
Using the compatible Admin build or Admin origin supplied through your handoff or Orchestris support, add providers and models, then grant models or aliases to a group before onboarding members. The CE image itself does not provide this Admin surface.
Advanced: back up and test recovery
A usable backup keeps every /data file together, including the SQLite database and the keys required to use protected data. The script below stops the service, writes the archive and checksum into the current working directory, and restarts the service. Run it from protected storage with enough free space for the complete volume.
Show the complete backup script
bash <<'ORCHESTRIS_BACKUP'
set -Eeuo pipefail
export BACKUP_DIR="$PWD"
BACKUP_NAME="orchestris-data-$(date -u +%Y%m%dT%H%M%SZ).tar.gz"
BACKUP_FILE="$BACKUP_DIR/$BACKUP_NAME"
CHECKSUM_FILE="$BACKUP_FILE.sha256"
if [ -e "$BACKUP_FILE" ] || [ -e "$CHECKSUM_FILE" ]; then
printf '%s\n' "ERROR: refusing to overwrite an existing backup or checksum." >&2
exit 1
fi
TEMP_BACKUP="$(mktemp "$BACKUP_DIR/.$BACKUP_NAME.partial.XXXXXX")"
if ! TEMP_CHECKSUM="$(mktemp "$BACKUP_DIR/.$BACKUP_NAME.sha256.partial.XXXXXX")"; then
rm -f -- "$TEMP_BACKUP"
exit 1
fi
TEMP_BACKUP_NAME="$(basename "$TEMP_BACKUP")"
restart_required=0
backup_complete=0
cleanup_backup() {
status=$?
trap - EXIT INT TERM
if ! rm -f -- "$TEMP_BACKUP" "$TEMP_CHECKSUM"; then
printf '%s\n' "ERROR: temporary backup files could not be removed." >&2
status=1
fi
if [ "$backup_complete" -ne 1 ]; then
if ! rm -f -- "$BACKUP_FILE" "$CHECKSUM_FILE"; then
printf '%s\n' "ERROR: incomplete backup files could not be removed." >&2
status=1
fi
fi
if [ "$restart_required" -eq 1 ]; then
if ! docker start orchestris-ce >/dev/null; then
printf '%s\n' "ERROR: orchestris-ce did not restart; start it manually." >&2
status=1
fi
fi
exit "$status"
}
trap cleanup_backup EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
restart_required=1
docker stop orchestris-ce >/dev/null
test "$(docker inspect --format '{{.State.Running}}' orchestris-ce)" = false
docker run --rm \
-v orchestris-data:/source:ro \
-v "$BACKUP_DIR":/backup \
busybox:1.37 \
tar -czf "/backup/$TEMP_BACKUP_NAME" -C /source .
docker run --rm \
-v "$BACKUP_DIR":/backup:ro \
busybox:1.37 sh -c '
set -eu
tar -tzf "$1" >/dev/null
tar -tzf "$1" | grep -qx "./orchestris.db"
tar -tzf "$1" | grep -qx "./orchestris.env"
' sh "/backup/$TEMP_BACKUP_NAME"
BACKUP_SHA256="$(sha256sum -- "$TEMP_BACKUP" | cut -d ' ' -f 1)"
printf '%s %s\n' "$BACKUP_SHA256" "$BACKUP_NAME" > "$TEMP_CHECKSUM"
mv -- "$TEMP_BACKUP" "$BACKUP_FILE"
mv -- "$TEMP_CHECKSUM" "$CHECKSUM_FILE"
(
cd "$BACKUP_DIR"
sha256sum --check "$(basename "$CHECKSUM_FILE")"
)
backup_complete=1
docker start orchestris-ce >/dev/null
restart_required=0
trap - EXIT INT TERM
printf 'Backup: %s\nChecksum: %s\n' "$BACKUP_FILE" "$CHECKSUM_FILE"
ORCHESTRIS_BACKUPThe command refuses to overwrite an existing result, verifies that orchestris-ce is stopped, writes to temporary files, validates that the gzip archive can be listed and contains both orchestris.db and orchestris.env, then publishes the archive and checksum. Its EXIT trap restarts orchestris-ce after an error or interruption and removes an incomplete result.
The recovery block is a template. Replace <BACKUP_FILE> with the archive filename printed by the backup script, including its .tar.gz extension. Keep the matching .sha256 file beside it.
Show the complete recovery-test script
bash <<'ORCHESTRIS_RECOVERY'
set -Eeuo pipefail
export BACKUP_FILE="$PWD/<BACKUP_FILE>"
BACKUP_DIR="$(dirname "$BACKUP_FILE")"
BACKUP_NAME="$(basename "$BACKUP_FILE")"
CHECKSUM_NAME="$BACKUP_NAME.sha256"
RECOVERY_SUFFIX="$(date -u +%Y%m%dT%H%M%SZ)-$$"
RECOVERY_VOLUME="orchestris-data-restored-$RECOVERY_SUFFIX"
RECOVERY_CONTAINER="orchestris-ce-recovery-$RECOVERY_SUFFIX"
RECOVERY_PUBLIC_URL="http://127.0.0.1:18080"
if docker container inspect "$RECOVERY_CONTAINER" >/dev/null 2>&1; then
printf '%s\n' "ERROR: refusing to reuse an existing recovery container." >&2
exit 1
fi
if docker volume inspect "$RECOVERY_VOLUME" >/dev/null 2>&1; then
printf '%s\n' "ERROR: refusing to reuse an existing recovery volume." >&2
exit 1
fi
cleanup_recovery() {
status=$?
trap - EXIT INT TERM
if docker container inspect "$RECOVERY_CONTAINER" >/dev/null 2>&1; then
if ! docker rm -f "$RECOVERY_CONTAINER" >/dev/null; then
printf '%s\n' "ERROR: recovery container cleanup failed." >&2
status=1
fi
fi
if docker volume inspect "$RECOVERY_VOLUME" >/dev/null 2>&1; then
if ! docker volume rm "$RECOVERY_VOLUME" >/dev/null; then
printf '%s\n' "ERROR: recovery volume cleanup failed." >&2
status=1
fi
fi
return "$status"
}
trap cleanup_recovery EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
test -f "$BACKUP_FILE"
test -f "$BACKUP_FILE.sha256"
(
cd "$BACKUP_DIR"
sha256sum --check "$CHECKSUM_NAME"
)
docker run --rm \
-v "$BACKUP_DIR":/backup:ro \
busybox:1.37 sh -c '
set -eu
tar -tzf "$1" >/dev/null
tar -tzf "$1" | grep -qx "./orchestris.db"
tar -tzf "$1" | grep -qx "./orchestris.env"
' sh "/backup/$BACKUP_NAME"
docker volume create "$RECOVERY_VOLUME" >/dev/null
docker run --rm \
-v "$RECOVERY_VOLUME":/target \
-v "$BACKUP_DIR":/backup:ro \
busybox:1.37 \
tar -xzf "/backup/$BACKUP_NAME" -C /target
docker run --rm \
-v "$RECOVERY_VOLUME":/target:ro \
busybox:1.37 sh -c \
'test -s /target/orchestris.db && test -s /target/orchestris.env'
docker run -d \
--name "$RECOVERY_CONTAINER" \
-p 127.0.0.1:18080:8080 \
-v "$RECOVERY_VOLUME":/data \
-e ORCHESTRIS_SERVER__PUBLIC_BASE_URL="$RECOVERY_PUBLIC_URL" \
"$ORCHESTRIS_IMAGE" >/dev/null
recovery_ready=0
for attempt in {1..30}; do
if curl --fail --silent --show-error --output /dev/null \
"$RECOVERY_PUBLIC_URL/health"; then
recovery_ready=1
break
fi
sleep 1
done
if [ "$recovery_ready" -ne 1 ]; then
docker logs --tail 100 "$RECOVERY_CONTAINER" >&2
exit 1
fi
docker logs --tail 100 "$RECOVERY_CONTAINER"
printf 'Recovery process is responding at %s/app/\n' "$RECOVERY_PUBLIC_URL"
read -r -p "Complete the product checks below, then press Enter to remove the recovery clone: " _ </dev/tty
cleanup_recovery
ORCHESTRIS_RECOVERY- 1
Sign in with restored credentials
Open http://127.0.0.1:18080/app/ and sign in with a user email and password that existed before the backup. Confirm the expected organization, server-backed conversations, projects, and representative attachments are present.
- 2
Check restored administration records
Using the separately supplied, release-compatible Admin surface against the recovery origin, confirm the expected users, groups, model grants, providers, models, aliases, organization API-key policy, and a representative usage record.
- 3
Confirm saved credentials still work
Test a configured provider or run one minimal inference to confirm its saved credential still works. If available, authenticate one API key created before the backup against /openai/v1/models. Do not use or expose production credentials beyond this isolated test.
- 4
Remove the clone
Return to the waiting shell and press Enter. The cleanup handler removes the recovery container and its temporary volume on success and is registered as an EXIT trap for failures or interruptions; it reports a cleanup failure. The source orchestris-data volume is never mounted into the recovery container.
Advanced: upgrade a pinned deployment
- 1
Read the release notes
Confirm upgrade prerequisites, breaking changes, and any release-specific migration or rollback instructions.
- 2
Pull the next pinned image
Use the exact tag or digest shown on /download. Keep the previous image reference until recovery is verified.
- 3
Stop and back up
Stop orchestris-ce and archive the complete orchestris-data volume using the backup procedure above.
- 4
Recreate the container
Remove only the stopped container, not the volume. Run the new pinned image with the same volume, public origin, port, and restart policy.
- 5
Verify before reopening access
Check /health, review startup logs, open /app/, sign in, and verify provider and model access.
The command below is a template. Replace <NEW_VERSION> with the exact next version shown on /download, or use that release's immutable digest.
export NEXT_ORCHESTRIS_IMAGE="ghcr.io/orchestris-inc/orchestris-server-community:<NEW_VERSION>"
docker pull "$NEXT_ORCHESTRIS_IMAGE"
docker stop orchestris-ce
# Create and verify a complete /data backup before continuing.
docker rm orchestris-ce
docker run -d \
--name orchestris-ce \
--restart unless-stopped \
-p 8080:8080 \
-v orchestris-data:/data \
-e ORCHESTRIS_SERVER__PUBLIC_BASE_URL="$ORCHESTRIS_PUBLIC_URL" \
"$NEXT_ORCHESTRIS_IMAGE"
curl --fail --silent --show-error "http://127.0.0.1:8080/health"
docker logs --tail 100 orchestris-ceAdvanced: stop or remove the Docker deployment
docker stop orchestris-ce
docker rm orchestris-ce
docker volume inspect orchestris-dataThe container is replaceable. The named orchestris-data volume is the deployment: it contains the SQLite database, generated secrets, authentication keys, and other persistent state. Removing the container leaves that volume available for a reinstall or recovery.