Docker installation
Choose and load an image
Obtain a TinyCMS image archive for your host platform and the matching ZIP release for database migration tooling. Choose the standard Alpine image when audio and video are disabled, or the FFmpeg variant when those features are needed. The FFmpeg variant includes both ffmpeg and ffprobe; enable audio/video through the configuration described below.
For version 0.1.0, load the supplied archive:
sh
docker load --input /path/to/tinycms-0.1.0.tarFor FFmpeg, load /path/to/tinycms-0.1.0-ffmpeg.tar instead. The examples below use the default image names tinycms:0.1.0 and tinycms:0.1.0-ffmpeg; use the image name supplied with your release if it differs. The image platform must match your Docker host.
Both images serve the prebuilt frontend through the backend on port 3000 and run as UID/GID 1000.
Prepare persistent data and the database
Extract the matching ZIP release and install its dependencies on the deployment host for database migration tooling. The runtime images contain production dependencies; they do not include Drizzle Kit or pnpm.
From the extracted release root, create the bind-mount directories:
sh
mkdir -p docker/data docker/backupsApply the release's reviewed migration history before starting the container:
sh
DB_FILE_NAME="file:$PWD/docker/data/database.db" pnpm --filter backend run db.migrateUse the reviewed migrations supplied with the matching release. If migration history is missing, obtain a complete release from your provider before continuing. On upgrades, stop the existing container and take a validated backup before migrating. Keep the data, migration history, and image version matched.
Give the container user access after migration:
sh
sudo chown -R 1000:1000 docker/data docker/backupsConfigure and run
Create a private docker/.env using the backend environment template and configuration guide. Set these values for the container, together with working production email settings:
dotenv
NODE_ENV=production
PORT=3000
DB_FILE_NAME=file:/data/database.db
BETTER_AUTH_URL=https://cms.example.com
FRONTEND_ORIGIN=https://cms.example.com
BETTER_AUTH_SECRET=REPLACE_WITH_RANDOM_SECRET
SETUP_TOKEN=REPLACE_WITH_DIFFERENT_RANDOM_SECRETLeave APP_CONFIG_FILE unset to use the image's configuration. Unlike the host template, its persistent paths point into /data, backups into /backups, and frontend files into /app/frontend.
sh
docker run -d --name tinycms \
--restart unless-stopped \
--env-file docker/.env \
-p 127.0.0.1:3000:3000 \
--mount "type=bind,source=$PWD/docker/data,target=/data" \
--mount "type=bind,source=$PWD/docker/backups,target=/backups" \
tinycms:0.1.0Choose tinycms:0.1.0-ffmpeg for the FFmpeg image. Follow the production guide for HTTPS and proxy configuration, check /health, and complete initial setup. Remove SETUP_TOKEN and recreate the container afterward. Persist and back up the mounted data independently of image archives.
For custom configuration, copy /app/backend/config.json from a created container, edit the complete JSON, and bind-mount it read-only. Keep server.listenAddress set to 0.0.0.0, paths.frontendDist at /app/frontend, and data paths inside the mounted directories. Set APP_CONFIG_FILE to the mounted file's container path. To enable audio/video, use the FFmpeg image and set media.audioEnabled / media.videoEnabled in this JSON.
sh
docker cp tinycms:/app/backend/config.json docker/config.jsonWhen recreating the container with this configuration, add --mount "type=bind,source=$PWD/docker/config.json,target=/etc/tinycms/config.json,readonly" and -e APP_CONFIG_FILE=/etc/tinycms/config.json to the run command.