Working restic restore from snapshot id on boot.

This commit is contained in:
2026-04-23 19:01:12 -07:00
parent f3b9bfee9a
commit ce5d3f0cc6
6 changed files with 70 additions and 6 deletions

View File

@@ -110,6 +110,7 @@ all-apps/nassella/lldap-config/lldap_config.toml \
all-apps/ghost/.compose-env \ all-apps/ghost/.compose-env \
restic-env \ restic-env \
restic-password \ restic-password \
restic-restore.sh \
all-apps/.env \ all-apps/.env \
$(config_dir)ssh-keys $(config_dir)ssh-keys
cat cl.yaml | docker run --rm --volume $(config_dir)/ssh-keys:/pwd/ssh-keys --volume ${PWD}:/pwd --workdir /pwd -i quay.io/coreos/butane:latest -d /pwd > ignition.json cat cl.yaml | docker run --rm --volume $(config_dir)/ssh-keys:/pwd/ssh-keys --volume ${PWD}:/pwd --workdir /pwd -i quay.io/coreos/butane:latest -d /pwd > ignition.json
@@ -146,7 +147,7 @@ restic-snapshots: $(apps_config) restic-password
.PHONY: archive .PHONY: archive
archive: archive:
tar -cf nassella-latest.tar all-apps cl.yaml init-restic.sh main.tf make-caddyfile.sh Makefile \ tar -cf nassella-latest.tar all-apps cl.yaml init-restic.sh main.tf make-caddyfile.sh Makefile \
make-generated.sh make-nextcloud-env.sh make-ghost-env.sh make-restic-generated.sh make-restic-password.sh restic-snapshots.sh copy-apps.sh \ make-generated.sh make-nextcloud-env.sh make-ghost-env.sh make-restic-generated.sh make-restic-password.sh restic-snapshots.sh copy-apps.sh restic-restore.sh \
make-nassella-authelia-config.sh make-nassella-lldap-config.sh .terraform.lock.hcl make-nassella-authelia-config.sh make-nassella-lldap-config.sh .terraform.lock.hcl
cp nassella-latest.tar src/ cp nassella-latest.tar src/

View File

@@ -1,7 +1,7 @@
[Unit] [Unit]
Description=Main App Description=Main App
After=docker.service After=restic-restore.service
Requires=docker.service Requires=docker.service restic-restore.service
[Service] [Service]
TimeoutStartSec=0 TimeoutStartSec=0
ExecStart=/bin/bash -c '/usr/bin/docker compose -f /app/docker-compose.yaml $(find /app -mindepth 2 -maxdepth 2 -type f -name docker-compose.yaml -exec echo -f {} \;) up' ExecStart=/bin/bash -c '/usr/bin/docker compose -f /app/docker-compose.yaml $(find /app -mindepth 2 -maxdepth 2 -type f -name docker-compose.yaml -exec echo -f {} \;) up'

29
cl.yaml
View File

@@ -19,6 +19,21 @@ systemd:
[Install] [Install]
RequiredBy=local-fs.target RequiredBy=local-fs.target
- name: restic-restore.service
enabled: true
contents: |
[Unit]
Description=Run once on first boot, if needed, to restore a backup
After=docker.service
Requires=docker.service
[Service]
Type=oneshot
EnvironmentFile=/restic-env
ExecStart=/restic-restore.sh
[Install]
WantedBy=multi-user.target
- name: app.service - name: app.service
enabled: true enabled: true
contents_local: app/app.service contents_local: app/app.service
@@ -31,7 +46,7 @@ systemd:
[Service] [Service]
Type=oneshot Type=oneshot
EnvironmentFile=/restic-env EnvironmentFile=/restic-env
ExecStart=/usr/bin/bash -c "docker run --rm --volume /nassella:/nassella --volume /restic-password:/restic-password -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} -i restic/restic:0.18.0 backup --verbose --repo s3:${BACKBLAZE_BUCKET_URL} --password-file /restic-password /nassella" ExecStart=/usr/bin/bash -c "docker run --rm --volume /nassella:/nassella --volume /restic-password:/restic-password -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} -i restic/restic:0.18.0 backup --verbose --repo s3:${BACKBLAZE_BUCKET_URL} --password-file /restic-password --tag daily_automatic /nassella"
ExecStopPost=systemctl start app.service ExecStopPost=systemctl start app.service
- name: restic-backup.timer - name: restic-backup.timer
@@ -91,8 +106,20 @@ storage:
contents: contents:
local: restic-password local: restic-password
- path: /restic-env - path: /restic-env
overwrite: true
contents: contents:
local: restic-env local: restic-env
- path: /restic-restore.sh
mode: 0755
contents:
local: restic-restore.sh
- path: /etc/ssh/sshd_config.d/custom.conf
overwrite: true
mode: 0600
contents:
inline: |
PermitRootLogin no
AllowUsers core
### docker-compose sysext ### docker-compose sysext
### https://flatcar.github.io/sysext-bakery/docker_compose/ ### https://flatcar.github.io/sysext-bakery/docker_compose/
- path: /opt/extensions/docker-compose/docker-compose-2.34.0-x86-64.raw - path: /opt/extensions/docker-compose/docker-compose-2.34.0-x86-64.raw

View File

@@ -7,3 +7,7 @@ set -e
echo "AWS_ACCESS_KEY_ID=\"$BACKBLAZE_KEY_ID\"" echo "AWS_ACCESS_KEY_ID=\"$BACKBLAZE_KEY_ID\""
echo "AWS_SECRET_ACCESS_KEY=\"$BACKBLAZE_APPLICATION_KEY\"" echo "AWS_SECRET_ACCESS_KEY=\"$BACKBLAZE_APPLICATION_KEY\""
echo "BACKBLAZE_BUCKET_URL=\"$BACKBLAZE_BUCKET_URL\"" echo "BACKBLAZE_BUCKET_URL=\"$BACKBLAZE_BUCKET_URL\""
if [ -n "$RESTIC_SNAPSHOT_ID" ]; then
echo "RESTIC_SNAPSHOT_ID=\"$RESTIC_SNAPSHOT_ID\""
fi

8
restic-restore.sh Normal file
View File

@@ -0,0 +1,8 @@
#!/bin/bash
MARKER=/var/lib/firstboot.done
if [ ! -f "$MARKER" ] && [ -n "$RESTIC_SNAPSHOT_ID" ]; then
docker run --rm --volume /nassella:/nassella --volume /restic-password:/restic-password -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} -i restic/restic:0.18.0 restore "$RESTIC_SNAPSHOT_ID" --verbose --repo s3:${BACKBLAZE_BUCKET_URL} --password-file /restic-password --target /
fi
touch "$MARKER"

View File

@@ -1304,6 +1304,7 @@ chmod -R 777 /opt/keys")))
(get-most-recent-deployment-status db (session-user-id) instance-id))))))) (get-most-recent-deployment-status db (session-user-id) instance-id)))))))
(when (not (or (eq? status 'queued) (eq? status 'in-progress))) (when (not (or (eq? status 'queued) (eq? status 'in-progress)))
(let* ((instance-id (alist-ref "id" (current-params) equal?)) (let* ((instance-id (alist-ref "id" (current-params) equal?))
(restic-snapshot-id (alist-ref 'restic-snapshot-id (current-params)))
(results (results
(with-db/transaction (with-db/transaction
(lambda (db) (lambda (db)
@@ -1372,7 +1373,8 @@ chmod -R 777 /opt/keys")))
("BACKBLAZE_KEY_ID" . ,(alist-ref 'backblaze-key-id service-config)) ("BACKBLAZE_KEY_ID" . ,(alist-ref 'backblaze-key-id service-config))
("BACKBLAZE_APPLICATION_KEY" . ,(alist-ref 'backblaze-application-key service-config)) ("BACKBLAZE_APPLICATION_KEY" . ,(alist-ref 'backblaze-application-key service-config))
("BACKBLAZE_BUCKET_URL" . ,(alist-ref 'backblaze-bucket-url service-config)) ("BACKBLAZE_BUCKET_URL" . ,(alist-ref 'backblaze-bucket-url service-config))
("RESTIC_PASSWORD" . ,restic-password))))) ("RESTIC_PASSWORD" . ,restic-password)
,@(if (and restic-snapshot-id (not (string=? restic-snapshot-id ""))) `(("RESTIC_SNAPSHOT_ID" . ,restic-snapshot-id)) '())))))
(with-output-to-file (string-append dir "/config/production.tfvars") (with-output-to-file (string-append dir "/config/production.tfvars")
(lambda () (lambda ()
(map (lambda (e) (map (lambda (e)
@@ -1526,7 +1528,8 @@ chmod -R 777 /opt/keys")))
,(alist-ref 'instance-id instance))) ,(alist-ref 'instance-id instance)))
"Modify Setup")) "Modify Setup"))
(li "Upgrade Now (pending automatic upgrades scheduled for: )") (li "Upgrade Now (pending automatic upgrades scheduled for: )")
(li "Manage Backups") (li (a (@ (href "/backups/" ,(alist-ref 'instance-id instance)))
"Manage Backups"))
(li (a (@ (href "/destroy/" ,(alist-ref 'instance-id instance))) (li (a (@ (href "/destroy/" ,(alist-ref 'instance-id instance)))
"Destroy - deletes data and configuration (confirmation required)")) "Destroy - deletes data and configuration (confirmation required)"))
(li (a (@ (href "/reset/" ,(alist-ref 'instance-id instance))) (li (a (@ (href "/reset/" ,(alist-ref 'instance-id instance)))
@@ -1744,6 +1747,27 @@ chmod -R 777 /opt/keys")))
,output))) ,output)))
))))) )))))
(get/widgets
("/backups/:id")
(let* ((instance-id (alist-ref "id" (current-params) equal?))
;; (res (with-db/transaction
;; (lambda (db)
;; `((status . ,(get-most-recent-deployment-status db (session-user-id) instance-id))
;; (progress . ,(get-most-recent-deployment-progress db (session-user-id) instance-id))))))
)
`(App
(Main-Container
(VStack
(h1 "Backups")
(a (@ (href "/")) "Create Snapshot") ;; TODO
(table
(thead
(tr (th "Time") (th "Size") (th "Tag") (th "*")))
(tbody
(tr (td "2026-04-22 22:24:41") (td "139.742 MiB") (td "") (td (a (@ (href "/")) "Restore")))
(tr (td "2026-04-21 12:01:03") (td "139.742 MiB") (td "before upgrade") (td (a (@ (href "/")) "Restore")))
(tr (td "2026-04-21 22:24:41") (td "129.742 MiB") (td "") (td (a (@ (href "/")) "Restore"))))))))))
(schematra-install) (schematra-install)
)) ))