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
backupservice 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, thearca-backupsvolume. To store them on a NAS, replace the volume by a mounted folder incompose.yaml(- /mnt/nas/arca:/backupsin 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:
- Turn on Enable Rules.
- Add Rule: action Always Allow (bypass auth), match type Path,
value
/ical/*, priority1. - 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/.