Docker Deployment
September 4, 2026 · View on GitHub
The official Docker image is published to Docker Hub:
mebtte/cicada:v3
v3 tracks the latest major-version-3 release. Pull the image again when you
want to upgrade within the v3 line.
Docker Compose
Create compose.yaml:
services:
cicada:
image: mebtte/cicada:v3
container_name: cicada
command: ["start", "--scratch", "/scratch"]
restart: unless-stopped
ports:
- "8000:8000"
environment:
CICADA_DATA: /data
CICADA_PORT: 8000
volumes:
- ./data:/data
- /device-local/cicada-scratch:/scratch
Replace /device-local/cicada-scratch with a writable host directory outside
your synchronized data. Use a separate scratch mount for each data directory.
Start the service:
docker compose up -d
Open http://localhost:8000 after the container starts.
First Login
On the first startup, Cicada creates a default admin user and prints the password to the container log.
docker logs cicada
The default username is cicada. Save the generated password before clearing
the logs.
Data Directory
The compose example mounts ./data on the host to /data in the container.
This directory contains the SQLite database, uploaded assets, data-version files,
and other persistent data. Back it up before upgrading or moving the service to
another host.
The example separately mounts a device-local directory at /scratch and passes
--scratch /scratch. Scratch contains bin, thumbnails, music_transcoded,
partial_uploads, and logs/access, logs/scheduler, and logs/ffmpeg, without a nested
cache directory. Its v file tracks local upgrade progress. Missing directories are created at startup; invalid or
unwritable paths prevent startup. Container mount permissions must allow Cicada
to write to both data and scratch.
scratch/bin is reserved for embedded executables. At startup, Cicada reuses
identical tools, replaces changed or missing tools via files staged in the same
directory, then removes obsolete entries. Do not put your own files there or
share scratch between running instances. The scratch mount must allow execution
of these tools (it cannot be mounted with noexec).
Without --scratch, the default is <data>/scratch, which still participates
in data-directory synchronization. Relative paths are resolved from the process
working directory inside the container. There is no scratch environment variable;
use the command argument. Startup output shows the resolved scratch path.
Stop the service before clearing scratch or changing its location. Missing scratch is recreated on startup, but its historical logs and unfinished uploads are lost. Music caches are rebuilt according to the selected transcoding mode. Moving scratch does not guarantee a smaller total disk footprint: cache regeneration consumes space, and reusable source-quality files are copied into independent caches rather than hard-linked.
Music Transcoding Mode
The default eager mode generates music caches in the background and retains
valid caches indefinitely. For limited storage, choose lazy in the Compose
command and recreate the container:
command: ["start", "--scratch", "/scratch", "--music-transcode=lazy"]
With plain Docker, append --music-transcode=lazy after start. The option is
server-wide and accepts only eager or lazy; invalid values stop startup.
There is no corresponding environment variable. Restart with
--music-transcode=eager or omit the option to restore the default.
Lazy mode generates missing caches when requested and has no background pretranscoding job. The first request waits for the whole file to finish transcoding. Every server request using a cache refreshes that audio file's modification time; the two quality levels are tracked independently. Requests served entirely by a browser or proxy cache do not refresh server timestamps, and background checks do not renew existing caches.
Daily cleanup at 04:10 in the container's local timezone removes lazy caches unused for more than 60 × 24 hours, alongside invalid caches. Active generation and responses are protected. Existing caches remain when switching modes, but switching to lazy makes them subject to expiry. Expiry reduces idle cache storage; it does not guarantee a maximum disk footprint. Eager mode only cleans invalid caches.
The music cache change advances the data version by one. Its local scratch migration discards old music caches and metadata, preserving uploaded files and business database contents. New caches use independent files, never hard links. They are rebuilt by background jobs or requests in eager mode, and only by requests in lazy mode. Allow for cache regeneration after upgrading.
Upgrade
Pull the latest v3 image and recreate the container:
docker compose pull
docker compose up -d
Cicada runs required data migrations automatically during startup. The scratch
layout advances the data version and deletes the old <data>/cache,
<data>/partial_uploads, and <data>/logs once, without migrating their contents.
Original assets and database contents remain. Finish uploads and save required
logs before upgrading; caches will be regenerated. Do not point scratch at or
inside those old directories, including through symbolic links.
Older binaries may refuse the upgraded data version. Keep a pre-upgrade backup if you need to restore the previous release; switching the image back alone is not a supported rollback.
On every startup, Cicada upgrades data first and then local scratch, even if
another device has already upgraded the synchronized data. scratch/v tracks
this device's progress toward the data version. Existing scratch without that
file is adopted at baseline 123 without clearing its contents, then upgraded
as needed. Data-only changes advance the marker without deleting caches;
future scratch changes preserve compatible files and only convert or remove
formats that cannot be reused.
An invalid scratch version or one newer than data prevents startup and preserves
the files. If data upgrades successfully but scratch fails, the service stays
stopped; retry startup to recover and upgrade scratch. The successful data
upgrade is not rolled back. Keep scratch/v with its directory rather than
editing or removing it separately.
Useful Commands
Stop the service:
docker compose down
Follow logs:
docker logs -f cicada
Run with plain Docker instead of Compose:
docker run -d \
--name cicada \
--restart unless-stopped \
-p 8000:8000 \
-e CICADA_DATA=/data \
-e CICADA_PORT=8000 \
-v "$(pwd)/data:/data" \
-v /device-local/cicada-scratch:/scratch \
mebtte/cicada:v3 start --scratch /scratch