Compare commits

..
33 Commits
Author SHA1 Message Date
julien ecdc3fea76 "Updates" 2026-11-03 11:07:17 +01:00
julien ec824c5ba0 "Updates" 2026-11-03 11:05:50 +01:00
julien 6c9495b285 "Updates" 2026-10-28 16:32:46 +01:00
julien cb18a906cc "Updates" 2026-10-28 16:29:53 +01:00
julien 3e0063c969 "Updates" 2026-10-28 15:14:56 +01:00
julien 99922e6388 "Updates" 2026-10-28 15:14:02 +01:00
julien e8a1110b81 "Updates" 2026-10-28 14:39:18 +01:00
julien 46eec705fd "Updates" 2026-10-28 14:37:14 +01:00
julien a99013ea2e "Updates" 2026-10-28 14:36:23 +01:00
julien 3d48a3b11a "Updates" 2026-10-27 09:24:36 +01:00
julien d69005508b "Updates" 2026-10-27 08:37:39 +01:00
julien 4b29a0f45c "Updates" 2026-10-23 18:45:56 +02:00
julien ad4f6eb97f "Updates" 2026-10-21 17:21:40 +02:00
julien 9719212edb "Updates" 2026-10-15 19:32:05 +02:00
julien c58777ec1d "Updates" 2026-10-15 19:19:30 +02:00
julien 6af121a9bb "Updates" 2026-10-15 19:08:22 +02:00
julien 5225327413 "Updates" 2026-10-15 19:03:29 +02:00
julien 348cdccfd7 "Updates" 2026-10-15 19:02:49 +02:00
julien 5acdfebc71 "Updates" 2026-10-07 17:45:32 +02:00
julien d2268f7383 "Updates" 2026-10-07 17:33:48 +02:00
julien 61fe5ef660 "Updates" 2026-10-01 11:53:09 +02:00
julien 33bd2dfeed "Updates" 2026-09-19 15:31:55 +02:00
julien d3833df125 "Updates" 2026-09-17 08:52:54 +02:00
julien 97b1fa7dd1 "Updates" 2026-09-17 08:51:44 +02:00
julien 25c58446e9 "Updates" 2026-08-29 16:08:34 +02:00
julien d99e4b1e52 Updates 2026-08-23 12:39:04 +02:00
julien 9ef4b9ea8b "Updates" 2026-08-23 12:35:34 +02:00
julien 76d2d806a9 "Updates" 2026-07-31 18:23:18 +02:00
julien d4a4139a0c "Updates" 2026-07-29 12:40:25 +02:00
julien 6149daa549 "Updates" 2026-07-22 09:06:08 +02:00
julien ee6bd1a243 "Updates" 2026-07-21 10:16:31 +02:00
julien 8e3d295e8f "Updates" 2026-07-14 11:22:58 +02:00
julien d07497e061 "Updates" 2026-07-09 00:30:55 +02:00
9 changed files with 326 additions and 482 deletions

No files matched your search

+11 -10
View File
@@ -1,5 +1,5 @@
$TTL 3600
@ IN SOA dns106.ovh.net. tech.ovh.net. (2083530541 86400 3600 3600000 300)
@ IN SOA dns106.ovh.net. tech.ovh.net. (2093525583 86400 3600 3600000 300)
IN NS dns106.ovh.net.
IN NS ns106.ovh.net.
IN MX 100 mx3.mail.ovh.net.
@@ -18,7 +18,6 @@ _autodiscover._tcp IN SRV 0 0 443 pro1.mail.ovh.net.
_dmarc IN TXT "v=DMARC1;p=none;sp=none;aspf=r;"
affine IN A 176.188.240.123
asm IN A 176.188.240.123
auth IN A 176.188.240.123
autoconfig IN CNAME autodiscover.mail.ovh.net.
autodiscover IN CNAME mailconfig.ovh.net.
books IN A 176.188.240.123
@@ -26,16 +25,16 @@ borg IN A 176.188.240.123
cap IN A 176.188.240.123
cfy IN A 176.188.240.123
cloud IN A 176.188.240.123
cnvrt IN A 176.188.240.123
crbn IN A 176.188.240.123
cs IN A 176.188.240.123
dev IN A 176.188.240.123
design IN A 176.188.240.123
dia IN A 176.188.240.123
draw IN A 176.188.240.123
events IN A 176.188.240.123
freecad IN A 176.188.240.123
ftp IN CNAME delmar.bzh.
gen IN A 176.188.240.123
git IN A 176.188.240.123
gotify IN A 176.188.240.123
hmr IN A 176.188.240.123
home-assistant IN A 176.188.240.123
homepage IN A 176.188.240.123
imgs IN A 176.188.240.123
@@ -45,24 +44,26 @@ jellyfin IN A 176.188.240.123
jellyseerr IN A 176.188.240.123
kontadenn IN A 176.188.240.123
lnk IN A 176.188.240.123
lud IN A 176.188.240.123
minio IN A 176.188.240.123
mmgr IN A 176.188.240.123
nds IN A 176.188.240.123
nsns IN A 176.188.240.123
octoprint IN A 176.188.240.123
oec IN A 176.188.240.123
ovhemp1116203-selector1._domainkey 60 IN CNAME ovhemp1116203-selector1._domainkey.274927.cq.dkim.mail.ovh.net.
ovhemp1116203-selector2._domainkey 60 IN CNAME ovhemp1116203-selector2._domainkey.274928.az.dkim.mail.ovh.net.
paperless IN A 176.188.240.123
pdf IN A 176.188.240.123
penpot IN A 176.188.240.123
pip IN A 176.188.240.123
search IN A 176.188.240.123
send IN A 176.188.240.123
shop IN A 176.188.240.123
sketch IN A 176.188.240.123
slicer IN A 176.188.240.123
smk IN A 176.188.240.123
snot IN A 176.188.240.123
stream IN A 176.188.240.123
swpt IN A 176.188.240.123
timesheet IN A 176.188.240.123
tournoi IN A 176.188.240.123
tpml IN A 176.188.240.123
trek IN A 176.188.240.123
trmx IN A 176.188.240.123
+176
View File
@@ -0,0 +1,176 @@
A practical tutorial for people who moved to a ZimaBoard for the faster CPU and extra RAM, but want to keep using their existing Synology as a rock-solid backup target.
Disclaimer: this is a setup that works well for me. I take no responsibility for your data or hardware — test on your own gear, verify the results yourself, and be very careful with any command that writes to a disk.
The idea
Your ZimaBoard is now the workhorse — apps, containers, everything runs there. Your Synology is perfect for what it’s genuinely great at: reliable, cheap, roomy storage you write to and rarely read. This tutorial wires the two together so the ZimaBoard pushes versioned, space-efficient backups to the Synology every night, automatically.
What you get:
Dated snapshots — one folder per run (e.g. 2026-08-06_000006), each a complete browsable copy of your data at that moment.
Almost no extra space per snapshot — unchanged files are hardlinked, so keeping 14 daily snapshots costs roughly one copy + the daily changes, not 14 full copies. (In practice: one snapshot looks like 517 GB, but 14 of them plus the live mirror total just 542 GB on disk.)
Only changed data crosses the network each night — quick after the first run.
A locked-down backup key that can’t get a shell or touch anything outside the backup folder.
How it works (two steps, and why)
Rather than one big rsync, the nightly job does two things:
Snapshot — runs on the Synology itself: copy the previous backup into a new dated folder with cp -al (a hardlink copy). Done locally this is near-instant.
Mirror — runs over SSH from the ZimaBoard: a plain rsync into a single CURRENT/ folder.
Snapshot first, mirror second — that way, if a mirror is ever interrupted, the previous night’s snapshot is already complete and safe.
The Synology ends up looking like:
/volume2/Backups/
├── CURRENT/ ← the live mirror (updated in place each night)
├── 2026-08-05_000006/ ← dated hardlinked snapshot
├── 2026-08-06_000006/ ← dated hardlinked snapshot
└── ... ← up to however many you keep
Restore from a dated snapshot, never from CURRENT — CURRENT is the live mirror and could be mid-update.
Why the snapshot runs on the Synology, not over a mounted share: cp -al creates one hardlink per file. Run locally on the Synology, hardlinking a large tree takes a couple of minutes. Run across an SMB/network mount, each hardlink becomes a separate network round-trip — for a large file count that turns minutes into many hours. So we trigger the snapshot on the Synology. This one detail makes or breaks the whole thing.
Step 1 — Turn on rsync-over-SSH on the Synology
In DSM:
Control Panel → File Services → rsync → enable the rsync service. Note the SSH encryption port shown (often non-standard). Your backups use this port.
Leave the “rsync account” option off (that’s an unencrypted mode you don’t need).
Make sure your DSM user is in the administrators group (Control Panel → User & Group) — DSM only allows admin users to SSH in by default.
Enable user home service (Control Panel → User & Group → Advanced), so your user has a home directory with a ~/.ssh folder.
DSM’s SSH is strict about a couple of things:
~/.ssh must be 700 and ~/.ssh/authorized_keys must be 600, or DSM quietly ignores your key and falls back to password auth.
If rapid failed attempts get your source blocked, clear it under Control Panel → Security → Account (Auto Block).
Step 2 — Create a key and restrict it with rrsync
On the ZimaBoard, generate a key with no passphrase (an automated job can’t type one). Put it somewhere that survives reboots — on ZimaOS, keep it on your data pool, e.g. under /media/YOURPOOL/scripts/.ssh/:
ssh-keygen -t ed25519 -f /media/YOURPOOL/scripts/.ssh/synology_backup -N ""
rrsync is the official wrapper that confines a key to rsync-only, in one folder. Fetch it into your DSM user’s home (over SSH to the Synology):
mkdir -p ~/bin
curl -o ~/bin/rrsync https://raw.githubusercontent.com/RsyncProject/rsync/master/support/rrsync
chmod +x ~/bin/rrsync
(head -1 ~/bin/rrsync tells you if it wants python3 or perl — DSM has both.)
Install the public key on the Synology with a forced command, so this key can only run rsync into your backup folder — no shell, no other paths:
# on the Synology, append (>> not >) to ~/.ssh/authorized_keys:
cat >> ~/.ssh/authorized_keys <<'EOF'
command="/var/services/homes/YOURUSER/bin/rrsync '/volume2/Backups'",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-ed25519 AAAA...your_public_key... zimaboard
EOF
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
Use plain rrsync '...', not -wo — write-only mode blocks reading the destination, which the snapshot approach and any restore need.
Test: an rsync of a small file should work; a plain ssh with this key should not give you a shell. That refusal is the lockdown doing its job.
Step 3 — The snapshot script (lives on the Synology)
Put this on the Synology as ~/bin/snapshot.sh (adjust path and retention):
#!/bin/sh
BACKUP_ROOT="/volume2/Backups"
RETENTION=14
TS=$(date +%Y-%m-%d_%H%M%S)
cd "$BACKUP_ROOT" || exit 1
[ -d CURRENT ] || { echo "No CURRENT yet, skipping"; exit 0; }
echo "Snapshotting CURRENT -> $TS"
mkdir -p "$TS"
cp -al CURRENT/. "$TS/" || { rm -rf "$TS"; echo "cp -al failed"; exit 1; }
TOTAL=$(ls -1d [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]_* 2>/dev/null | wc -l)
if [ "$TOTAL" -gt "$RETENTION" ]; then
ls -1d [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]_* | sort | head -n $((TOTAL-RETENTION)) \
| while read -r old; do echo "Pruning $old"; rm -rf "$old"; done
fi
echo "Done: $TS"
chmod +x ~/bin/snapshot.sh and test it once by hand — it should finish in a couple of minutes and leave a dated folder.
Trigger it remotely with a second restricted key, so the nightly job can run it without a shell. Generate a second key on the ZimaBoard (synology_snapshot), and install its public key on the Synology forced to run only this script:
command="/var/services/homes/YOURUSER/bin/snapshot.sh",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-ed25519 AAAA...second_public_key... zimaboard
Now SSHing in with that key just runs the snapshot and disconnects.
Step 4 — The nightly backup script (on the ZimaBoard)
#!/bin/sh
SSH="ssh -p PORT -o StrictHostKeyChecking=accept-new"
SNAPKEY=/media/YOURPOOL/scripts/.ssh/synology_snapshot
MIRRORKEY=/media/YOURPOOL/scripts/.ssh/synology_backup
USER_HOST="youruser@your.synology.ip"
# 1. Snapshot CURRENT server-side (fast, local cp -al)
$SSH -i "$SNAPKEY" "$USER_HOST" || { echo "snapshot failed"; exit 1; }
# 2. Mirror your data -> CURRENT
rsync -aH --delete --stats \
-e "$SSH -i $MIRRORKEY" \
/media/YOURPOOL/ "$USER_HOST":/CURRENT/
Adjust the pool path, port, and add any excludes you need (see the traps below).
Scheduling on ZimaOS: ZimaOS clears the system crontab on reboot, so don’t rely on plain cron. Run the schedule from a small Docker container instead (e.g. the lightweight Ofelia scheduler, deployed as a Portainer stack) — Docker state lives on your pool and survives reboots, so the schedule sticks. Point one Ofelia job at your backup script on your chosen time (e.g. daily at 00:00).
Two traps worth knowing before your first run
1. rsync include/exclude order is first-match-wins. If you exclude a big directory but want to keep a subfolder of it, the --include for that subfolder must come before the broad --exclude, or it never takes effect and you silently lose that data. Correct order:
--include='/somedir/'
--include='/somedir/keepthis/***'
--exclude='/somedir/**'
2. Some objects can’t be rsynced, and that’s normal. Live special files (block devices, sockets, certain container-runtime internals under Docker’s overlay2) make rsync return exit 23 (“some files not transferred”) — the real files still went across fine. If you back up your whole pool, exclude Docker’s runtime layers (keep docker/volumes, skip docker/overlay2 and friends), plus the SMB recycle bin (.trash) and @eaDir metadata. Treat exit codes 23 and 24 (files vanished mid-copy — normal on a live system) as OK in your script; anything else is a real failure.
Verify it — the important part
Check hardlinks are real (snapshots share storage instead of duplicating). On the Synology:
find "/volume2/Backups/<a-dated-snapshot>/<some/known/file/path>" -type f -printf '%n %p\n' | head
Link count 2 or more = shared with CURRENT, working correctly. 1 = something’s full-copying.
Check the real total size — the decisive space test. On the Synology:
du -sh "/volume2/Backups"
du counts hardlinked files only once, so CURRENT + all snapshots together should total roughly one copy plus accumulated changes — not N copies. (Example: 14 snapshots + mirror = 542 GB, versus 517 GB for a single snapshot. The 25 GB difference is two weeks of real changed data.) Note: File Station → Properties on one snapshot shows the full ~517 GB because it counts each hardlink as a full file — that number is misleading. du -sh on the whole Backups folder is the true figure.
Check the data you expect is actually there:
ls "/volume2/Backups/CURRENT/"
ls "/volume2/Backups/CURRENT/<a/subfolder/you/care/about>"
Restoring
One file: browse the right dated snapshot on the Synology (File Station or SSH) and copy it out — plain hardlinked folders, no special tooling.
Full restore: rsync a dated snapshot back to the ZimaBoard using your normal Synology login (the restricted keys are for pushing):
rsync -aH --info=progress2 -e "ssh -p PORT" \ "youruser@synology:/volume2/Backups/2026-MM-DD_HHMMSS/" /media/YOURPOOL/
Fix ownership afterward if an app expects specific file owners (databases, web apps, etc.).
Getting the most out of the Synology as a target
Throughput will be modest, and that’s expected. A single rsync stream over gigabit, with lots of small files, runs well under line speed because per-file overhead dominates. A link-aggregation bond doesn’t speed up a single stream. The first full run takes a while; every run after is fast because only changes move.
Keep the versioning on the Synology (Step 3). It’s the difference between a 2-minute snapshot and an hours-long one.
If a run ever fails with “another instance is already accessing this directory,” a killed transfer left a process running on the Synology holding the lock. SSH in, ps aux | grep rsync, and kill the leftover rrsync/rsync --server PIDs — but not the SynoRsync … --daemon one (that’s DSM’s own service).
Expect a “login at an unusual time” notice if you back up at night — that’s DSM (via Active Insight) noticing your own nightly login. Either widen the “usual” window in Active Insight or accept the notice; don’t disable login alerts entirely.
Keep the disks healthy (SMART checks, periodic scrubs). This is where your safety net lives.
One habit to keep
Verify on disk. Exit codes and “done” messages don’t prove your data is there. Check the destination contents, the link counts, and the real du size yourself now and then. It takes a minute and it’s the difference between hoping you have a backup and knowing you do.
Binary file not shown.
+2 -1
View File
@@ -67,7 +67,8 @@ UUID=B23E-A140 /boot/efi vfat umask=0077
# swap was on /dev/mmcblk0p3 during installation
UUID=69691db2-1213-4f0b-8797-a246e6924c4a none swap sw 0 0
# ssd
UUID=6702c3b0-eb03-4c1f-9ddc-56f4f7736222 /mnt/ssd ext4 defaults 0 0
# UUID=6702c3b0-eb03-4c1f-9ddc-56f4f7736222 /mnt/tmp ext4 defaults 0 0
UUID=bac562df-e5ca-4b1c-acde-d6c541a89ddb /mnt/ssd ext4 defaults 0 0
/mnt/ssd/var /var none bind
/mnt/ssd/tmp /tmp none bind
/mnt/ssd/home /home none bind
+12 -7
View File
@@ -31,6 +31,9 @@ ff02::3 ip6-allhosts
192.168.1.19 pearl
192.168.1.20 karen
# turinpi
192.168.1.21 bikinibottom bikinibottom.local
#
192.168.1.53 retropie
```
@@ -50,18 +53,20 @@ ssh-copy-id -f -i ~/.ssh/id_ed25519.pub pleb@<hostname>
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBLk24u7FT8PhAdM8EVUFGlOi0hle4CW8L284E1foUhS julien@julien-pc
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE6wr+DUbcfVTltoWT6gbPRY3geUYNhgN7/CLcMaMu0B eliot@toile-win
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKmttayKqj6Z290hMCc97v4dMZTSUz4lYgXR0NtcRr8U delmar@thinkpad
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFlta/YdJ0ztVpZsP/nh37Fn+H5Hxg/Mw+jR91f5Gf08 pleb@bob
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN9mn7tuYWTPLbH2MViAkiKSUkXj4NauCUgzj778LoQ2 pleb@carlo
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKL7A0xvHSfmWo+LUHdWWb03a5NXN1IlbLS5iSHxs3zw pleb@sandy
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHpnC0ftrLwzhsmonDtSvh38Oi5OGe1iOaQjlsm1RlD2 pleb@gary
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII9USnPFJx/PbV+KnlTN4o3f4SwiuHCWaAlE8aKcY4Ne pleb@sheldon
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMrWtBN3yRh3PHG+7UUeRUIvhuMcwtR88FzUn4xS5FyV pleb@pearl
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMfd7PrJ50jHrG6yjIJ5u7jKTyXi9mPn8/oa+HNAVNsf pleb@krabs
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKe0iX+Al5bdMf93lMj/V/1FUpXJsYG6XNw4C4Bpj7SS pleb@sandy
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPq4T605pUQsUAntUbFousyuJADISEHAk+MnZoq7lAYB pleb@gary
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKvQwj0zeF18hl/BcX7eRFgXb3TNFUGooOE1NJeNlX0z pleb@sheldon
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEPUeE7PCnDcEW7dtyWUdxDBD57GmIzeY1a0eFn0JiRX pleb@pearl
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILPeyUpr/R9KgX+0Yr8R9VLIoxREc+XC7EJA1aWDS/08 pleb@krabs
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJtrn0Oj2IstMwzheIZcJGBA8RNWTyNtksaK2LhvjNul pleb@bernie
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHh1LTS5PzsQ45xiRbyxBbCurI7JdEpdkCsbx3mlYaaR pleb@patrick
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAaOsYNLsoYcXDV3I7zbJABeIo7CJOdMxUN86rH1/IH9 pleb@karen
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG+Odc/LY/fPcapj6yxF6of+pygbaFvMg0P9RUA69pQV borg@3c6ee04b29c5
## krabs
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJDsfMBjZO/uWCoyvuYEKVq4wr6Z67gZRC3wRAimxdLS root@nextcloud-aio-borgbackup
## karen
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCiAt5dNKbcaYmmsMGitBTaYoKkfEMJ5dGBzbSIDF4WdmPQGFmNf3urAxM1MDjlW7ifzfia7I49pc+Sndo0+b/FiS9FIMWwlNmOrr5c24XXZvYhPvk2M9ghEhXgLGDO3N/xPG6M+rrEzeRFXCdlHZuan6/iUdGcDQtgS2q4ciAMCk8V0QptmvWYqgs/CMsnU3WULUA+abKdx605zzG0inF6pNFaIO50mRraPQsWq34SxXknkJnTBHFogj9NyV/Y9BhiKBm3IXn2f9cVK5/+8Af91w5uI07kpLnPXSDkEZFKK4J48dCdDLhOk2H1/PzapkwW5pF8dhBeKVW2W7oyvuWplKj7cS2dS9ODqqae5kgI83IBdOxQ3VONRCHiUVbezREON66xpOncmWq/YhegWCCHviHUzO0DtpxQXPnZTcX6LwiWhZ9vzGdostJ72i2PxtU155S5PBqaXF+u01cbD0yOuA364LIri2mJxgXHqQH6VwgUJYA7G3Ln4KTueHc9oQxZS5+zZA6LfIu0AB0o7RGcvRV2F+434svy9aXceOUQ2n/5qWo6jmqtOsx2IGkiBkCCHBK8G/83mWBWcfbzXdfPDj7a2xeMoiAU5Rr99JIJkiplDMVrR48diGtCxRYjitWUBigbz6Yy0ozowT6TUvK2PaPUgfhxVK2lhi/et37+/w== NVIDIA-SDK-Manager
```
-375
View File
@@ -1,375 +0,0 @@
Kubernetes (K3Sup)
===
### Installation de kubectl ?
```bash
sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
sudo mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
sudo chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo chmod 644 /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubectl
```
### Installation de k3sup :
```bash
# Avec curl
curl -sLS https://get.k3sup.dev | sh
sudo install k3sup /usr/local/bin/
# Ou téléchargement direct depuis GitHub
wget https://github.com/alexellis/k3sup/releases/download/0.13.11/k3sup
chmod +x k3sup
sudo mv k3sup /usr/local/bin/
```
#### Premier déploiement :
```bash
# Installation du master node
k3sup install --ip 192.168.1.14 --user pleb --ssh-key $HOME/.ssh/bikiniBottom
# Ajout des worker nodes
k3sup join --ip 192.168.1.13 --server-ip 192.168.1.14 --user pleb --ssh-key $HOME/.ssh/bikiniBottom
k3sup join --ip 192.168.1.16 --server-ip 192.168.1.14 --user pleb --ssh-key $HOME/.ssh/bikiniBottom
k3sup join --ip 192.168.1.19 --server-ip 192.168.1.14 --user pleb --ssh-key $HOME/.ssh/bikiniBottom
```
#### Vérification du cluster :
```bash
# Export du kubeconfig
export KUBECONFIG=~/delmar.bzh/kubernetes/kubeconfig
# Vérification des nœuds
kubectl get nodes -o wide
# Check des pods système
kubectl get pods -n kube-system
```
#### Setting labels:
```bash
# sudo k3s kubectl label nodes xxx kubernetes.io/role=worker
kubectl label nodes gary kubernetes.io/role=worker
kubectl label nodes sheldon kubernetes.io/role=worker
kubectl label nodes pearl kubernetes.io/role=worker
# sudo k3s kubectl label nodes sandy node-type=worker
kubectl label nodes gary node-type=worker
kubectl label nodes sheldon node-type=worker
kubectl label nodes pearl node-type=worker
```
```bash
kubectl get nodes
```
```
NAME STATUS ROLES AGE VERSION
gary Ready worker 82m v1.35.5+k3s1
pearl Ready worker 81m v1.35.5+k3s1
sandy Ready control-plane 84m v1.35.5+k3s1
sheldon Ready worker 82m v1.35.5+k3s1
```
### Helm
> On sandy
```bash
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
helm version
```
#### [Headlamp](https://headlamp.dev/docs/latest/)
```bash
# first add our custom repo to your local helm repositories
helm repo add headlamp https://kubernetes-sigs.github.io/headlamp/
# now you should be able to install headlamp via helm
helm install bb-headlamp headlamp/headlamp --namespace kube-system
```
```
NAME: bb-headlamp
LAST DEPLOYED: Tue Feb 17 17:17:03 2026
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
```
1. Get the application URL by running these commands:
```bash
export POD_NAME=$(kubectl get pods --namespace kube-system -l "app.kubernetes.io/name=headlamp,app.kubernetes.io/instance=bb-headlamp" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace kube-system $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace kube-system port-forward $POD_NAME 8080:$CONTAINER_PORT
```
2. Get the token using
```bash
kubectl create token bb-headlamp --namespace kube-system
```
#### metallb
```bash
# Add MetalLB repository to Helm
helm repo add metallb https://metallb.github.io/metallb
# Check the added repository
helm search repo metallb
helm upgrade --install metallb metallb/metallb --create-namespace \
--namespace metallb-system --wait
```
```bash
Release "metallb" does not exist. Installing it now.
NAME: metallb
LAST DEPLOYED: Wed Feb 18 11:46:03 2026
NAMESPACE: metallb-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
MetalLB is now running in the cluster.
Now you can configure it via its CRs. Please refer to the metallb official docs
on how to use the CRs.
```
```bash
vim metallb-config.yaml
---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default-pool
namespace: metallb-system
spec:
addresses:
- 192.168.1.21-192.168.1.30
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb-system
spec:
ipAddressPools:
- default-pool
```
#### traefik
```bash
vim traefik-ingress.yml
```
```
---
apiVersion: v1
kind: Secret
metadata:
name: traefik-basic-auth-secret
namespace: kube-system
data:
users: |2
YWRtaW46JGFwcjEkMmp5TzMwYmskRE5IV0VEQW1VQXFVajVGOHNvdXNVMAoK
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: traefik-basic-auth-middleware
spec:
basicAuth:
secret: traefik-basic-auth-secret
realm: "Traefik Dashboard"
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: traefik-ingress
namespace: kube-system
annotations:
spec.ingressClassName: traefik
traefik.ingress.kubernetes.io/router.middlewares: kube-system-traefik-basic-auth-middleware@kubernetescrd
spec:
serviceAccountName: traefik-ingress
env:
name: OVH_ENDPOINT
value: ovh-eu
name: OVH_APPLICATION_KEY
value: 3f8bdfed17f848d8
name: OVH_APPLICATION_SECRET
value: 6946758d7515ecef108aeb286bf3c7d0
name: OVH_CONSUMER_KEY
value: 94b2ddf482d36421a33aa6b3aa51595
args:
- --configFile=/config/traefik.toml
volumeMounts:
- name: traefik-config
mountPath: /config/
- name: traefik-custom
mountPath: /custom/
- name: traefik-certs
mountPath: /certs/
ports:
name: http
containerPort: 80
name: https
containerPort: 443
name: dashboard
containerPort: 8080
volumes:
- name: traefik-config
configMap:
- name: traefik-config
- name: traefik-custom
- name: traefik-certs
persistentVolumeClaim:
claimName: traefik-certsrules:
- http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: traefik-dashboard
port:
number: 8080
---
apiVersion: v1
kind: Service
metadata:
name: traefik-dashboard
spec:
ports:
- name: http
port: 8080
targetPort: 8080
selector:
app: traefik-dashboard
type: LoadBalancer
```
```bash
sudo k3s kubectl -n kube-system apply -f traefik-ingress.yml
```
#### [longhorn](https://longhorn.io)
```bash
helm repo add longhorn https://charts.longhorn.io
helm repo update
kubectl create namespace longhorn-system
helm install longhorn longhorn/longhorn --namespace longhorn-system
USER=admin; PASSWORD=v5bB4OQRDfY5tFJ1; echo "${USER}:$(openssl passwd -stdin -apr1 <<< ${PASSWORD})" >> auth
kubectl -n longhorn-system create secret generic basic-auth --from-file=auth
vim longhorn/longhorn-middelwares.yaml
````
```
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: longhorn-auth
namespace: longhorn-system
spec:
basicAuth:
secret: basic-auth
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: longhorn-buffering
namespace: longhorn-system
spec:
buffering:
# Allows backing image uploads up to 10,000MB
maxRequestBodyBytes: 10485760000
```
```bash
kubectl apply -f longhorn-middlewares.yml
```
```bash
vim longhorn/longhorn-ingress.yaml
```
```
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: longhorn-ingress
namespace: longhorn-system
annotations:
# Connect the middlewares defined in step 2
traefik.ingress.kubernetes.io/router.middlewares:
longhorn-system-longhorn-auth@kubernetescrd,
longhorn-system-longhorn-buffering@kubernetescrd
spec:
ingressClassName: traefik
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: longhorn-frontend
port:
number: 80
```
```bash
kubectl -n longhorn-system get pod
kubectl get storageclass
```
```
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
local-path (default) rancher.io/local-path Delete WaitForFirstConsumer false 93m
longhorn (default) driver.longhorn.io Delete Immediate true 59m
longhorn-static driver.longhorn.io Delete Immediate true 59m
```
##### Unset default for "local-path" (emmc)
```bash
kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
```
##### Mark longhorn as "default"
```bash
kubectl patch storageclass longhorn -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
```
##### Apply ingress
```bash
kubectl -n longhorn-system apply -f longhorn/longhorn-ingress.yaml
kubectl -n longhorn-system get ingress
```
+110 -77
View File
@@ -55,7 +55,7 @@
gzip
minimum_length 1024
}
root * /mnt/ssd/www/comics
root * /mnt/data/www/comics
file_server
}
@@ -83,7 +83,7 @@ books.delmar.bzh {
gzip
minimum_length 1024
}
reverse_proxy carlo:10801
reverse_proxy krabs:10801
}
borg.delmar.bzh {
@@ -92,7 +92,7 @@ borg.delmar.bzh {
gzip
minimum_length 1024
}
reverse_proxy patrick:8080
reverse_proxy carlo:8081
}
cap.delmar.bzh {
@@ -154,40 +154,13 @@ cloud.delmar.bzh:8443 {
}
}
cnvrt.delmar.bzh {
design.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy bob:32770
}
crbn.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy bob:4000
}
cs.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy patrick:49505
}
dev.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy patrick:19080
reverse_proxy patrick:8080
}
dia.delmar.bzh {
@@ -208,6 +181,28 @@ draw.delmar.bzh {
reverse_proxy carlo:24928
}
events.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy patrick:8080 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
}
freecad.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy patrick:3935
}
gen.delmar.bzh {
encode {
zstd
@@ -235,6 +230,15 @@ gotify.delmar.bzh {
reverse_proxy carlo:41901
}
hmr.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy bob:39084
}
homepage.delmar.bzh {
encode {
zstd
@@ -290,7 +294,7 @@ jellyfin.delmar.bzh {
gzip
minimum_length 1024
}
reverse_proxy patrick:8096
reverse_proxy carlo:8096
}
jellyseerr.delmar.bzh {
@@ -299,7 +303,7 @@ jellyseerr.delmar.bzh {
gzip
minimum_length 1024
}
reverse_proxy patrick:5055
reverse_proxy carlo:5055
}
kontadenn.delmar.bzh {
@@ -308,7 +312,7 @@ kontadenn.delmar.bzh {
gzip
minimum_length 1024
}
root * /mnt/ssd/www/kontadenn
root * /mnt/data/www/kontadenn
file_server
handle_errors {
@@ -329,22 +333,13 @@ lnk.delmar.bzh {
reverse_proxy bob:3000
}
lud.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy carlo:3002
}
mmgr.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy patrick:38274
reverse_proxy carlo:38274
}
nds.delmar.bzh {
@@ -353,7 +348,7 @@ nds.delmar.bzh {
gzip
minimum_length 1024
}
root * /mnt/ssd/www/nds
root * /mnt/data/www/nds
file_server
handle_errors {
@@ -371,7 +366,7 @@ nsns.delmar.bzh {
gzip
minimum_length 1024
}
root * /mnt/ssd/www/nsns
root * /mnt/data/www/nsns
file_server
handle_errors {
@@ -383,6 +378,15 @@ nsns.delmar.bzh {
}
}
oec.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy carlo:32768
}
octoprint.delmar.bzh {
encode {
zstd
@@ -403,15 +407,6 @@ paperless.delmar.bzh {
reverse_proxy bob:8000
}
pdf.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy bob:16080
}
penpot.delmar.bzh {
encode {
zstd
@@ -421,16 +416,6 @@ penpot.delmar.bzh {
reverse_proxy bob:43735
}
pip.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
root * /mnt/ssd/www/pip
file_server
}
search.delmar.bzh
encode {
zstd
@@ -499,8 +484,28 @@ shop.delmar.bzh {
gzip
minimum_length 1024
}
root * /mnt/ssd/www/shop
file_server
reverse_proxy carlo:8090
}
sketch.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy patrick:3001
basic_auth / {
admin $2a$14$Z5n.aZ3DVnl.DjE9h2WP4OcR21tROpN1dyv8hFxGU3AEbdcOssUKi
}
}
slicer.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy patrick:3937
}
smk.delmar.bzh {
@@ -509,7 +514,16 @@ smk.delmar.bzh {
gzip
minimum_length 1024
}
reverse_proxy carlo:10802
reverse_proxy krabs:10802
}
snot.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy carlo:1349
}
stream.delmar.bzh {
@@ -524,13 +538,22 @@ stream.delmar.bzh {
}
}
swpt.delmar.bzh {
timesheet.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy 192.168.1.21:888
reverse_proxy patrick:44796
}
tournoi.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy patrick:42606
}
tpml.delmar.bzh {
@@ -539,7 +562,7 @@ tpml.delmar.bzh {
gzip
minimum_length 1024
}
root * /mnt/ssd/www/tpml
root * /mnt/data/www/tpml
file_server
handle_errors {
@@ -560,6 +583,15 @@ trek.delmar.bzh {
reverse_proxy carlo:32776
}
trfk.delmar.bzh {
encode {
zstd
gzip
minimum_length 1024
}
reverse_proxy bikinibottom:9000
}
trmx.delmar.bzh {
encode {
zstd
@@ -592,7 +624,8 @@ ugo.delmar.bzh {
gzip
minimum_length 1024
}
reverse_proxy carlo:8090
root * /mnt/data/www/shop
file_server
}
vault.delmar.bzh {
@@ -610,7 +643,7 @@ wizarr.delmar.bzh {
gzip
minimum_length 1024
}
reverse_proxy patrick:5690
reverse_proxy carlo:5690
}
www.delmar.bzh {
@@ -619,11 +652,11 @@ www.delmar.bzh {
gzip
minimum_length 1024
}
root * /mnt/ssd/www/comics
root * /mnt/data/www/comics
file_server
handle_path /julien/* {
root * /mnt/ssd/www/resumes/julien
root * /mnt/data/www/resumes/julien
}
redir /julien /julien/
@@ -652,5 +685,5 @@ zik.delmar.bzh {
gzip
minimum_length 1024
}
reverse_proxy patrick:4533
reverse_proxy carlo:4533
}
+13 -10
View File
@@ -21,7 +21,7 @@ curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-xcaddy-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-xcaddy.list
sudo apt update && sudo apt install -y caddy xcaddy
```
#### Build with dns-ovh
@@ -33,10 +33,9 @@ sudo apt update && sudo apt install -y caddy xcaddy
```bash
wget https://go.dev/dl/go1.26.4.linux-arm64.tar.gz
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.26.4.linux-arm64.tar.gz
export PATH=$PATH:/usr/local/go/bin
```
```bash
export PATH=$PATH:/usr/local/go/bin
mkdir ~/caddy && cd caddy
xcaddy build --with github.com/caddy-dns/ovh \
@@ -44,13 +43,17 @@ xcaddy build --with github.com/caddy-dns/ovh \
--with github.com/mholt/caddy-l4/modules/l4tls \
--with github.com/mholt/caddy-l4/modules/l4proxyprotocol
sudo mv caddy /usr/bin
sudo chown root:root /usr/bin/caddy
sudo chmod 755 /usr/bin/caddy
sudo systemctl daemon-reload
```
# sudo mv caddy /usr/bin
# sudo chown root:root /usr/bin/caddy
# sudo chmod 755 /usr/bin/caddy
# sudo systemctl daemon-reload
sudo dpkg-divert --divert /usr/bin/caddy.default --rename /usr/bin/caddy
sudo mv ./caddy /usr/bin/caddy.custom
sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.default 10
sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.custom 50
sudo systemctl restart caddy
```bash
sudo vim /etc/caddy/Caddyfile
```
+2 -2
View File
@@ -3,8 +3,8 @@
### On compute module :
```bash
mkdir -p /mnt/ssd/docker/data
mkdir -p /mnt/ssd/docker/compose
mkdir -p /mnt/<ssd>/docker/data
mkdir -p /mnt/<ssd>/docker/compose
```
```