Deployment and configuration
Run Depsilo v0.11.0 with persistent state, readiness checks, diagnostics, and tested backup and restore.
Recommended Docker deployment
Section titled “Recommended Docker deployment”The following command keeps configuration, SQLite, and the local object cache in one named volume:
docker volume create depsilo-state
docker run -d --name depsilo \ -p 23333:23333 \ -v depsilo-state:/root/.depsilo \ --restart unless-stopped \ ghcr.io/depsilo/depsilo:0.11.0v0.11.0 setup writes absolute database and local-cache paths into its generated
configuration, so a new installation only needs to persist /root/.depsilo.
The official image runs as UID/GID 10001:10001; new named volumes inherit
that ownership. For an older root-running container or v0.9.0 Compose layout,
follow the versioned upgrade guide before reopening its state.
| State | Path in the container | Purpose |
|---|---|---|
| Configuration | /root/.depsilo/config.toml |
Generated by setup; may contain sensitive values |
| SQLite | /root/.depsilo/data/depsilo.db |
Authoritative users, policy, audit, and cache metadata |
| Local object cache | /root/.depsilo/data/cache |
Package artifacts; excluded from depsilo backup |
When storage.type is s3, only cache objects move to the remote backend.
Configuration and SQLite remain local state and still require persistence and
backup. An S3 backend does not make v0.11.0 multi-instance or highly available.
Bind-mounted state
Section titled “Bind-mounted state”Use a host directory instead of a named volume when host-side tools must read
or back up the state root directly. Keep the mount target at /root/.depsilo
and prepare ownership for the image’s fixed 10001:10001 identity first:
state_dir="$HOME/.local/share/depsilo/state"mkdir -p "$state_dir"docker run --rm --user 0:0 \ --entrypoint /bin/chown \ --mount "type=bind,src=$state_dir,dst=/root/.depsilo" \ ghcr.io/depsilo/depsilo:0.11.0 \ -R 10001:10001 /root/.depsilo
docker run -d --name depsilo \ -p 23333:23333 \ --mount "type=bind,src=$state_dir,dst=/root/.depsilo" \ ghcr.io/depsilo/depsilo:0.11.0Keep one state source per instance: switching between a named volume and a bind
mount starts from a different state unless you migrate it explicitly. The
repository ships compose.yaml (named volume) and compose.bind.yaml (host
directory); both accept DEPSILO_IMAGE, DEPSILO_BIND_ADDRESS, and PORT.
Complete first-time setup
Section titled “Complete first-time setup”docker logs depsiloOpen http://localhost:23333, enter the one-time bootstrap token from the
startup log, and create the first administrator. Depsilo has no default
admin/admin account. Do not expose startup logs; protect or retire retained
bootstrap log data according to your log policy after setup.
Use a single binary
Section titled “Use a single binary”For a new installation, use the Linux or macOS amd64 / arm64 archive. This POSIX shell script selects the stable asset for your system, checks its SHA-256, and installs it at ~/.local/bin/depsilo. It requires curl, tar, and either sha256sum or macOS’s built-in shasum. For an existing instance, back up its state and follow the matching upgrade procedure first.
( set -eu case "$(uname -s)" in Linux) depsilo_os=linux ;; Darwin) depsilo_os=darwin ;; *) printf 'Use the Windows archive from the release page.\n' >&2; exit 1 ;; esac case "$(uname -m)" in x86_64|amd64) depsilo_arch=amd64 ;; aarch64|arm64) depsilo_arch=arm64 ;; *) printf 'Unsupported CPU architecture.\n' >&2; exit 1 ;; esac depsilo_archive="depsilo_0.11.0_${depsilo_os}_${depsilo_arch}.tar.gz" depsilo_release='https://github.com/depsilo/depsilo/releases/download/v0.11.0' depsilo_download_dir=$(mktemp -d "${TMPDIR:-/tmp}/depsilo-install.XXXXXX") trap 'rm -rf "$depsilo_download_dir"' EXIT cd "$depsilo_download_dir" curl -fSL "$depsilo_release/$depsilo_archive" -o "$depsilo_archive" curl -fSL "$depsilo_release/checksums.txt" -o checksums.txt awk -v archive="$depsilo_archive" '$2 == archive' checksums.txt > selected.sha256 test -s selected.sha256 if command -v sha256sum >/dev/null 2>&1; then sha256sum -c selected.sha256 else shasum -a 256 -c selected.sha256 fi tar -xzf "$depsilo_archive" depsilo mkdir -p "$HOME/.local/bin" install -m 0755 depsilo "$HOME/.local/bin/depsilo")Asset names include depsilo_0.11.0_linux_amd64.tar.gz. Windows ZIP archives and all checksum files are on the v0.11.0 release page. For signature checks, follow the release verification guide.
Start the service in the foreground and keep this terminal open to read the bootstrap token:
cd "$HOME""$HOME/.local/bin/depsilo" version"$HOME/.local/bin/depsilo" serve --host 127.0.0.1 --port 23333Open http://localhost:23333 to complete setup, then run the readiness check and first request from the quick start in another terminal. HTTPS is not required for this local check. With no explicit configuration file, a new installation saves configuration, the database, and local cache under the running user’s ~/.depsilo/. Run only one process against that state. Stop with Ctrl+C and resume with the same serve command. For continuous operation, configure a service manager with the same user and configuration path.
Configure HTTPS for other devices
Section titled “Configure HTTPS for other devices”Use http://127.0.0.1:23333 for the local check. For HTTPS access from other devices, run Caddy on the same Linux host and proxy to Depsilo’s loopback HTTP port. This example assumes clients connect directly to Caddy; a CDN or another proxy requires its own trust configuration.
- Keep the backend port local. For a binary installation, use
--host 127.0.0.1as above. For the quick-start Docker container, the following commands briefly stop service and recreate its port mapping while retaining the originaldepsilo-statenamed volume. They apply only to that volume name and mount layout; adapt other installations to their existing mounts first.
docker stop depsilodocker rm depsilodocker run -d --name depsilo --restart unless-stopped \ -p 127.0.0.1:23333:23333 \ -v depsilo-state:/root/.depsilo \ ghcr.io/depsilo/depsilo:0.11.0- Prepare a domain and Caddy. Follow the official installation instructions for a Linux package with the systemd service. Point your domain’s A/AAAA records at this host, allow the certificate checks on ports 80/443, and persist Caddy’s certificate data. Replace
depsilo.example.combelow with your domain and add this site to/etc/caddy/Caddyfile, keeping any existing sites:
depsilo.example.com { reverse_proxy 127.0.0.1:23333 { header_up Host {hostport} }}The proxy retains the public Host and sets X-Forwarded-Proto so Depsilo generates HTTPS artifact URLs. Caddy manages certificates for qualifying public domains. Internal names require an internal CA trusted by every client. See automatic HTTPS and proxy headers.
- Validate and load the configuration. These commands assume the official
caddysystemd service is already running; for its initial start, follow the service guide.
sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfilesudo systemctl reload caddy- Check the HTTPS endpoint from a client. Replace the domain and run without disabling certificate verification:
DEPSILO_URL='https://depsilo.example.com'curl -fsS "$DEPSILO_URL/ready"curl -fsS "$DEPSILO_URL/npm/is-number" -o /dev/null -w 'HTTP %{http_code}\n'After HTTP 200, find this is-number request in Admin → Access logs at the same HTTPS address. Follow Verify caching to check returned artifact URLs and downloads, then use this HTTPS endpoint in client configuration.
server.trusted_proxies controls trust in forwarded client IPs and trusts no proxies by default. To record original client IPs, add only the proxy addresses Depsilo actually sees; a host proxy reaching a Docker container may not appear as 127.0.0.1. This setting does not replace Host / X-Forwarded-Proto forwarding. Do not trust every address just to recover client IPs.
Configuration sources and precedence
Section titled “Configuration sources and precedence”v0.11.0 resolves the same setting in this order, highest precedence first:
- CLI flag
DEPSILO_*environment variableconfig.toml- Built-in default
For example, server.port maps to DEPSILO_SERVER_PORT and
cache.ttl_index maps to DEPSILO_CACHE_TTL_INDEX. Set DEPSILO_CONFIG
to select a file. Without it, Depsilo searches ./config.toml,
/app/config.toml, and ~/.depsilo/config.toml.
The most deployment-sensitive differences are:
| Setting | v0.11.0 built-in default | v0.11.0 example | Production guidance |
|---|---|---|---|
server.host |
127.0.0.1 |
0.0.0.0 |
The official container sets DEPSILO_SERVER_HOST=0.0.0.0; binary installs widen it deliberately or sit behind a TLS proxy |
server.port |
23333 |
23333 |
Keep probes and client URLs in sync when changing it |
database.dsn |
./data/depsilo.db |
./data/depsilo.db |
Use an absolute path in the container volume |
storage.path |
./data/cache |
./data/cache |
Use an absolute path in the container volume |
cache.max_size_gb |
20 |
20 |
Size for artifact volume and disk budget |
cache.ttl_index |
5m |
1h |
Choose for your metadata freshness requirement |
cache.ttl_blob |
72h |
72h |
Evaluate with capacity and offline tolerance |
auth.enabled |
true |
true |
Keep authentication enabled for the admin plane |
auth.token_ttl |
168h |
168h |
Shorten to match your session policy |
When no configuration file exists, v0.11.0 relocates the effective database and
cache defaults under ~/.depsilo/data/ and generates a temporary secure JWT
secret for setup. This is special missing-file behavior; it does not make the
placeholder in an explicit example configuration safe.
With an explicit configuration, a non-loopback listener refuses to start when
auth.jwt_secret = "change-me-in-production". Inject a random value through
your secret manager, for example:
export DEPSILO_AUTH_JWT_SECRET="$(openssl rand -hex 32)"Do not commit the secret or send it through public logs.
Configuration authority for upstreams
Section titled “Configuration authority for upstreams”On first upgrade or activation, Depsilo seeds ordinary ecosystem upstreams into the database. After that import, Admin and the database are authoritative: restarts do not recreate an upstream that an operator changed or deleted. Adding configuration for a previously inactive supported ecosystem can activate that ecosystem on the next restart.
Docker registries and extra indexes remain configuration-owned and are not managed by ordinary Admin Upstream CRUD. Deployment automation should distinguish these sources rather than treating the file as a continuous source of truth for all runtime state.
Readiness and diagnostics
Section titled “Readiness and diagnostics”/ready checks SQLite and object storage and returns a non-2xx response when
either is unavailable. It intentionally excludes upstream health because
Depsilo may still serve cached packages during an upstream outage.
curl -fsS http://127.0.0.1:23333/ready
docker exec depsilo /app/depsilo doctordocker exec depsilo /app/depsilo doctor --jsonThe container image health check also uses /ready. Use it to decide whether
an orchestrator should send traffic to the instance; use /health only as a
process liveness signal. doctor additionally checks version alignment,
storage, upstreams, and cache hit rate. Without DEPSILO_TOKEN it reports
fewer protected admin details, but its basic diagnostics still run.
Backup and restore
Section titled “Backup and restore”depsilo backup can create a consistent SQLite snapshot while the service is
running. Write the archive to the state volume and copy it to a controlled
backup location outside the container:
docker exec depsilo mkdir -p /root/.depsilo/backupsdocker exec depsilo /app/depsilo backup \ --out /root/.depsilo/backups/depsilo-backup.tar.gzdocker cp depsilo:/root/.depsilo/backups/depsilo-backup.tar.gz .The archive contains only the config.toml file and a consistent SQLite snapshot. It
does not contain local or S3 cache objects. Treat it as sensitive because it
contains users, policies, audit data, and potentially secret configuration.
Encrypt it, restrict access, and copy it outside the deployment failure domain.
Protect cache data separately or accept that it will be fetched again.
On ordinary Linux Docker, docker cp usually makes the exported archive owned
by the host user running the command, while depsilo backup creates it with
mode 0600. If that host owner is not 10001:10001 inside the container, a
read-only bind mount may be unreadable by the default non-root restore process.
This does not occur in every Docker environment.
Run the following in the directory holding the archive. It expects this page’s
depsilo container and depsilo-state named volume. The script checks the
archive, running container, and image version, then creates a separate temporary
input volume. Only a preparation container runs as root to copy the archive and
set ownership; the input directory stays 0700 and the archive 0600. It
checks access from a read-only mount as the image’s default non-root user
before stopping the service. The actual restore also runs as that user,
which owns the resulting state files. On preparation failure, the script does
not stop the service and attempts to remove only this temporary volume. Ensure
the source archive is trusted before copying it into the volume.
sh -eu <<'RESTORE'image='ghcr.io/depsilo/depsilo:0.11.0'archive="$PWD/depsilo-backup.tar.gz"if ! test -f "$archive" || ! test -r "$archive"; then echo 'Backup archive is missing or unreadable; aborting.' >&2 exit 1fitest "$(docker inspect --format '{{.State.Running}}' depsilo)" = truetest "$(docker inspect --format '{{.Image}}' depsilo)" = \ "$(docker image inspect --format '{{.Id}}' "$image")"test "$(docker inspect --format '{{range .Mounts}}{{if and (eq .Type "volume") (eq .Destination "/root/.depsilo")}}{{.Name}}{{end}}{{end}}' depsilo)" = depsilo-state
input_volume="depsilo-restore-input-$(date +%s)-$$"if docker volume inspect "$input_volume" >/dev/null 2>&1; then echo 'Input volume already exists; aborting.' >&2 exit 1fidocker volume create "$input_volume" >/dev/nulltrap 'docker volume rm "$input_volume" >/dev/null || true' 0
docker run --rm --user 0:0 --entrypoint /bin/sh \ -v "$archive:/source/depsilo-backup.tar.gz:ro" \ --mount "type=volume,src=$input_volume,dst=/backup" \ "$image" -ec ' cp /source/depsilo-backup.tar.gz /backup/depsilo-backup.tar.gz chown 10001:10001 /backup /backup/depsilo-backup.tar.gz chmod 0700 /backup chmod 0600 /backup/depsilo-backup.tar.gz 'docker run --rm --entrypoint /bin/sh \ --mount "type=volume,src=$input_volume,dst=/backup,readonly" \ "$image" -ec ' test "$(id -u):$(id -g)" = 10001:10001 test "$(stat -c "%u:%g:%a" /backup)" = 10001:10001:700 test "$(stat -c "%u:%g:%a" /backup/depsilo-backup.tar.gz)" = 10001:10001:600 test -r /backup/depsilo-backup.tar.gz test -s /backup/depsilo-backup.tar.gz 'trap - 0
docker stop depsilodocker run --rm \ -v depsilo-state:/root/.depsilo \ --mount "type=volume,src=$input_volume,dst=/backup,readonly" \ -e DEPSILO_CONFIG=/root/.depsilo/config.toml \ -e DEPSILO_DATABASE_DSN=/root/.depsilo/data/depsilo.db \ -e DEPSILO_STORAGE_PATH=/root/.depsilo/data/cache \ "$image" restore /backup/depsilo-backup.tar.gzdocker start depsilocurl -fsS http://127.0.0.1:23333/readyprintf '\nAfter checking Admin, policies and a client fetch, remove only this input volume:\ndocker volume rm %s\n' "$input_volume"RESTORE/ready only checks readiness. Verify admin login, policies, upstreams, and a
real client package fetch. Only after manual verification succeeds, run the
printed docker volume rm command to remove this run’s temporary input volume.
If restore, startup, or verification fails, keep the original backup and
depsilo-state intact; retain the input volume while investigating and deciding
how to roll back. Rehearse the whole procedure in isolation first: creating an
archive does not verify a restore.
Docker Desktop, rootless Docker, user namespace mappings, and unusual volume
drivers may map file ownership differently. If the preparation container cannot
read the host archive or change volume ownership, it stops before downtime;
check your environment’s mappings and volume permissions instead of widening
the archive to 0644 or running the actual restore as root.
Audit-chain checkpoints
Section titled “Audit-chain checkpoints”[audit] checkpoint_file appends audit chain-head checkpoints as NDJSON with
fsync, and depsilo audit verify, the integrity API, and the audit page
cross-check every line. The checkpoint must live outside the database’s
failure domain: mount it on a controlled host directory, or push it to a WORM
gateway or log platform with [audit] checkpoint_url. Keeping both next to
each other leaves a full-database rewrite undetectable. Checkpoints are
written every 15 minutes by default; checkpoint_interval changes that.
Pre-production checklist
Section titled “Pre-production checklist”- Pin the
0.11.0tag, or an image digest when stronger reproducibility is required. - Expose the service through a TLS reverse proxy or controlled network, and restrict the Admin and setup surfaces.
- Persist configuration, SQLite, and the local cache; apply least privilege to the state volume and backups.
- Put JWT and other secrets in a secret manager, not an image or repository.
- Route traffic with
/ready, diagnose the whole path withdoctor, and rehearse restores regularly.