# Raspberry Pi deployment This profile runs the single-container QSfera server on a 64-bit Raspberry Pi OS and persists configuration and user data outside the container. It expects a separate reverse proxy for a browser-trusted TLS certificate; by default port 9200 is therefore published only on `127.0.0.1`. ## Requirements - `uname -m` must report `aarch64` or `arm64`. - Docker Engine with the Compose plugin must be installed. - The selected QSfera image tag or digest must contain `linux/arm64`. - The configuration and data directories must be on persistent storage and writable by UID/GID `1000:1000`, which is the non-root user in the image. For an external disk mounted at `/mnt/qsfera`, create the directories with: ```sh sudo install -d -o 1000 -g 1000 -m 0750 /mnt/qsfera/config /mnt/qsfera/data findmnt /mnt/qsfera ``` `findmnt` must show the expected external filesystem before the service starts. This prevents an unavailable disk from silently placing data on the Pi's root filesystem. ## Configuration ```sh cd Server/deployments/raspberry-pi cp .env.example .env chmod 600 .env ``` Fill every empty value in `.env`. The Compose file deliberately has no default for the image, public URL, admin password, persistent paths or memory limit. `docker compose config` fails when any of these values is empty. Choose `QSFERA_MEMORY_LIMIT` from measurements on the target Pi: ```text QSFERA_MEMORY_LIMIT = total RAM - OS reserve - other services reserve ``` Use `free -h` for total/current host memory and `docker stats` for the other containers. Leave enough headroom for the kernel, filesystem cache and reverse proxy. QSfera's Go runtime then derives its own default `GOMEMLIMIT` from the container limit with a 0.9 ratio. Keep `QSFERA_BIND_IP=127.0.0.1` when the reverse proxy runs on the same Pi. Set it to a reachable interface only when access to port 9200 is protected by an equivalent network and TLS design. ## Start and verify ```sh sh ./smoke-test.sh docker compose ps ``` The smoke test validates the Compose file, starts the service and waits for the container health check. Its default 180-second startup budget can be changed with `SMOKE_TIMEOUT_SECONDS`. ## Backup The backup script stops QSfera, archives both persistent directories, writes a SHA-256 checksum and starts the service again: ```sh sh ./backup.sh /mnt/backups/qsfera ``` Copy the resulting `.tar.gz` and `.sha256` files to storage that is independent of the Pi and its data disk. ## Restore Restore replaces the current configuration and data. Check the selected archive and its checksum first, then run: ```sh RESTORE_CONFIRM=restore sh ./restore.sh /mnt/backups/qsfera/qsfera-TIMESTAMP.tar.gz sh ./smoke-test.sh ``` The restore script verifies the checksum when the matching `.sha256` file is present and stops the service during replacement. It starts QSfera only after a successful extraction; after an error the service remains stopped so a partial data set is never served automatically. ## References - [Raspberry Pi external storage documentation](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#external-storage) - [Docker Compose service configuration](https://docs.docker.com/reference/compose-file/services/) - [Go garbage collector guide](https://go.dev/doc/gc-guide)