kamal-backup 0.1.0.pre.2 → 0.1.0.pre.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f90e6e9f02fd3ddb958b6f2c41de4219b36fa3e8ff4b84ea779c7decf74379b5
4
- data.tar.gz: ab72fc616b324bcceee78c3d0060900e747334bf2ef8f3e962c0d81e0d7674ca
3
+ metadata.gz: dffee9d885ca23342a84ac3fc494d09f9f44b323a10ae981df4665f31206b20a
4
+ data.tar.gz: 0c6352b4f00008b54b22442f0b192eb54adf7f52c0350ab8cb5c69dd1cff9c4f
5
5
  SHA512:
6
- metadata.gz: a94b5efc6f8c9727a176899572a758247f1db0150af45f71b6a0f830c95a9294f885d26e67d7b649308f604087e9e318f427033b8428ed663671b0b1cdbda87f
7
- data.tar.gz: 97cfef328b321fefca4d95c36caf25d3a168e49b97e5de02879d3907a88d61842aa233d6dacb4367e1ac5c6866d2636586e67db91e04f2acfa02057dae318c4b
6
+ metadata.gz: 77f916eec58efe57ad7c1b65b8f93cab39d647b9051dc6d77cbebfa66f830cbc65bfdf9bdfc8aa0016109969a88b68bef8f2ea79a71a97ce4670b6c1028fa8ba
7
+ data.tar.gz: 631793de8449a07bf774f91a5bf7aea669b4773da960a27319cf8ecca00c6194a37214f36cc70c49857247406e665292318ad145f9c9e87d15f53751b92bf00a
data/README.md CHANGED
@@ -1,40 +1,67 @@
1
1
  # kamal-backup
2
2
 
3
- `kamal-backup` is a small Docker image for Kamal accessories. It creates encrypted, restic-backed backups for self-hosted apps by backing up database dumps and mounted application files together.
3
+ `kamal-backup` gives Rails apps a clean backup and restore workflow for Kamal.
4
4
 
5
- The Docker image is the normal production interface. The Ruby gem packages the same `kamal-backup` executable so the image can install it cleanly, and so operators can optionally run the CLI from a laptop for restore drills when they have restic, database clients, and the right environment configured.
5
+ It backs up:
6
6
 
7
- It is aimed at common Kamal backup needs:
7
+ - PostgreSQL, MySQL/MariaDB, or SQLite
8
+ - file-backed Active Storage and other mounted app files
8
9
 
9
- - Kamal Postgres backup
10
- - Kamal MySQL and MariaDB backup
11
- - Kamal Active Storage backup
12
- - Kamal restic backup
13
- - Restore drills and evidence for security reviews such as CASA
10
+ It restores in two clear modes:
14
11
 
15
- ## What It Backs Up
12
+ - `restore local`: pull a production backup onto your machine
13
+ - `restore production`: restore back into live production
16
14
 
17
- `kamal-backup` handles two data surfaces:
15
+ And it drills in two clear modes:
18
16
 
19
- 1. A logical database dump from PostgreSQL, MySQL/MariaDB, or SQLite.
20
- 2. Mounted application files such as Rails Active Storage.
17
+ - `drill local`: prove the backup works on your machine
18
+ - `drill production`: restore into scratch targets on production infrastructure, run checks, and record evidence
21
19
 
22
- Database backups are logical dumps, not raw database data directories. File backups use one `restic backup` snapshot per run containing all configured mounted paths, so `restore-files latest` restores all file paths from that run.
20
+ Under the hood it uses [restic](https://restic.net/) for encrypted backup storage and repository management.
23
21
 
24
- Database dump snapshots are tagged with `kamal-backup`, `app:<name>`, `type:database`, `adapter:<adapter>`, and `run:<timestamp>`. The dump object uses a flat restic stdin filename such as `databases-chatwithwork-postgres-20260422T120000Z.pgdump` because restic stdin backups do not support nested virtual paths consistently.
22
+ ## Why Rails teams use it
25
23
 
26
- ## Quick Start With Kamal
24
+ `kamal-backup` is aimed at the common self-hosted Rails setup where:
27
25
 
28
- Add a backup accessory to your Kamal deploy config:
26
+ - the app is deployed with Kamal
27
+ - the database is PostgreSQL, MySQL/MariaDB, or SQLite
28
+ - file data lives on a mounted volume
29
+ - you need real restore drills and evidence for CASA or another security review
29
30
 
30
- ```yaml
31
- aliases:
32
- backup: accessory exec backup "kamal-backup backup"
33
- backup-list: accessory exec backup "kamal-backup list"
34
- backup-check: accessory exec backup "kamal-backup check"
35
- backup-evidence: accessory exec backup "kamal-backup evidence"
36
- backup-logs: accessory logs backup -f
31
+ If your app already stores Active Storage blobs directly in S3, there may be no local file path for `BACKUP_PATHS` to capture. In that case, `kamal-backup` still covers the database side, but object-storage backups are a separate concern.
32
+
33
+ ## Quick Start
34
+
35
+ Add the gem in your Rails app:
36
+
37
+ ```ruby
38
+ group :development do
39
+ gem "kamal-backup"
40
+ end
41
+ ```
42
+
43
+ Install it and generate the shared config stub:
44
+
45
+ ```sh
46
+ bundle install
47
+ bundle exec kamal-backup init
48
+ ```
49
+
50
+ That creates:
51
+
52
+ - `config/kamal-backup.yml`
53
+
54
+ For most Rails apps, that is enough. `restore local` and `drill local` can infer:
55
+
56
+ - the development database target from `config/database.yml`
57
+ - the local files target from `storage`
58
+ - the local drill state directory from `tmp/kamal-backup`
37
59
 
60
+ Only create `config/kamal-backup.local.yml` if you need to override those local defaults.
61
+
62
+ Then add the backup accessory to `config/deploy.yml`:
63
+
64
+ ```yaml
38
65
  accessories:
39
66
  backup:
40
67
  image: ghcr.io/crmne/kamal-backup:latest
@@ -64,34 +91,49 @@ bin/kamal accessory boot backup
64
91
  bin/kamal accessory logs backup
65
92
  ```
66
93
 
67
- Run manual commands:
94
+ Run the first backup from your app checkout with the local gem and Kamal-style destination selection:
95
+
96
+ ```sh
97
+ bundle exec kamal-backup -d production backup
98
+ bundle exec kamal-backup -d production list
99
+ bundle exec kamal-backup -d production evidence
100
+ ```
101
+
102
+ If you keep multiple deploy configs, pass `-c` the same way Kamal does:
68
103
 
69
104
  ```sh
70
- bin/kamal backup
71
- bin/kamal backup-list
72
- bin/kamal backup-check
73
- bin/kamal backup-evidence
74
- bin/kamal backup-logs
105
+ bundle exec kamal-backup -c config/deploy.staging.yml -d staging backup
75
106
  ```
76
107
 
77
- Alias reference:
108
+ Examples live in:
78
109
 
79
- | Alias | Expands to | Use |
80
- |---|---|---|
81
- | `bin/kamal backup` | `accessory exec backup "kamal-backup backup"` | Run one backup immediately. |
82
- | `bin/kamal backup-list` | `accessory exec backup "kamal-backup list"` | Show restic snapshots for the configured app. |
83
- | `bin/kamal backup-check` | `accessory exec backup "kamal-backup check"` | Run `restic check` and store the latest check result. |
84
- | `bin/kamal backup-evidence` | `accessory exec backup "kamal-backup evidence"` | Print redacted backup evidence JSON. |
85
- | `bin/kamal backup-logs` | `accessory logs backup -f` | Tail the backup accessory logs. |
110
+ - [examples/kamal-accessory.yml](examples/kamal-accessory.yml)
111
+ - [examples/kamal-backup.yml.example](examples/kamal-backup.yml.example)
112
+ - [examples/kamal-backup.local.yml.example](examples/kamal-backup.local.yml.example)
113
+
114
+ ## What Restic Does Here
115
+
116
+ `kamal-backup` uses restic as the backup engine and repository format.
117
+
118
+ In the normal Kamal setup, you do not install restic on the Rails app host. The backup accessory image already includes it. You only point the accessory at a restic repository, usually:
119
+
120
+ - S3-compatible object storage
121
+ - a restic REST server
122
+ - a filesystem path for local development
123
+
124
+ If you choose a `rest:` repository, `kamal-backup` does not install or operate that server for you. It is a separate service.
86
125
 
87
126
  ## Commands
88
127
 
89
- Commands usually run inside the production backup accessory with `bin/kamal accessory exec backup "kamal-backup <command>"`, or through Kamal aliases such as `bin/kamal backup`. A local gem install is useful when you intentionally want the operator laptop to run restic and database client commands directly.
128
+ The operator-facing command surface is:
90
129
 
91
130
  ```sh
131
+ kamal-backup init
92
132
  kamal-backup backup
93
- kamal-backup restore-db [snapshot-or-latest]
94
- kamal-backup restore-files [snapshot-or-latest] [target-dir]
133
+ kamal-backup restore local [snapshot-or-latest]
134
+ kamal-backup restore production [snapshot-or-latest]
135
+ kamal-backup drill local [snapshot-or-latest]
136
+ kamal-backup drill production [snapshot-or-latest]
95
137
  kamal-backup list
96
138
  kamal-backup check
97
139
  kamal-backup evidence
@@ -99,259 +141,162 @@ kamal-backup schedule
99
141
  kamal-backup version
100
142
  ```
101
143
 
102
- | Command | What it does |
103
- |---|---|
104
- | `backup` | Runs one immediate backup, creating one database snapshot and one file snapshot for all `BACKUP_PATHS`. |
105
- | `restore-db [snapshot-or-latest]` | Restores a database dump. Defaults to `latest` and requires explicit restore environment. |
106
- | `restore-files [snapshot-or-latest] [target-dir]` | Restores file paths from a file snapshot. Defaults to `latest /restore/files`. |
107
- | `list` | Lists restic snapshots for the configured app tags. |
108
- | `check` | Runs `restic check` and records the latest result for evidence output. |
109
- | `evidence` | Prints redacted JSON with backup configuration, latest snapshots, check status, and tool versions. |
110
- | `schedule` | Runs the foreground scheduler loop used by the container default command. |
111
- | `version` | Prints the gem version. `--version` and `-v` do the same. |
144
+ Production-side commands shell out through Kamal when you pass `-d` or `-c`. Local commands run on your machine.
112
145
 
113
- The default container command is:
146
+ Common examples:
114
147
 
115
148
  ```sh
116
- kamal-backup schedule
149
+ bundle exec kamal-backup -d production backup
150
+ bundle exec kamal-backup -d production check
151
+ bundle exec kamal-backup -d production evidence
152
+ bundle exec kamal-backup -d production restore production latest
153
+ bundle exec kamal-backup -d production drill production latest --database app_restore_20260423 --files /restore/files
154
+ bundle exec kamal-backup -d production version
155
+ bundle exec kamal-backup restore local latest
156
+ bundle exec kamal-backup drill local latest --check "bin/rails runner 'puts User.count'"
117
157
  ```
118
158
 
119
- ## Configuration
159
+ Use `kamal-backup help`, `kamal-backup help restore`, or `kamal-backup help drill` for task-specific usage.
120
160
 
121
- Required common environment:
161
+ ## How a Backup Run Works
122
162
 
123
- ```sh
124
- APP_NAME=chatwithwork
125
- DATABASE_ADAPTER=postgres
126
- RESTIC_REPOSITORY=s3:https://s3.example.com/chatwithwork-backups
127
- RESTIC_PASSWORD=change-me
128
- BACKUP_PATHS=/data/storage
129
- ```
130
-
131
- `BACKUP_PATHS` accepts colon-separated or newline-separated paths. Every path must exist. Suspicious broad paths such as `/`, `/var`, `/etc`, and `/root` are refused unless `KAMAL_BACKUP_ALLOW_SUSPICIOUS_PATHS=true`.
163
+ When `kamal-backup backup` runs, it does five things:
132
164
 
133
- PostgreSQL:
134
-
135
- ```sh
136
- DATABASE_ADAPTER=postgres
137
- DATABASE_URL=postgres://app@app-db:5432/app_production
138
- PGPASSWORD=change-me
139
- ```
165
+ 1. Validates the app name, restic repository, database settings, and `BACKUP_PATHS`.
166
+ 2. Creates a database backup with the database-native export tool.
167
+ 3. Streams that database backup into restic with tags such as `type:database`, `adapter:<adapter>`, and `run:<timestamp>`.
168
+ 4. Runs one `restic backup` for all configured `BACKUP_PATHS`, tagged as `type:files` with the same `run:<timestamp>`.
169
+ 5. Optionally runs `restic forget --prune` and `restic check`.
140
170
 
141
- MySQL/MariaDB:
142
-
143
- ```sh
144
- DATABASE_ADAPTER=mysql
145
- DATABASE_URL=mysql2://app@app-mysql:3306/app_production
146
- MYSQL_PWD=change-me
147
- ```
148
-
149
- SQLite:
150
-
151
- ```sh
152
- DATABASE_ADAPTER=sqlite
153
- SQLITE_DATABASE_PATH=/data/db/production.sqlite3
154
- ```
171
+ That shared `run:<timestamp>` tag lets you match the database backup and file backup from the same run.
155
172
 
156
- Retention defaults:
173
+ ## Restore
157
174
 
158
- ```sh
159
- RESTIC_KEEP_LAST=7
160
- RESTIC_KEEP_DAILY=7
161
- RESTIC_KEEP_WEEKLY=4
162
- RESTIC_KEEP_MONTHLY=6
163
- RESTIC_KEEP_YEARLY=2
164
- RESTIC_FORGET_AFTER_BACKUP=true
165
- ```
175
+ `restore` means "put data back."
166
176
 
167
- Set `RESTIC_FORGET_AFTER_BACKUP=false` for append-only repositories, such as a restic REST server started with `--append-only`. In that mode, run retention and prune from the backup server or another trusted maintenance process with delete permissions.
177
+ `restore local` runs on your machine. With `-d` or `-c`, it asks Kamal for the backup accessory config and uses that as the source of truth for:
168
178
 
169
- Scheduler and checks:
179
+ - `APP_NAME`
180
+ - `DATABASE_ADAPTER`
181
+ - `RESTIC_REPOSITORY`
182
+ - `LOCAL_RESTORE_SOURCE_PATHS` from the accessory `BACKUP_PATHS`
170
183
 
171
- ```sh
172
- BACKUP_SCHEDULE_SECONDS=86400
173
- BACKUP_START_DELAY_SECONDS=0
174
- RESTIC_CHECK_AFTER_BACKUP=false
175
- RESTIC_CHECK_READ_DATA_SUBSET=5%
176
- ```
184
+ For a normal Rails app, the local targets come from Rails conventions:
177
185
 
178
- For S3-compatible restic repositories, provide the standard restic/AWS variables as Kamal secrets:
186
+ - the development database in `config/database.yml`
187
+ - `storage` as the local files target
188
+ - `tmp/kamal-backup` as the local drill state directory
179
189
 
180
- ```sh
181
- AWS_ACCESS_KEY_ID=...
182
- AWS_SECRET_ACCESS_KEY=...
183
- AWS_DEFAULT_REGION=...
184
- ```
190
+ You still provide the local secrets yourself in env:
185
191
 
186
- ## Restore Drills
192
+ - `RESTIC_PASSWORD`
193
+ - `POSTGRES_PASSWORD` or `MYSQL_PWD` when needed
194
+ - `RESTIC_REPOSITORY` when it is not visible through `kamal config`
187
195
 
188
- Restores are intentionally hard to run by accident. Every restore command requires:
196
+ Example:
189
197
 
190
198
  ```sh
191
- KAMAL_BACKUP_ALLOW_RESTORE=true
199
+ bundle exec kamal-backup -d production restore local latest
192
200
  ```
193
201
 
194
- Database restores use restore-specific environment by default. They do not restore to `DATABASE_URL`.
195
-
196
- PostgreSQL restore:
202
+ `restore production` is the emergency path back into the live production database and live production file paths:
197
203
 
198
204
  ```sh
199
- bin/kamal accessory exec backup \
200
- --env KAMAL_BACKUP_ALLOW_RESTORE=true \
201
- --env RESTORE_DATABASE_URL=postgres://app@app-db:5432/app_restore \
202
- "kamal-backup restore-db latest"
205
+ bundle exec kamal-backup -d production restore production latest
203
206
  ```
204
207
 
205
- MySQL/MariaDB restore:
208
+ It prompts locally, then shells out through Kamal to the backup accessory.
206
209
 
207
- ```sh
208
- bin/kamal accessory exec backup \
209
- --env KAMAL_BACKUP_ALLOW_RESTORE=true \
210
- --env RESTORE_DATABASE_URL=mysql2://app@app-mysql:3306/app_restore \
211
- "kamal-backup restore-db latest"
212
- ```
213
-
214
- SQLite restore:
210
+ ## Restore Drills
215
211
 
216
- ```sh
217
- bin/kamal accessory exec backup \
218
- --env KAMAL_BACKUP_ALLOW_RESTORE=true \
219
- --env RESTORE_SQLITE_DATABASE_PATH=/restore/db/restore.sqlite3 \
220
- "kamal-backup restore-db latest"
221
- ```
212
+ `drill` means "restore, check, and record the result."
222
213
 
223
- File restore:
214
+ `drill local` is often the fastest proof for a small app:
224
215
 
225
216
  ```sh
226
- bin/kamal accessory exec backup \
227
- --env KAMAL_BACKUP_ALLOW_RESTORE=true \
228
- "kamal-backup restore-files latest /restore/files"
217
+ bundle exec kamal-backup -d production drill local latest --check "bin/rails runner 'puts User.count'"
229
218
  ```
230
219
 
231
- Restore targets that look production-like are refused unless:
220
+ `drill production` restores into scratch targets on production infrastructure. It does not touch the live production database:
232
221
 
233
222
  ```sh
234
- KAMAL_BACKUP_ALLOW_PRODUCTION_RESTORE=true
223
+ bundle exec kamal-backup -d production drill production latest \
224
+ --database app_restore_20260423 \
225
+ --files /restore/files \
226
+ --check "test -d /restore/files/data/storage"
235
227
  ```
236
228
 
237
- File restores to configured backup paths are refused unless:
229
+ Every drill writes `last_restore_drill.json` under `KAMAL_BACKUP_STATE_DIR`, and `kamal-backup evidence` includes that latest result.
238
230
 
239
- ```sh
240
- KAMAL_BACKUP_ALLOW_IN_PLACE_FILE_RESTORE=true
241
- ```
231
+ ## Evidence for CASA and Similar Reviews
242
232
 
243
- ## Evidence
233
+ `evidence` is the JSON summary you can attach to an ops record or security review.
244
234
 
245
- `kamal-backup evidence` prints a redacted JSON summary suitable for operational evidence:
235
+ It includes:
246
236
 
247
- - app name
248
- - current time
249
- - database adapter
250
- - redacted restic repository
251
- - configured file backup paths
252
- - whether client-side forget/prune is enabled
253
- - retention policy
254
237
  - latest database and file snapshots
255
- - last tracked `restic check` result
256
- - image version
257
- - installed tool versions
258
-
259
- Secrets, passwords, access keys, and database URL credentials are redacted.
238
+ - latest `restic check` result
239
+ - latest restore drill result
240
+ - retention settings
241
+ - tool versions
260
242
 
261
- Run:
262
-
263
- ```sh
264
- bin/kamal accessory exec backup "kamal-backup evidence"
265
- ```
243
+ For many reviews, the useful sequence is:
266
244
 
267
- ## Local Development
245
+ 1. scheduled backups
246
+ 2. repository checks
247
+ 3. a real restore drill
248
+ 4. `kamal-backup evidence`
268
249
 
269
- Run tests:
250
+ That reads much better to a reviewer than "the backup job is green."
270
251
 
271
- ```sh
272
- bin/test
273
- ```
252
+ ## Configuration Highlights
274
253
 
275
- Run docs locally:
254
+ Core accessory environment:
276
255
 
277
256
  ```sh
278
- cd docs
279
- bundle install
280
- bundle exec jekyll serve --livereload
281
- ```
282
-
283
- Published docs are configured for `https://kamal-backup.dev`.
284
-
285
- Build the image:
286
-
287
- ```sh
288
- docker build -t kamal-backup .
257
+ APP_NAME=chatwithwork
258
+ DATABASE_ADAPTER=postgres
259
+ RESTIC_REPOSITORY=s3:https://s3.example.com/chatwithwork-backups
260
+ RESTIC_PASSWORD=change-me
261
+ BACKUP_PATHS=/data/storage
289
262
  ```
290
263
 
291
- CI publishes container images to `ghcr.io/crmne/kamal-backup`. Pull requests build the image without pushing; branch, tag, SHA, default-branch `latest`, and default-branch version tags are pushed on non-PR builds. The version tag comes from `lib/kamal_backup/version.rb`, matching the gem version.
292
-
293
- The CLI is packaged as the `kamal-backup` gem. The Docker image builds and installs that gem, which is why `kamal-backup` is on `PATH` inside the container. On default-branch CI, a new gem version is published to RubyGems and GitHub Packages when it does not already exist. The RubyGems publish step expects the repository secret `RUBYGEMS_AUTH_TOKEN`.
294
-
295
- For local Ruby use:
264
+ PostgreSQL:
296
265
 
297
266
  ```sh
298
- gem build kamal-backup.gemspec
299
- gem install ./kamal-backup-*.gem
300
- kamal-backup --help
267
+ DATABASE_ADAPTER=postgres
268
+ DATABASE_URL=postgres://app@app-db:5432/app_production
269
+ PGPASSWORD=change-me
301
270
  ```
302
271
 
303
- In normal Kamal use, you do not need to install the gem on the app host. Run the command inside the accessory:
272
+ MySQL/MariaDB:
304
273
 
305
274
  ```sh
306
- bin/kamal accessory exec backup "kamal-backup evidence"
275
+ DATABASE_ADAPTER=mysql
276
+ DATABASE_URL=mysql2://app@app-mysql:3306/app_production
277
+ MYSQL_PWD=change-me
307
278
  ```
308
279
 
309
- Run a local backup against a filesystem restic repository:
280
+ SQLite:
310
281
 
311
282
  ```sh
312
- export APP_NAME=local-app
313
- export DATABASE_ADAPTER=sqlite
314
- export SQLITE_DATABASE_PATH=/tmp/app.sqlite3
315
- export BACKUP_PATHS=/tmp/app-files
316
- export RESTIC_REPOSITORY=/tmp/kamal-backup-restic
317
- export RESTIC_PASSWORD=local-password
318
- export RESTIC_INIT_IF_MISSING=true
319
-
320
- kamal-backup backup
321
- kamal-backup list
322
- kamal-backup evidence
283
+ DATABASE_ADAPTER=sqlite
284
+ SQLITE_DATABASE_PATH=/data/db/production.sqlite3
323
285
  ```
324
286
 
325
- An example Docker Compose setup for local integration work is in `examples/docker-compose.integration.yml`.
326
-
327
- ## Container Contents
328
-
329
- The image is based on Debian slim Ruby and includes:
330
-
331
- - Ruby runtime
332
- - `pg_dump` and `pg_restore`
333
- - `mariadb-dump` or `mysqldump`, plus `mariadb` or `mysql`
334
- - `sqlite3`
335
- - `restic`
336
- - CA certificates
337
- - `tini`
338
-
339
- ## Security Notes
287
+ Optional local config files:
340
288
 
341
- - Subprocesses are executed with argument arrays, not shell interpolation.
342
- - The CLI redacts secrets in errors and evidence output.
343
- - Database backups use logical dump tools.
344
- - File data should be mounted read-only in the backup accessory.
345
- - Restores require explicit environment flags.
346
- - Object storage credentials should be least-privilege for the backup bucket or prefix.
289
+ - `config/kamal-backup.yml`
290
+ - `config/kamal-backup.local.yml`
347
291
 
348
- ## Non-Goals
292
+ `config/kamal-backup.local.yml` is only for nonstandard local targets. Keep secrets such as `RESTIC_PASSWORD`, cloud credentials, and local DB passwords in environment variables, not in YAML files.
349
293
 
350
- - Not a hosted backup service.
351
- - Not a replacement for database point-in-time recovery.
352
- - Not a physical replication tool.
353
- - Not a secret manager.
294
+ ## Docs
354
295
 
355
- ## License
296
+ Full docs live in [`docs/`](docs/):
356
297
 
357
- MIT
298
+ - [`docs/_guide/getting-started.md`](docs/_guide/getting-started.md)
299
+ - [`docs/_guide/configuration.md`](docs/_guide/configuration.md)
300
+ - [`docs/_guide/restore.md`](docs/_guide/restore.md)
301
+ - [`docs/_guide/restore-drills.md`](docs/_guide/restore-drills.md)
302
+ - [`docs/_reference/commands.md`](docs/_reference/commands.md)
data/exe/kamal-backup CHANGED
@@ -1,5 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
4
+
5
+ require "bundler/setup"
6
+
3
7
  $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
4
8
 
5
9
  require "kamal_backup"