Skip to content

Operations

Day-to-day running of an installed Arca. To install or update it, see Installation.

Configuration

Variable Default Effect
ARCA_SECRET_KEY — Required unless ARCA_DEBUG is on. Generate it with python3 -c "import secrets; print(secrets.token_urlsafe(50))".
ARCA_ALLOWED_HOSTS — Comma-separated names or IPs used to reach Arca (arca.lan,192.168.1.20).
ARCA_TIME_ZONE UTC IANA time zone (Europe/Paris): decides what today is.
ARCA_MAX_UPLOAD_MB 25 Largest document accepted, in MB. Arca stops receiving a document past this size, even when the reverse proxy sets no limit (Traefik and Pangolin set none by default). A proxy with its own limit needs one at least as large (nginx: client_max_body_size).
ARCA_DATA_DIR ./data Database and documents. Docker always uses /data.
ARCA_BACKUP_DIR ./backups Encrypted backup archives. Docker always uses /backups.
ARCA_HTTPS off Behind an HTTPS reverse proxy: secure cookies, redirect to HTTPS, HSTS.
ARCA_CSRF_TRUSTED_ORIGINS — Behind a proxy: the public origin (https://arca.example.org).
ARCA_TRUSTED_PROXIES — Behind a proxy: the address (or network, 10.0.0.0/8) the proxy connects from, comma-separated. Arca then reads the client's address from X-Forwarded-For to limit login attempts; see Login security.
ARCA_VERSION latest Docker only: the image version to run (0.1.0).
ARCA_DEBUG off Development only.

Automatic backups

Open Backups and choose Enable automatic backups. Arca shows a recovery key once — XXXX-XXXX-XXXX-XXXX-XXXX-XXXX — and offers an emergency kit to download. Keep it away from the server (password manager, printed copy): it is the only way to open the archives, and Arca cannot show it again.

  • Arca then makes an encrypted archive every day (the backup service checks every hour) and keeps the newest archive of each of the last 7 days, 4 weeks and 12 months, plus the 2 most recent (so a manual backup made just before a change survives the next one).
  • Archives go to ARCA_BACKUP_DIR: with Docker, the arca-backups volume. To store them on a NAS, replace the volume by a mounted folder in compose.yaml (- /mnt/nas/arca:/backups in both services).
  • Copy them off the server (Proxmox backup, rsync, NAS): Arca makes no network call.
  • Export downloads a fresh archive of the same kind, readable with the same key.
  • The server keeps only the public half of the key: it can make archives, not read them. A lost recovery key cannot be recovered.

Backups include the documents. A document you delete stays in the backups made before, until their rotation removes them.

Off-site copies

Backups on the same machine as the data do not survive a disk failure, a fire or a theft. Keep the 3-2-1 rule in mind: 3 copies of your data, on 2 different media, 1 of them elsewhere. Archives are encrypted with your recovery key, so any storage will do, a consumer cloud service included. Keep the recovery key somewhere else than the archives (a password manager, a printed emergency kit).

Arca makes no network call: the copy is made by you or by a tool of your choice. Three levels, from the simplest:

1. Download an archive (everyone). On the Backups page, download the latest archive (or an export) to another device: a USB key, a laptop. Arca shows when you last did it, and the integrity check reminds you after 30 days without a downloaded copy.

2. A synced folder. Store the archives in a folder that a sync client already copies elsewhere (Syncthing, Nextcloud, Dropbox, OneDrive, Google Drive…). With Docker, replace the arca-backups volume with that folder in compose.yaml, for both the arca and backup services:

    volumes:
      - arca-data:/data
      - /home/me/Sync/arca-backups:/backups

The folder must be writable by uid 1000 (the arca user of the image).

3. An automatic copy. On the Docker host, a scheduled job copies the archives to another machine or to remote storage. To a NAS or another machine over SSH, with rsync (crontab of the host, every night at 3:30):

30 3 * * * rsync -a --delete /var/lib/docker/volumes/arca_arca-backups/_data/ nas:/backups/arca/

To almost any storage (S3, Backblaze B2, SFTP, WebDAV, Google Drive, OneDrive…), with rclone after rclone config:

30 3 * * * rclone sync /var/lib/docker/volumes/arca_arca-backups/_data remote:arca-backups

The volume path depends on the compose project name (docker volume inspect arca_arca-backups shows it). With levels 2 and 3, tick An automatic copy off the server is in place on the Backups page: Arca cannot see these copies, and stops reminding you.

Restore

From the browser: Backups › Restore…, choose an archive from the list or upload one, type the recovery key. Arca checks everything first (key, archive integrity, database, version) and changes nothing if a check fails. After you confirm, it restarts and replaces the data before serving pages again; the previous data is kept in a before-restore-<date> folder of the data volume. Log in with the account as it was on the archive's date.

On a new server: install Arca, start it once (docker compose up -d), create an account, then use Backups › Restore an archive from another installation… with the uploaded file.

If Arca no longer starts, restore from the command line with the web service stopped:

docker compose stop arca
docker compose run --rm arca python manage.py restore /backups/arca-YYYYMMDD-HHMMSS.arca-backup
docker compose start arca

From source, Arca does not restart by itself: after confirming a restore in the browser, stop Arca, run uv run manage.py restore --apply-staged, then start it again. Or restore from the command line, Arca stopped: uv run manage.py restore <archive>.

Manual volume copy

As a fallback, or before a risky operation on the server, copy the whole volume while Arca is stopped (the database is then consistent):

docker compose stop arca
docker run --rm -v arca_arca-data:/data:ro -v "$PWD":/backup alpine \
  tar czf "/backup/arca-$(date +%F).tar.gz" -C /data .
docker compose start arca

The volume is named <project directory>_arca-data (docker volume ls). Keep a copy off the server, ideally encrypted: a backup on the same machine does not survive its failure.

To restore:

docker compose stop arca
docker run --rm -v arca_arca-data:/data -v "$PWD":/backup alpine \
  sh -c 'test -f /backup/arca-YYYY-MM-DD.tar.gz && rm -rf /data/* && tar xzf /backup/arca-YYYY-MM-DD.tar.gz -C /data'
docker compose start arca

test -f stops before emptying the volume if the archive name is wrong. On a new server, run docker compose up -d once so the container and its volume exist, then restore as above.

From source: stop the service, then copy the ARCA_DATA_DIR directory; restore by copying it back while the service is stopped.

Integrity

Arca checks itself: the database file (corruption, broken references), the consistency of derived data (action dates, anchor days, currency codes) and the installation (migrations, Django checks, data directory, free space, package versions).

Documents are checked too: a missing file (error), a file changed since it was added (error, full check only) and a file that belongs to no document (warning; it is never deleted, look at it before removing it by hand).

  • A quick check runs at every container start; its result appears in the Integrity page and on the dashboard.
  • The Integrity page can run a quick check on demand.
  • The full check and repairs run from a terminal:
docker compose exec arca python manage.py doctor --mode full
docker compose exec arca python manage.py doctor --mode full --fix

From source: uv run manage.py doctor --mode full (add --fix to repair).

--fix only recomputes derived fields (action date, anchor day); it never deletes anything. The exit code is 0 when everything is fine, 1 with warnings, 2 with errors — usable by a monitoring tool.

Calendar feed

Arca can publish your upcoming deadlines as a private calendar feed: one all-day event on the action date of each deadline, with alarms at 9:00 before it (90, 30 and 7 days by default, set on the Calendar page). Done and ignored deadlines leave the feed. The feed never contains reference numbers, amounts, organizations or notes.

Turn it on from the Calendar page, then subscribe with its address. The feed's texts are in the interface language of the moment you turned it on; to change it, turn the feed off and on again in the other language (this gives a new address: subscribe again).

  • iPhone, iPad: Settings › Apps › Calendar › Calendar Accounts › Add Account › Other › Add Subscribed Calendar (before iOS 18: Settings › Calendar › Accounts › …), paste the address. Then open the subscription and turn off Remove Alerts, or the alarms are dropped. The Subscribe button on the Calendar page does the same from the phone's browser; if Arca is served over plain HTTP (local network), iOS first tries a secure connection and then asks whether to continue without it: accept.
  • Mac: Calendar › File › New Calendar Subscription, or the Subscribe button; untick Remove Alerts.
  • Android: install ICSx⁵ (free on F-Droid), add the address; any calendar app then shows the events and alarms. In Google Calendar, the ICSx⁵ calendars stay hidden until you tick their account: in the Google Calendar app (not Android's settings), Settings › Manage accounts, then tick the ICSx⁵ account ("Calendar subscriptions"; the exact name depends on the phone's language).
  • Computer: Thunderbird, Evolution and GNOME Calendar subscribe to an address (New calendar › On the network).
  • Google Calendar (From URL) is not recommended: Google's servers fetch the feed, so it must be reachable from the Internet; they ignore alarms and refresh slowly.

Calendar apps refresh on their own schedule (from 15 minutes to a day): an edit in Arca shows up at the next refresh.

Feeds per person. The feed above is the full one, for you who manage the household. To give a member of the household only their deadlines, turn on their feed in Feeds per person on the Calendar page. Whole-household deadlines (records without a person) are left out unless you tick Include whole-household deadlines for that person. Reminder delays are common to every feed. Each address is worth a password for its feed; renew or turn off each one separately.

Reaching the feed. Arca only serves the address; your phone must be able to reach it:

  • on the local network only: nothing to do, the phone updates at home;
  • through a VPN (Tailscale, WireGuard…): the phone is "at home" everywhere;
  • through a reverse proxy (Caddy, Traefik, nginx, Cloudflare Tunnel, Pangolin…): the token protects the feed. If the proxy puts a login (single sign-on) in front of Arca, let the path /ical/ through without it: a calendar app cannot log in.

With Pangolin and platform SSO, open the Arca resource, Rules tab:

  1. Turn on Enable Rules.
  2. Add Rule: action Always Allow (bypass auth), match type Path, value /ical/*, priority 1.
  3. Click Save Rules.

If the resource uses a shared policy ("This resource inherits from…"), its rules come from that policy, and rules set on the resource are not applied: give the resource its own policy, or add the rule to the shared one (it then applies to every resource using it). To check, open https://<your domain>/ical/test.ics without being logged in: Arca's "Not Found" page means the rule works; Pangolin's "Unauthorized" means it does not.

Security. The address works like a password: anyone who has it can read the feed. If it leaks, create a new address on the Calendar page and subscribe your devices again. The token is part of the address, so it appears in access logs (Arca's and your proxy's).

Login security

Two-factor authentication (page Security) asks, after the password, for a code from an authenticator app on your phone (Aegis, 2FAS, Google Authenticator, KeePassXC…). Turn it on when Arca is reachable from the Internet without an authenticating proxy. It is not needed on a local network, behind a proxy that already asks for a second factor (Pangolin, Authelia, Authentik…), or in the desktop application.

  • Turn on two-factor authentication shows a QR code: scan it, then type the code the app shows. Nothing is active until that code is accepted.
  • Arca then shows 10 recovery codes, once. Each one replaces a phone code once. Keep them away from the phone: printed, or in your password manager. Regenerate recovery codes replaces them all.
  • Turn off asks for a code.
  • Lost phone and codes: on the server, run docker compose exec arca python manage.py disable_2fa (from the sources: uv run manage.py disable_2fa), then log in with the password alone.
  • Restoring an older backup brings two-factor back to its state in the archive: the phone keeps working, the recovery codes are those of that time.

Login attempts are limited per address: after 5 failures, the address is blocked for 1 minute, then twice as long after each new failure, up to 15 minutes; the count starts over after 15 minutes without a failure (counted from the end of the last block). A failed code counts like a failed password. Behind a reverse proxy, every request comes from the proxy's address: set ARCA_TRUSTED_PROXIES to it, so that Arca reads the client's address from X-Forwarded-For, which the proxy appends (Pangolin, Traefik, Caddy, and nginx with proxy_add_x_forwarded_for do). Without it, failures count for the proxy's address, shared by everyone: an attacker's failures would block you too, and the integrity check warns about it when ARCA_HTTPS is on. The header is only believed from those addresses, so a client reaching Arca's port directly cannot choose its address. To find the proxy's address, look at where requests come from, for example with Docker: the gateway of Arca's network (docker network inspect arca_default) when the proxy reaches Arca through the published port on the same host. Each failure is logged, for example:

2026-09-30 12:00:00,000 WARNING arca.auth Login failure from 203.0.113.7 at the password step

IPv6 addresses are counted per /64, which the line adds: … from 2001:db8:1:2::1 at the code step (counted for 2001:db8:1:2::/64).

To ban persistent addresses at the firewall, a fail2ban filter can match Login failure from <HOST> at the in the container log (docker compose logs arca).

Troubleshooting

Symptom Cause and fix
Bad Request (400) The name or IP in the address bar is not in ARCA_ALLOWED_HOSTS.
CSRF verification failed. Request aborted. behind a proxy Set ARCA_CSRF_TRUSTED_ORIGINS to the public origin, with https://.
Integrity warns about the secret key (W009) The key is too weak or was truncated: Compose expands $ in .env. Generate one with secrets.token_urlsafe(50).
Integrity reports unapplied migrations Restart the container (it migrates at start), or run manage.py migrate.
Help says the documentation is missing Source install: run uv run --group docs mkdocs build, then uv run manage.py collectstatic --noinput.

Archive format

An .arca-backup file is the line ARCA-BACKUP 1, one line of JSON header (creation date, Arca version, kind, scrypt parameters and salt, key fingerprint, ephemeral X25519 public key, chunk size), then 64 KiB chunks. The recovery key (24 characters, case-insensitive, dashes ignored) is stretched with scrypt into an X25519 private key; the archive key is HKDF-SHA256 of the X25519 shared secret, salted with both public keys, with info arca-backup v1 followed by the SHA-256 of the header line. Chunks are sealed with ChaCha20-Poly1305 under the nonce 11-byte big-endian counter + 1 byte (1 for the last chunk). The payload is a gzip tar: manifest.json (counts, migrations, SHA-256 of every file), db.sqlite3 and media/.