Skip to content

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 build completed)

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