Docker
Docker is the recommended way to deploy Conloca. This guide provides a complete Dockerfile and docker-compose.yml for running your CMS in production.
Prerequisites
- Docker and Docker Compose installed on your server
- A built Astro site with Conloca configured (
bun run buildcompleted)
Dockerfile
Create a Dockerfile in your project root. This multi-stage build installs dependencies, builds the Astro site, and
creates a minimal runtime image:
FROM oven/bun:1 AS base
WORKDIR /app
# Install dependencies
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile --production
# Build stage
FROM base AS build
RUN bun install --frozen-lockfile
COPY . .
RUN bun run build
# Runtime
FROM oven/bun:1-slim AS runtime
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/package.json ./
ENV HOST=0.0.0.0
ENV PORT=4321
EXPOSE 4321
CMD ["bun", "run", "./dist/server/entry.mjs"]
The runtime image uses oven/bun:1-slim to keep the image size small. The Astro SSR entry point is at
dist/server/entry.mjs.
docker-compose.yml
Create a docker-compose.yml alongside the Dockerfile:
services:
conloca:
build: .
ports:
- '4321:4321'
environment:
- HOST=0.0.0.0
- PORT=4321
volumes:
- ./content:/app/content
- ./public/assets:/app/public/assets
restart: unless-stopped
The volume mounts are important:
./content:/app/content— Persists your content directory across container restarts. This is where pages, blocks, and data entries are stored../public/assets:/app/public/assets— Persists uploaded media assets.
Running
Build and start the container:
docker compose up -d
Verify the CMS is running:
curl http://localhost:4321
View logs:
docker compose logs -f conloca
Stop the container:
docker compose down
Adding authentication
Today, the documented authentication option for a Docker deployment is Cloudflare Access in front of the container. Add
the Cloudflare Access environment variables to docker-compose.yml:
services:
conloca:
build: .
ports:
- '4321:4321'
environment:
- HOST=0.0.0.0
- PORT=4321
- CF_ACCESS_TEAM_NAME=YOUR_TEAM_NAME
- CF_ACCESS_AUD=YOUR_APPLICATION_AUD_TAG
volumes:
- ./content:/app/content
- ./public/assets:/app/public/assets
restart: unless-stopped
No astro.config.mjs auth block is required for this setup on the current branch. See the
Cloudflare Access guide for the full configuration details.
Reverse proxy
For production, place a reverse proxy in front of the container to handle HTTPS termination. Here is a minimal Caddy example:
services:
conloca:
build: .
expose:
- '4321'
environment:
- HOST=0.0.0.0
- PORT=4321
volumes:
- ./content:/app/content
- ./public/assets:/app/public/assets
restart: unless-stopped
caddy:
image: caddy:2
ports:
- '80:80'
- '443:443'
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
restart: unless-stopped
volumes:
caddy_data:
With a Caddyfile:
cms.YOUR_DOMAIN.com {
reverse_proxy conloca:4321
}
Caddy automatically provisions and renews TLS certificates via Let’s Encrypt.
Git content persistence
The content directory should be a git repository for version history. Conloca stores content as files and exposes git
operations (commit, push, pull) through the CMS git panel. The volume mount (./content:/app/content) preserves the git
repository across container restarts.
Initialize git in your content directory if it does not already exist:
cd content
git init
git add .
git commit -m "Initial content"
Next steps
- Cloudflare Access — Zero-trust authentication
- Cloudflare Tunnel — Expose without opening ports
- Getting Started — Set up your first Conloca site