Running Foundry with Docker
Foundry ships two Docker Compose shapes: a local-development default and a stricter production-oriented setup. This page explains when to use each one and what each overlay expects.
Default Docker workflow
The default docker-compose.yml is meant for local development. It keeps the
source tree bind-mounted into the container so code, themes, and content edits are
reflected immediately.
sh scripts/docker-init.sh
docker compose up -d --build
That setup:
- bind-mounts the project root into
/app - keeps
data/andpublic/on named Docker volumes - uses
content/config/site.docker.yamlas the config overlay - reads local Docker secrets from
.envwhen present -
can bootstrap a local
.envwithscripts/docker-init.sh
Local secret bootstrap
scripts/docker-init.sh creates a local .env file if one does
not exist and fills in:
FOUNDRY_PUBLISH_ADDRFOUNDRY_ADMIN_SESSION_SECRETFOUNDRY_ADMIN_TOTP_SECRET_KEY
Those values are for local Docker convenience. They are not the production deployment path.
Production-oriented Docker workflow
The stricter setup lives in docker-compose.prod.yml. Use it when you want a
safer immutable-style container shape instead of a source-mounted development container.
export FOUNDRY_ADMIN_SESSION_SECRET="$(openssl rand -hex 32)"
export FOUNDRY_ADMIN_TOTP_SECRET_KEY="$(openssl rand -base64 32)"
docker compose -f docker-compose.prod.yml up -d --build
That setup:
- requires explicit session and TOTP secrets
- runs with a read-only root filesystem
- uses
tmpfsfor/tmp - drops Linux capabilities
- enables
no-new-privileges -
uses named volumes for
content/,themes/,plugins/,data/, andpublic/ - uses
content/config/site.docker.prod.yamlas the config overlay
Important config overlays
-
content/config/site.docker.yaml: development-oriented Docker defaults like local base URL and live reload enabled. -
content/config/site.docker.prod.yaml: production-shaped Docker defaults like disabled live reload, disabled debug surfaces, and explicit production environment labeling.
Before using the production overlay, set
content/config/site.docker.prod.yaml base_url to the real
HTTPS origin for the deployment.
Operational notes
-
Set strong values for
FOUNDRY_ADMIN_SESSION_SECRETandFOUNDRY_ADMIN_TOTP_SECRET_KEYin production. - Keep the production admin behind HTTPS so secure cookies behave correctly.
- The default Docker setup is convenient for development, but the production compose file is the right base for a real deployment.
-
The Dockerfile creates runtime directories inside the image; generated output belongs
on the writable
public/volume, not in the image layer.
Published GitHub Container Registry images
Release tags publish two OCI images to
ghcr.io/sphireinc:
-
ghcr.io/sphireinc/foundry-runtimeruns Foundry as a long-lived server. -
ghcr.io/sphireinc/foundry-static-runtimebuilds a checked-out Foundry site mounted at/repo.
Use the static image with the invoking user's UID and GID so the generated
public/ files remain writable on the host:
docker run --rm \
--user "$(id -u):$(id -g)" \
--mount "type=bind,src=$PWD,dst=/repo" \
--workdir /repo \
ghcr.io/sphireinc/foundry-static-runtime:latest \
foundry build
The workflow checks the registry and refuses to overwrite an existing versioned release
tag. The latest tag is updated for convenience. Both images publish
linux/amd64 and linux/arm64 variants. They are built with OCI
source, version, revision, and creation-date labels so GitHub can associate them with
this repository.
If a release fails after publishing only one versioned image, delete any versioned tags created by that partial run in GHCR before retrying, or use a new release version. Versioned tags are never overwritten.
GitHub creates a newly published package as private. An organization or repository administrator must change both package visibility settings to Public before unauthenticated pulls will work.
Related docs
Container provenance and updates
Image tags and source release tags are distinct. Embedded commit, build date, platform, and modification state identify the binary; Foundry cannot infer the registry digest inside the container. Pull and recreate images through deployment tooling. See build identity and update guidance.
