Copy .env.example to .env and fill in what you need. See Get started → Install for the handful that are actually required. The release stack has its own, shorter env.example (attached to every GitHub release and in deploy/release); every variable in it is described here, and the repository’s .env.example is the full list. An empty value in .env falls back to the default named here; NODE_ENV is deliberately absent from the file, since the release image always runs with NODE_ENV=production and any entry here, even an empty one, would override that.
Public origin the browser uses (origin only), e.g. https://app.example.com or http://localhost:5173.
RESTOW_APP_DOMAIN
none
Public app domain for the Caddy edge (automatic Let’s Encrypt TLS), e.g. app.example.com.
RESTOW_API_URL
none
Internal API base URL.
RESTOW_MODE
none
Operating mode: local | public. Set by the setup wizard; may be pinned here.
RESTOW_EDITION
community
Edition until a license key is installed: community | business | service_provider.
RESTOW_LICENSE_PUBLIC_KEY
built into the release
Optional override of the Ed25519 license verification key (raw, base64url).
RESTOW_UPDATE_CHECK_URL
empty: the Updates tab decides
Environment override for the update check: a releases endpoint over https (a GitHub .../releases or .../releases/latest URL, or a Forgejo or Gitea releases API). When set it wins over the tab under Settings, Updates: the check is on, the source is this URL and read-only there, and no stored token is sent to it. Empty means the tab decides, and the check is off until an administrator turns it on. Only the release list is read; no installation data is sent. See Updates.
LOG_LEVEL
info
Log level of worker and scheduler: debug | info | warn | error.
The application image with its version, used by api, worker, scheduler and the updater, for example ghcr.io/restow-backup/restow:0.1.0. In the source stack leave it empty: Compose then runs the restow:local image it builds. The opt-in updater writes this line.
RESTOW_WEB_IMAGE
none (required in the release stack)
The web image with the Caddy edge, for example ghcr.io/restow-backup/restow-web:0.1.0. Empty in the source stack: restow-web:local. The updater writes this line too.
RESTOW_PROJECT_DIR
/srv/restow
Absolute path, on the host, of the directory that holds docker-compose.yml and .env, for example /opt/restow. Only the optional updater needs it; it mounts the directory at the same path.
RESTOW_UPDATER_URL
http://updater:8090
Where the api looks for the optional updater. Nothing answers there unless the updater profile runs.
The updater (docker compose --profile updater up -d, opt-in) mounts the Docker socket, which is root on the host; read Updates first. The variables below are read by the updater container only (ROLE=updater). The updater service gets no .env, so the defaults apply unless you add a variable to that service’s environment in the Compose file.
Variable
Default
Purpose
RESTOW_UPDATER_PROJECT_DIR
set from RESTOW_PROJECT_DIR
Absolute host path of the Compose project, mounted at the same path.
RESTOW_UPDATER_IMAGE_REPOSITORY
ghcr.io/restow-backup/restow
Application image repository for the image mode.
RESTOW_UPDATER_WEB_IMAGE_REPOSITORY
ghcr.io/restow-backup/restow-web
Web image repository for the image mode.
RESTOW_UPDATER_HEALTH_TIMEOUT_SECONDS
600
How long to wait for the new api (migrations can take a while).
RESTOW_UPDATER_MIN_FREE_MB
1024
Free space required in the updater’s volume.
RESTOW_UPDATER_CLI_IMAGE
docker:27-cli
Image used to run docker and docker compose.
RESTOW_UPDATER_SOURCE_HOSTS
any https host
Optional comma-separated list of hosts a source archive may be downloaded from.
Peers whose X-Forwarded-For the edge keeps (and appends to) instead of replacing with the peer’s own address: space-separated CIDR ranges, or private_ranges. Needed only when another reverse proxy sits in front of Caddy.
RESTOW_EDGE_HSTS
false
true sends Strict-Transport-Security (with includeSubDomains). Set it only once RESTOW_APP_DOMAIN is a real, publicly resolvable domain for which the edge terminates its own valid TLS certificate (public mode). The value is compared literally, so it must be exactly lowercase true; anything else leaves HSTS off. Never set it for a local or IP installation: browsers would then insist on HTTPS for a host that may never serve it.
Password for the Postgres superuser Docker Compose creates. POSTGRES_USER/POSTGRES_DB default to restow.
DATABASE_MIGRATION_URL
none (required)
The database owner; runs migrations only.
DATABASE_URL
none (required)
The application role, subject to Row Level Security. The migration step creates it with the name/password given here.
DATABASE_PROVIDER_URL
none (required)
The installation role (BYPASSRLS), created the same way.
Three roles, three connection strings, three different passwords. See Get started → The three database roles. The processes refuse to start if DATABASE_URL turns out to be a superuser or able to bypass RLS.
Permits IMAP sources without TLS. Development only; never in production.
IMAP_ALLOW_PRIVATE_NETWORKS
provider-saved only
true lets every IMAP source reach loopback and private networks; by default only servers a provider admin saved can, and tenant admins are limited to public servers.
Host directory that is mounted read-only at /var/lib/restow/import in the api and the worker. Each tenant uses its own subfolder <directory>/<tenant slug>/, which you create yourself.
IMPORT_DIR
/var/lib/restow/import
The path inside the containers. Change it only together with the mount above.
IMPORT_MAX_FILE_BYTES
10 GiB
Largest file the browser upload accepts, in bytes.
IMPORT_UPLOAD_TTL_HOURS
48
Hours an unfinished or unused upload is kept before it is deleted.
IMPORT_SEGMENT_BYTES
8 MiB
Size of one upload chunk in bytes (allowed: 64 KiB to 32 MiB).
IMPORT_MAX_MESSAGE_BYTES
256 MiB
Largest single message that is read into memory.
EXPORT_TTL_HOURS
24
Hours a finished export can be downloaded before its file is deleted.
All optional. The defaults suit the release stack; only a custom image needs changes. See Endpoint backup.
Variable
Default
Purpose
RESTIC_BINARY
restic from the PATH
The restic binary that the api and the worker run for retention, checks, restore tests, browsing and downloads. The image ships it in /usr/local/bin/restic.
RESTOW_RESTIC_CACHE_DIR
the temp folder
Where restic keeps its per-endpoint caches. A folder on a volume, for example /data/restic-cache, keeps them across restarts and makes browsing faster.
All optional; the receiver is off until JOURNAL_SMTP_PORT is set. Setup, DNS, port 25 and the certificate: Exchange journaling.
Variable
Default
Purpose
JOURNAL_SMTP_PORT
none (receiver off)
Port the archive’s SMTP journal receiver listens on. The receiver starts only when this is set. Exchange Online delivers to port 25. The repository’s .env.example sets 25; the release env.example leaves it empty.
JOURNAL_SMTP_BIND
127.0.0.1
Release stack only: the host address the port is published on. Set it to 0.0.0.0 together with JOURNAL_SMTP_PORT=25 to receive Exchange Online journal reports, which must reach the receiver directly, not through Caddy.
JOURNAL_HOSTNAME
none
The host name Exchange Online delivers to, for example archive.example.com: host name only, without scheme, path, port or mail address. It forms the tenants’ journal addresses, journal+<token>@<host>; publish it in DNS. Without a valid value Restow shows no complete address.
JOURNAL_TLS_CERT_PATH
none
Path to the certificate chain (PEM, leaf first) of a publicly trusted authority, matching JOURNAL_HOSTNAME. Exchange Online requires TLS, so the receiver does not start without a certificate and never falls back to a built-in one. In the release stack: /etc/restow/journal-tls/fullchain.pem.
JOURNAL_TLS_KEY_PATH
none
Path to the private key (PEM, not encrypted with a passphrase) that belongs to the certificate. Both paths must be set. In the release stack: /etc/restow/journal-tls/privkey.pem.
JOURNAL_TLS_DIR
./journal-tls
Both stacks’ Compose file: the host directory that is mounted read-only into the api at /etc/restow/journal-tls. Put fullchain.pem and privkey.pem there. Renewed files are picked up within five minutes, without a restart.
JOURNAL_ALLOW_INSECURE
empty (off)
true starts the receiver without a certificate and without offering STARTTLS. Local development only, never in production: Exchange Online does not deliver to such a receiver and mail would cross the network in plain text. Ignored while a certificate is configured.
JOURNAL_MAX_SIZE_MB
150
Largest journal report accepted, in MB. Larger reports are refused.