chore: updated README for backup 88e84f4d
Steve · 2026-04-04 23:11 1 file(s) · +150 −0
apps/backup/README.md (added) +150 −0
1 +
# Backup
2 +
3 +
Automated SQLite backups for Jotts, Sipp, and Cellar to Cloudflare R2. Runs every 6 hours via cron inside a Docker container and prunes backups older than 30 days.
4 +
5 +
## Setup
6 +
7 +
1. **Create an R2 bucket:**
8 +
   - Log in to the [Cloudflare dashboard](https://dash.cloudflare.com).
9 +
   - Select your account, then navigate to **R2 Object Storage** in the sidebar.
10 +
   - Click **Create bucket** and name it `andromeda-backups` (or a name of your choice).
11 +
12 +
2. **Find your account ID and endpoint:**
13 +
   - Your account ID is in the Cloudflare dashboard URL: `https://dash.cloudflare.com/<account-id>`.
14 +
   - You can also find it on the **R2 Overview** page under **Account ID**.
15 +
   - Your R2 endpoint is `https://<account-id>.r2.cloudflarestorage.com`.
16 +
17 +
3. **Generate R2 API credentials:**
18 +
   - On the **R2 Overview** page, click **Manage R2 API Tokens**.
19 +
   - Click **Create API Token**.
20 +
   - Give it a name (e.g. `andromeda-backup`).
21 +
   - Set **Permissions** to **Object Read & Write**.
22 +
   - Under **Specify bucket(s)**, select the bucket you created (or apply to all buckets).
23 +
   - Click **Create API Token**.
24 +
   - Copy the **Access Key ID** and **Secret Access Key** — these are only shown once.
25 +
26 +
4. **Configure the environment:**
27 +
28 +
```sh
29 +
cp .env.example .env
30 +
```
31 +
32 +
Fill in the values from the previous steps:
33 +
34 +
```
35 +
R2_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com
36 +
AWS_ACCESS_KEY_ID=<your-r2-access-key>
37 +
AWS_SECRET_ACCESS_KEY=<your-r2-secret-key>
38 +
R2_BUCKET=andromeda-backups
39 +
```
40 +
41 +
4. If your Docker volume names differ from the defaults, set them in `.env`:
42 +
43 +
```
44 +
JOTTS_VOLUME=jotts_jotts-data
45 +
SIPP_VOLUME=sipp_sipp-data
46 +
CELLAR_VOLUME=cellar_cellar-data
47 +
```
48 +
49 +
Run `docker volume ls` to check the actual names on your host.
50 +
51 +
5. Start the backup container:
52 +
53 +
**Option A: Build from source**
54 +
55 +
```sh
56 +
docker compose up -d --build
57 +
```
58 +
59 +
**Option B: Use the pre-built image from GHCR**
60 +
61 +
Override the `build` directive with `image` in your compose file or use a separate override:
62 +
63 +
```sh
64 +
docker compose -f docker-compose.yml -f docker-compose.ghcr.yml up -d
65 +
```
66 +
67 +
Create a `docker-compose.ghcr.yml` override file:
68 +
69 +
```yaml
70 +
services:
71 +
  backup:
72 +
    image: ghcr.io/stevedylandev/andromeda-backup:latest
73 +
    build: !reset null
74 +
```
75 +
76 +
Or simply run the image directly:
77 +
78 +
```sh
79 +
docker run -d --restart unless-stopped \
80 +
  --env-file .env \
81 +
  -v jotts_jotts-data:/data/jotts:ro \
82 +
  -v sipp_sipp-data:/data/sipp:ro \
83 +
  -v cellar_cellar-data:/data/cellar:ro \
84 +
  ghcr.io/stevedylandev/andromeda-backup:latest
85 +
```
86 +
87 +
## Running a Manual Backup
88 +
89 +
```sh
90 +
docker compose exec backup /usr/local/bin/backup.sh
91 +
```
92 +
93 +
## Checking Logs
94 +
95 +
```sh
96 +
docker compose exec backup cat /var/log/backup.log
97 +
```
98 +
99 +
## Restoring from a Backup
100 +
101 +
1. List available backups for a service (e.g. `jotts`):
102 +
103 +
```sh
104 +
aws s3 ls s3://andromeda-backups/jotts/ --endpoint-url https://<account-id>.r2.cloudflarestorage.com
105 +
```
106 +
107 +
2. Download the backup you want to restore:
108 +
109 +
```sh
110 +
aws s3 cp s3://andromeda-backups/jotts/2026-04-04T060000Z.sqlite.gz ./restore.sqlite.gz \
111 +
  --endpoint-url https://<account-id>.r2.cloudflarestorage.com
112 +
```
113 +
114 +
3. Decompress it:
115 +
116 +
```sh
117 +
gunzip restore.sqlite.gz
118 +
```
119 +
120 +
4. Stop the target service so nothing is writing to the database:
121 +
122 +
```sh
123 +
docker compose -f /path/to/jotts/docker-compose.yml down
124 +
```
125 +
126 +
5. Copy the restored database into the volume:
127 +
128 +
```sh
129 +
docker run --rm -v jotts_jotts-data:/data -v $(pwd):/backup debian:bookworm-slim \
130 +
  cp /backup/restore.sqlite /data/jotts.sqlite
131 +
```
132 +
133 +
6. Restart the service:
134 +
135 +
```sh
136 +
docker compose -f /path/to/jotts/docker-compose.yml up -d
137 +
```
138 +
139 +
## Configuration
140 +
141 +
| Variable | Default | Description |
142 +
|---|---|---|
143 +
| `R2_ENDPOINT` | — | Cloudflare R2 S3-compatible endpoint |
144 +
| `AWS_ACCESS_KEY_ID` | — | R2 access key |
145 +
| `AWS_SECRET_ACCESS_KEY` | — | R2 secret key |
146 +
| `R2_BUCKET` | `andromeda-backups` | R2 bucket name |
147 +
| `RETENTION_DAYS` | `30` | Days to keep backups before pruning |
148 +
| `JOTTS_VOLUME` | `jotts_jotts-data` | Docker volume name for Jotts data |
149 +
| `SIPP_VOLUME` | `sipp_sipp-data` | Docker volume name for Sipp data |
150 +
| `CELLAR_VOLUME` | `cellar_cellar-data` | Docker volume name for Cellar data |