# Secret Store and encrypted full backup/restore RustProxy keeps application credentials in a central encrypted Secret Store. Provider and ACME secrets are not stored as plaintext configuration values in SQLite. ## Secret Store Secret records live in the `secret_store` SQLite table and contain an identifier, provider/type, encryption version, nonce, ciphertext, metadata and timestamps. Values are encrypted with AES-256-GCM using a random local data key stored at: ```text /secrets/master.key ``` The key file is created with mode `0600`; its directory is private. The application loads it during normal startup, so normal operation does not require an interactive password. Existing ACME DNS credential files are migrated on startup for Cloudflare, OVH and RFC2136. After successful import, the legacy plaintext credential file is removed. Certbot-compatible credential files are recreated only as short-lived private files around the external operation and removed afterwards. Do not copy only `config.sqlite3` as a Secret Store backup: the local key material is also required. Use the encrypted full-backup command below. ## Create a full backup `backup create` may run while RustProxy is serving traffic. If the service is stopped, the CLI takes the data-directory lock; if the service is running, it creates a consistent SQLite snapshot and stages durable filesystem state without taking ownership of that lock. The output file must be outside the RustProxy data directory and must not already exist. ```bash rust-proxy --data-dir /var/lib/rustproxy backup create \ --output /private/rustproxy-backup.rpb ``` When run from a TTY, RustProxy asks for the backup password without putting it in process arguments or shell history. Press Enter at the password prompt to generate a strong random password. A generated password is printed exactly once and is required for restore. For non-interactive `backup create`, RustProxy generates the password automatically and prints it once to standard output. Protect that output as a secret. The encrypted backup contains the durable application state needed for recovery, including: - a consistent SQLite snapshot, - configuration and Secret Store records, - backup-wrapped Secret Store key material, - certificates and private keys, - ACME state and durable provider data, - other durable RustProxy data accepted by the backup manifest, - validated internal relative symlinks, including Certbot `live/` links into the same profile's `archive/` tree. It excludes rebuildable/runtime data such as cache, logs, temporary files, sockets, PID/lock files and SQLite WAL/SHM sidecars. Symlinks are accepted only when their target is relative and resolves inside the staged RustProxy data tree; absolute, escaping or dangling links fail backup/restore. Restore recreates accepted links as links rather than dereferencing them. The outer container derives a backup key with Argon2id and encrypts authenticated chunks with AES-256-GCM. The backup password is independent from the local Secret Store key. ## Restore Restore is CLI-only, requires RustProxy to be stopped, and requires an interactive TTY for the password: ```bash rust-proxy --data-dir /var/lib/rustproxy backup restore \ /private/rustproxy-backup.rpb ``` Before replacing the destination, RustProxy verifies the encrypted container, password/authentication tags, manifest, checksums, backup format, RustProxy/schema compatibility, restored SQLite database and decryptability of all Secret Store records. Files are first restored into a private staging directory. Only after validation succeeds is the staged data directory atomically activated; activation failure attempts to roll back to the previous directory. Sensitive restored files use restrictive permissions. A lost backup password cannot be recovered by RustProxy.