Headless CMS. Nestable blocks, live collaborative editing, versioning, cached REST API. AGPLv3.
3.0K
The opinionated headless CMS. Model content as reusable blocks, edit it visually with your team in real time, deliver it anywhere through a fast, cached Data API.
Self-host the full product under AGPL-3.0 — no enterprise edition, no license keys, no feature gates — or use b10cks Cloud.
Website · Documentation · GitHub · Discord
On any machine with Docker:
curl -fsSL https://get.b10cks.com | sh
The installer writes a compose stack into ./b10cks, generates a database password, starts everything, and waits for the health check. It is scripts/install.sh — read it before piping it to a shell, as you should with any such command.
Then open http://localhost:8000 and create the first account. Do this immediately: a fresh instance accepts open sign-ups only until the first account exists — that account becomes the owner and everyone after joins by invitation.
curl -LO https://raw.githubusercontent.com/b10cks/cms/main/docker-compose.yml
curl -Lo .env https://raw.githubusercontent.com/b10cks/cms/main/.env.docker.example
# edit .env: APP_URL, DB_ROOT_PASSWORD, mail settings
docker compose up -d
On first boot the container generates an APP_KEY (persisted on the storage volume) and runs the installer automatically. Optional services sit behind compose profiles:
docker compose --profile redis --profile opensearch --profile reverb up -d
| Tag | Meaning |
|---|---|
latest | Newest release |
v2026.7.29-5acd0668 | A specific release — pin this in production |
Multi-arch manifests for linux/amd64 and linux/arm64; Docker picks the right one automatically. Mirrored to ghcr.io/b10cks/cms — useful if you hit Docker Hub's unauthenticated pull limit.
Images are published with build provenance attestations and an SBOM.
FrankenPHP (PHP 8.5, Alpine) running Laravel Octane under supervisord, plus the queue workers and the scheduler — one container is a complete, working instance. ffmpeg, libvips and libheif are included for video previews and fast image processing.
/app/storage — uploads, transfers, SQLite space databases, and the generated APP_KEYGET /mgmt/v1/healthapp, uid 1000); application code is root-owned and read-only to the runtimeThe same image serves the websocket process — set B10CKS_SUPERVISORD_CONF=/etc/supervisord-reverb.conf (the bundled compose file does this for you under the reverb profile).
Everything is standard Laravel .env configuration. The essentials:
| Variable | Default | Purpose |
|---|---|---|
APP_URL | http://localhost:8000 | Public URL of the instance |
APP_KEY | generated | Encrypts secrets at rest — back it up |
B10CKS_EDITION | self-hosted | Disables the SaaS billing surface, seeds one unlimited plan |
B10CKS_INSTALL_PROFILE | standard | standard = one database per space (needs admin DB credentials); shared = one database with per-space table prefixes |
B10CKS_AUTO_SETUP | true | Run the installer/upgrader on boot |
DB_* | — | MySQL 8.0+ / MariaDB connection |
QUEUE_CONNECTION / CACHE_STORE / SESSION_DRIVER | database / file / database | Redis recommended at scale |
FILESYSTEM_DISK | local | local, s3, or gcs for uploaded assets |
BROADCAST_DRIVER | null | Set to reverb for live collaboration and presence |
OPENSEARCH_HOST | — | Optional; MySQL fulltext is the default search driver |
AI_MODE / OPENROUTER_API_KEY | single / empty | Optional AI features; empty key disables them |
MAIL_* | log | Invites, notifications, password resets |
TRUSTED_PROXIES / TRUSTED_HOSTS | empty | Required behind a load balancer or CDN |
Full reference: Configuration.
The stack speaks plain HTTP and binds to
127.0.0.1by default. Put a TLS reverse proxy in front of anything reachable from other machines. If you proxy media, forwardRangeheaders and don't buffer whole responses.
Set B10CKS_IMAGE_TAG to the new release tag, then:
docker compose pull
docker compose up -d
On boot the container compares the image's version against the one recorded on the storage volume and runs b10cks:upgrade when they differ — migrating the management database and every space database. An ordinary restart costs nothing; a real upgrade is never forgotten.
docker compose logs app | grep -i upgrad # confirm it ran
Three things: all databases (one per space on the standard profile), /app/storage, and .env.
docker compose exec db mariadb-dump -uroot -p"$DB_ROOT_PASSWORD" \
--all-databases --single-transaction | gzip > b10cks-db-$(date +%F).sql.gz
docker compose exec app tar -czf - -C /app storage | cat > b10cks-storage-$(date +%F).tar.gz
cp .env b10cks-env-$(date +%F)
Losing
APP_KEYis unrecoverable. It encrypts API tokens and integration credentials at rest; a database restore without the matching key leaves that data permanently unreadable. If you never set it in.env, the container generated one atstorage/app/setup/app.key— copy it somewhere safe now.
Named volumes survive docker compose down and image upgrades, but not docker compose down -v. Volumes are not backups. See Backup & restore for the full restore procedure.
Plus block-based content modeling, releases with atomic publishing, scheduled publication, a hierarchical asset library with on-the-fly WebP/AVIF transformations, localization, full-text search, AI-assisted workflows, redirects, backups, and space-to-space migrations.
A webhost package (pre-built archive with a browser installer, for shared hosting — no Docker, no Composer, no shell) ships with every release. Manual installs from source are supported too; see the installation guide.
AGPL-3.0. Report vulnerabilities responsibly via the security policy.
Questions: Discord · GitHub Discussions
Content type
Image
Digest
sha256:255f65e9f…
Size
211.7 MB
Last updated
about 3 hours ago
docker pull b10cks/cms