Small runtime surface
Cotton runs as a cohesive ASP.NET Core application instead of a pile of unrelated runtimes. Postgres stores metadata; the chunk store can live on filesystem or S3-compatible storage.
Cotton keeps the deployment shape compact: one application image, PostgreSQL, persistent chunk storage, and a setup wizard that turns first-run decisions into product UI.
Cotton runs as a cohesive ASP.NET Core application instead of a pile of unrelated runtimes. Postgres stores metadata; the chunk store can live on filesystem or S3-compatible storage.
The basic Compose shape is intentionally direct: Postgres, Cotton, a bind mount for /app/files, database connection variables, and no manual Docker network or connection-string ceremony.
New exposed instances can leave COTTON_MASTER_KEY out and unlock in the browser. Trusted home deployments can uncomment the master key line for unattended restarts when that tradeoff is acceptable.
First-run setup covers admin creation, storage choice, email mode, timezone, and telemetry preference. Basic setup lives in the product instead of hidden environment folklore.
Cotton can use Cloud Cotton Mail, custom SMTP, or disabled email. That keeps simple home deployments and public instances from needing the same mail setup.
Filesystem storage uses atomic temp-file moves and capacity reporting. S3-compatible storage can use existence-checked writes behind the same logical chunk model.
The same small start can grow into real operation: local testing, home server behind a reverse proxy, public instance with security checkup and admin 2FA, or S3-backed storage when local filesystem capacity is not the right boundary.
User quotas and storage pressure checks help public/demo instances avoid uncontrolled growth and prevent filesystem-backed storage from filling the host disk to zero.
After deployment, the admin security checkup points at concrete risks such as public account creation, missing 2FA, writable rootfs, seccomp, ptrace, and Docker socket exposure.
The deployment story is backed by a single application image, PostgreSQL metadata, filesystem or S3-compatible chunk storage, first-run setup, email-mode selection, quota policy, storage pressure checks, and admin security diagnostics.
Cotton is easy to start without pretending production operations are fake. The deployment story is compact enough for a home server, but still exposes the knobs that matter when the instance is public.
Docker and Postgres are only the application shape. Public deployments still need TLS, tested backups, key custody, updates, storage monitoring, and host/container hardening that matches the real threat model.
Cotton is not sold as a black box appliance. It is a focused Docker/Postgres file cloud with explicit choices for storage, unlock behavior, permissions, hardening, backups, and diagnostics.
The web UI, API, storage pipeline, setup wizard, and background jobs ship as one Cotton runtime.
Postgres stores users, layouts, manifests, tokens, settings, and the database state Cotton verifies.
/app/files must survive container restarts because it holds chunks and the encrypted master-key sentinel.
Run Cotton behind your normal TLS edge for public deployments instead of turning the app container into the whole perimeter.
The deployment boundary is intentionally boring: generate the database password once, keep your Postgres deployment durable, keep /data/cotton durable, put TLS at the edge, and let the setup wizard handle first-run product choices.
services:
postgres:
image: postgres:18
restart: always
environment:
POSTGRES_DB: cotton
POSTGRES_USER: cotton
POSTGRES_PASSWORD: "replace with output of: openssl rand -base64 32"
cotton:
image: bvdcode/cotton:latest
restart: always
depends_on:
- postgres
ports:
- "8080:8080"
volumes:
- /data/cotton:/app/files
environment:
COTTON_PG_HOST: postgres
COTTON_PG_PORT: "5432"
COTTON_PG_DATABASE: cotton
COTTON_PG_USERNAME: cotton
COTTON_PG_PASSWORD: "same value as POSTGRES_PASSWORD"
COTTON_RESTORE_DATABASE_IF_EMPTY: "true"
# Optional unattended restarts; otherwise unlock in browser:
# COTTON_MASTER_KEY: "replace with output of: openssl rand -base64 24"
security_opt:
- no-new-privileges:trueUse Compose with a bind-mounted files directory, local Postgres, and browser unlock after boot.
Keep /data/cotton durable, use your reverse proxy for TLS, and decide whether unattended env unlock fits your threat model.
Prefer browser unlock, enable 2FA for admins, configure email, and run the security checkup after exposure.
Use S3-compatible chunk storage when the filesystem path is not the right durability or capacity boundary.
New instances can start without COTTON_MASTER_KEY and unlock through /unlock, keeping the key out of container environment metadata.
Trusted home deployments can still use COTTON_MASTER_KEY for unattended restarts. Cotton clears it from its own process after derivation.
The official image prepares volume permissions first, then runs the Cotton process as the .NET app user.
The admin UI reports concrete hardening signals such as diagnostics, dumpability, seccomp, ptrace, rootfs, Docker socket, and 2FA coverage.
Cotton can create PostgreSQL dumps, store backup artifacts through its own chunk pipeline, and attempt restore on an empty database when configured. That is not a replacement for off-box backups; it is a practical recovery layer inside the product.
The right pitch is simple: Cotton is easy to start, but it does not pretend operations stop at the first container boot.
Public deployments still need normal operator work: TLS, backups, key storage, updates, storage monitoring, and host/container hardening that matches the actual threat model.
Docker, PostgreSQL, and persistent storage for Cotton chunks. The starter Compose example uses a bind mount to /app/files and direct database variables, with TLS handled by your reverse proxy for public deployments.
No. The simple Compose shape uses service discovery for Postgres and individual COTTON_PG_* variables. No manual Docker network or connection-string ceremony is needed for the starter path.
Yes. Cotton can use S3-compatible storage for chunk objects while keeping the same metadata and storage pipeline above it.
It depends on the deployment. For a simple trusted home server, an environment key can make unattended restarts practical. For exposed instances, browser unlock keeps the key out of container environment metadata, but you must store the key safely yourself.
Cotton can create PostgreSQL dump backups through its storage pipeline and can attempt restore on an empty database when configured. That is useful, but it does not remove the need for off-box backups.