feat(devicebackup): UrBackup for the Windows laptops, Time Machine staging for the Macs
Deploy Caddyfile to valhalla / deploy (push) Successful in 1m42s

New devicebackup stack: UrBackup 2.5.x (pinned, watchtower off) in internet
mode on :55415 so laptops back up on the LAN and over the tailnet; web UI
only via Caddy + Authentik forward_auth (provider homelab-urbackup, pk 41).

MacBooks (tm-hub, tm-wif) use Time Machine on the host smbd, which already
owns :445. Shares are staged in /etc/samba/smb.conf.timemachine-pending and
not yet applied; README has the apply command and client setup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ginnoirandClaude Opus 5.5 committed 2026-10-01 12:45:32 -05:00
1 parent 1028bc3a74
commit a55cfd2b35
5 files changed
+169 -5

No files matched your search

+12
View File
@@ -473,6 +473,18 @@ backup.ginnoir.com {
} }
} }
# UrBackup web UI. Clients talk to :55415 directly, not through Caddy.
urbackup.ginnoir.com {
import internal_only
route {
import authentik_outpost
handle {
import authentik_forward_auth
reverse_proxy urbackup:55414
}
}
}
router.ginnoir.com { router.ginnoir.com {
import internal_only import internal_only
reverse_proxy 192.168.1.1 reverse_proxy 192.168.1.1
+2 -5
View File
@@ -12,11 +12,6 @@
<DT><A HREF="https://foundry2.ginnoir.com">foundry2</A> <DT><A HREF="https://foundry2.ginnoir.com">foundry2</A>
</DL><p> </DL><p>
<DT><H3>TABLETOP TOOLS (public)</H3>
<DL><p>
<DT><A HREF="https://5etools.ginnoir.com">5etools</A>
</DL><p>
<DT><H3>FILE STORAGE — internal only (Nextcloud) (internal)</H3> <DT><H3>FILE STORAGE — internal only (Nextcloud) (internal)</H3>
<DL><p> <DL><p>
<DT><A HREF="https://files.ginnoir.com">files</A> <DT><A HREF="https://files.ginnoir.com">files</A>
@@ -24,6 +19,7 @@
<DT><H3>STATIC SITES (public)</H3> <DT><H3>STATIC SITES (public)</H3>
<DL><p> <DL><p>
<DT><A HREF="https://5etools.ginnoir.com">5etools</A>
<DT><A HREF="https://wa4.ginnoir.com">wa4</A> <DT><A HREF="https://wa4.ginnoir.com">wa4</A>
</DL><p> </DL><p>
@@ -95,6 +91,7 @@
<DT><A HREF="https://webui.ginnoir.com">webui [internal]</A> <DT><A HREF="https://webui.ginnoir.com">webui [internal]</A>
<DT><A HREF="https://imgstudio.ginnoir.com">imgstudio [internal]</A> <DT><A HREF="https://imgstudio.ginnoir.com">imgstudio [internal]</A>
<DT><A HREF="https://backup.ginnoir.com">backup</A> <DT><A HREF="https://backup.ginnoir.com">backup</A>
<DT><A HREF="https://urbackup.ginnoir.com">urbackup [internal]</A>
<DT><A HREF="https://router.ginnoir.com">router [internal]</A> <DT><A HREF="https://router.ginnoir.com">router [internal]</A>
</DL><p> </DL><p>
+112
View File
@@ -0,0 +1,112 @@
# devicebackup stack
Full backups of the household laptops onto valhalla.
| Device | Disk | Tool | Cap |
|---|---|---|---|
| Windows laptop A | 1 TB | UrBackup image backups | shared 3.5 TB soft quota |
| Windows laptop B | 512 GB | UrBackup image backups | (same) |
| MacBook (hub) | 1 TB | Time Machine → `tm-hub` share | 1.5 TB |
| MacBook (wif) | 1 TB | Time Machine → `tm-wif` share | 1.5 TB |
Worst case (every disk full) that's ~6.5 TB on `storage1`. It had 16 TB free on 2026-10-01
(84% used); keep an eye on pool fill, since ZFS slows down past ~90%.
**storage1 has no redundancy.** Treat this as the *second* copy of each laptop, not the only one,
until the mirror rebuild is done.
## Windows: UrBackup
### Before first deploy (host)
```bash
sudo install -d -o ginnoir -g ginnoir /config/urbackup /storage1/labdata/urbackup
```
Register a new Portainer git stack → `stacks/devicebackup` (one-time), then push.
### Server settings (web UI → Settings)
- **General → Server:** backup storage path `/backups`.
- **General → Internet:** enable internet mode, server name `urbackup.ginnoir.com`, port `55415`;
tick **"Do image backups over internet"** and **"Do full file backups over internet"**.
- **General → Soft filesystem quota:** `3500G`.
- **Client defaults → Image backups:** incremental every 1 day, full every 30 days;
keep min 2 / max 4 full images, min 7 / max 30 incrementals. Volumes `ALL_NONUSB` (with ESP).
- **Client defaults → File backups:** off (images are browsable and mountable for single-file restores).
- Leave UrBackup with **no admin user**: auth is Authentik forward_auth at Caddy, and 55414 is not
published. Adding a UrBackup user just means logging in twice.
### Each Windows laptop
1. Web UI → **Add client → Internet/active client**, name it, and download the per-client installer
(it embeds the server address + auth key).
2. Run it on the laptop. The first full image takes a long time on Wi-Fi, so do it at home, plugged in.
3. **Make the restore USB:** download the UrBackup restore ISO and keep a stick around. A bare-metal
restore boots it, connects to the server on the LAN, and writes the image back.
4. BitLocker: images contain the *decrypted* volume. The data is protected only by valhalla's own security.
## macOS: Time Machine (host smbd)
Host `smbd` already serves `[storage1]` on :445, so Time Machine goes on the host Samba rather than
a container (Macs handle SMB on a non-standard port poorly). This config is **host-managed**, not
deployed from this repo. Keep this section in sync with `/etc/samba/smb.conf`.
Add to `[global]` (fruit has to be global, because macOS negotiates the AAPL extensions on the
first tree connect):
```ini
vfs objects = catia fruit streams_xattr
fruit:metadata = stream
fruit:model = MacSamba
fruit:posix_rename = yes
fruit:veto_appledouble = no
fruit:nfs_aces = no
fruit:wipe_intentionally_left_blank_rfork = yes
fruit:delete_empty_adfiles = yes
```
One share per Mac, so each Mac gets its own 1.5 TB cap:
```ini
[tm-hub]
path = /storage1/labdata/timemachine/hub
valid users = timemachine
read only = No
fruit:time machine = yes
fruit:time machine max size = 1500G
[tm-wif]
path = /storage1/labdata/timemachine/wif
valid users = timemachine
read only = No
fruit:time machine = yes
fruit:time machine max size = 1500G
```
Done on 2026-10-01: `timemachine` user + Samba password (password is in `stack.env`), and
`/storage1/labdata/timemachine/{hub,wif}` (owned by `timemachine`, mode 0700).
The full target config is **staged** at `/etc/samba/smb.conf.timemachine-pending`, already
`testparm`-validated. It is *not* live yet, because smbd re-reads `smb.conf` automatically
whenever the file changes. Apply it when nothing is mid-copy on `[storage1]`:
```bash
sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.bak-$(date +%F) && sudo mv /etc/samba/smb.conf.timemachine-pending /etc/samba/smb.conf && sudo systemctl reload smb
```
Samba registers the shares with avahi (already running), so on the LAN they show up directly in
**System Settings → General → Time Machine → Add Backup Disk**. Pick the share, enter the
`timemachine` credentials, and **turn on "Encrypt backup"**. Away from home, Bonjour doesn't cross
Tailscale, and valhalla has no MagicDNS name (the tailnet reaches it via the subnet route), so
when re-adding remotely use the LAN IP:
```bash
sudo tmutil setdestination -a "smb://timemachine@192.168.1.69/tm-hub"
```
## Verify
- [ ] Each Windows laptop: one full image completes, then **mount it in the UrBackup UI and open a file**.
- [ ] Each Mac: first backup completes, then **Enter Time Machine and restore one file**.
- [ ] Uptime Kuma: HTTP monitor on `https://urbackup.ginnoir.com`, TCP monitor on `valhalla:55415`.
+32
View File
@@ -0,0 +1,32 @@
# devicebackup stack — full backups of the household laptops onto valhalla.
#
# Windows laptops → UrBackup (this stack): incremental disk images, bare-metal restore.
# MacBooks → Time Machine over the HOST smbd (not in compose — host already owns
# :445, see README.md for the smb.conf shares).
#
# Clients run in UrBackup "internet mode" against urbackup.ginnoir.com:55415, which resolves
# to valhalla on the LAN and over the tailnet, so laptops keep backing up away from home.
# The web UI (55414) is only reachable through Caddy + Authentik forward_auth.
#
# Not part of the Kopia → B2 offsite set (stacks/backup) — this is copy #2 of each laptop.
services:
urbackup:
container_name: urbackup
image: uroni/urbackup-server:2.5.x
restart: unless-stopped
labels:
- "com.centurylabs.watchtower.enable=false"
networks: [edge]
env_file:
- stack.env
volumes:
- /config/urbackup:/var/urbackup
- /storage1/labdata/urbackup:/backups
ports:
- "55415:55415" # internet-mode clients (LAN + tailnet)
networks:
edge:
name: edge
external: true
+11
View File
@@ -0,0 +1,11 @@
# devicebackup stack — UrBackup server.
TZ=America/Chicago
# Run as ginnoir so /config/urbackup and /storage1/labdata/urbackup stay ginnoir-owned.
PUID=1000
PGID=1000
# Samba password for the host-managed Time Machine shares (tm-hub, tm-wif).
# Not read by the container; lives here so it is versioned with the stack (see README).
TIMEMACHINE_SMB_USER=timemachine
TIMEMACHINE_SMB_PASSWORD=Ey6gC0IL3rtm6nNL7oV3e08M