Proxmox memoárok: AdGuard Home és Unbound költöztetés

Proxmox memoárokFolytatom a "saját" bejegyzések generálását. A jegyzettömbél jobb és hátha másnak is segít...

Proxmox memoárok

Folytatom a "saját" bejegyzések generálását. A jegyzettömbnél jobb és hátha másnak is segít -legalább ötlet szinten. Előre szólok, hogy itt tömény CLI lesz, tele parancsokkal.

A mai feladat már várt rám nagyon rég... Proxmox helper scripts-ből telepített AdGuard Home költöztetése új LXC-be. A forrás LXC valaha Debian 12 volt, majd frissítve lett Debian 13 Trixie-re és kapott egy lakótársat is: az Unbound rekurzív DNS feloldót.

A történet annyi, hogy az otthoni hálózaton OpenWRT végzi a router és tűzfal feladatokat, DNS kéréseket küldi az AdGuard Home-nak, ami a szűrést végzi (reklámok, webhelyek, stb...), ami küldi a kérést az Unbound-nak, ahol a tényleges névfeloldás és cache a feladat. Miért nem az AGH a DNS resolver,
vagy miért nem az Unbound szűr? Miért nem OpenWrt-n belül és hasonló kérdések megválaszolása nem képezi a cikk tárgyát, kommentekben vagy a topikban kitérhetünk rá.

AI segített, elakadásnál továbbra is ajánlom a Claude/Gemini gondolkodó/Qwen AI megkérdezését. Ha nagyon rohannak vagy elkanyarodnak a feladattól, gyanús irányba menne a kapott bash utasítás, akkor másik AI-t is kérdezni kell - az a biztos.

Elvileg ebben a bemutatóban (leírás, memoár?) nincs veszélyes "beavatkozás", de ajánlott az LXC-k, VM-ek mentése. OK, az FSTAB piszkálása az tudna bajt okozni... ha ott hibázunk (valamit átírunk vagy törlünk),
akkor mentés nélkül lépjünk ki és kezdjük újra inkább a szerkesztését.

Hirdetés

Tehát a jó öreg Debian, 1,5 GB lemezmérettel, mert hely az van. Kezdeti állapot 863 MB-ról indult, mindenféle trükkökkel (felesleges csomagok, nyelvi fájlok és man törlése, journal csökkentése, stb.) próbáltam a méretet redukálni. Álljanak itt azért a parancsok, hátha még szükség lesz rá (a kód formázás nagyon beteges, monospace lett inkább):

1. Csomagkezelő ürítése
apt-get autoremove --purge -y
apt-get clean

2. Nyelvi fájlok és dokumentáció
apt-get install localepurge -y
# Válaszd ki: en_US.UTF-8 és hu_HU.UTF-8, a többi mehet a levesbe
localepurge

3. Manuálok és doksik törlése
rm -rf /usr/share/doc/*
rm -rf /usr/share/man/*

4. Journal logok korlátozása
journalctl --vacuum-time=1d

nano /etc/systemd/journald.conf
Itt átírni a következőket (# is törölni kell a sor elején):
SystemMaxUse=50M
RuntimeMaxUse=50M

Ezután a szolgáltatást újraindítjuk:
systemctl restart systemd-journald

A legnagyobb mappák listázása a meghajtón
du -sh /* 2>/dev/null | sort -h

Végül 690 MB lett a vége. Köszi systemd... Ez nem az a méret, amit terveztem.
Tehát jöhet a B terv: Alpine linux.


kép: Github

Alpine LXC

Mivel jár ez? A Debian/Ubuntu LXC-ket egy script frissítette, sok dolgom nem volt vele. Alpine-ra átírni... hááát... ezt buktam. Hátrány, hogy az Alpine-t nem ismerem, de a Debian-t sem kellett zaklatnom. Ha be vannak állítva, akkor az ilyen egyszerű LXC-k működnek. Ha van mentés, akkor meg a frissítéstől sem kell félni... ugye?

Proxmox, konzolban adjuk ki a pveam update parancsot, ezzel frissül a Template listánk. A webui-n menjünk
a template-okat tartalmazó tárhelyre, középen katt a CT Template-ra, fent pedig a Templates-ra és keressük meg a legfrissebb Alpine-t, letöltés.

Ezután PVE webui-n create CT, azaz hozzuk létre az Alpine LXC-t. Nálam kapott 2 core-t (nem használja ki, ahogy az 512M RAM-ot sem). Ezeket lehet utólag is módosítani, ahogy szükséges. A disk maga a kérdés, ezt PVE alatt csak növelni lehet könnyedén, csökkenteni már jóval macerásabb...
Annyira, hogy a reinstall általában a gyorsabb opció.

Ezért a disk méretre adjuk 0.3 -at, amiből egy ca. 300 MB-os lemez lesz. Mint kiderült, az Alpine annyira szerény, hogy ez is óriási lett... De kell a hely a frissítéseknek, AGH logoknak és Unbound cache-nak is.
Pár hétig figyelem majd hogy alakul a mérete és ha sok hely marad, akkor újra elkészítem 0.2 GB lemezmérettel. Egyelőre itt el fog férni biztosan:

A további beállításokat nem írtam, pl. unprivileged megfelel, kell neki IP cím (lehetőleg ne ütközön semmivel,
a hálózat rész csak ennyi egyelőre). Indítsuk el, konzolba be (Alpine LXC-n) és barátkozzunk össze vele, kezdjük a frissítéssel:
apk update && apk upgrade

Kell még néhány apróság:
apk add curl wget

Töltsük le az AdGuard Home-t:
mkdir -p /opt/AdGuardHome

wget https://static.adguard.com/adguardhome/release/AdGuardHome_linux_amd64.tar.gz
tar xvf AdGuardHome_linux_amd64.tar.gz -C /opt

*****
A kód formázás nem túl jó. Fórumtárs javaslatára monospace lett végül a kód helyett. Ez sem tökéletes, a sorok lezárása "windows-os", erre néhol a Linux érzékeny. Ahol több soros blokkban van kód, azt másold ki egy jegyzettömbbe, töröld az extra üres sorokat, ctrl+a, ctrl+c és terminálban jobb klikk, beillesztés egyszerű szövegként. Átnéztem, de ne legyen ebből gond.
*****

Systemd itt nincs, init van. Kell egy script (és a Claude AI segítsége), ami indítja majd az AGH-t:
nano /etc/init.d/adguardhome

Elvileg ez egy új file, másoljuk bele ezt:
#!/sbin/openrc-run
name="adguardhome"
command="/opt/AdGuardHome/AdGuardHome"
command_args="-s run"
pidfile="/run/${RC_SVCNAME}.pid"
background=yes
depend() {
need net
}

Mentsük el és kapjon jogokat:
chmod +x /etc/init.d/adguardhome

Legyen autostart is:
rc-update add adguardhome default

Ez a része kész, teszteljük:
rc-service adguardhome start
A böngészőben a http://Alpine_LXC_IP:3000 porton kellene az első indításos AGH-nak fogadnia.
Ha ez megtörtént, akkor itt ne harcoljunk tovább, állítsuk le: rc-service adguardhome stop

Jöhet az Unbound telepítése és autostart-hoz adása:
apk add unbound
rc-update add unbound default

Ezzel egyelőre készen vagyunk, irány a régi LXC: hozzuk át az AGH és Unbound beállításainkat.
Az AGH viszonylag egyszerű, vagy SSH-n vagy konzolban navigáljunk az /opt/AdGuardHome mappába (régebben mintha máshol lett volna a yaml file, de nem vennék rá mérget). Innen nekünk csak a yaml kell, illetve a data mappa, ha a statisztikákat is át szeretnénk vinni. A gyorsabb utat választottam, az eredeti yaml tartalmát kimásoltam egy txt-be, majd az Alpine LXC-ben létrehoztam a fájlt:
nano /opt/AdGuardHome/AdGuardHome.yaml
bemásoltam a korábbi tartalmát, mentés, kész.


kép: nlnetlabs.nl

Az Unbound már kicsit macerásabb, itt sokkal több a mentenivaló, szerencsére az AI segítségével ez is megoldódott. Első lépésben az Unbound mappánk beállításait csomagoljuk be, mindenestül a régi LXC-ben:
tar -czvf /root/unbound_backup.tar.gz /etc/unbound/

A parancs a csomagot a /root könyvtárba rakta, a régi AGH LXC-n ezzel végeztünk is.
Irány a Proxmox konzol, csináljuk amit az AI javasolt:
Húzd ki a fájlt a Debianból a hostra:
pct pull 112 /root/unbound_backup.tar.gz /tmp/unbound_backup.tar.gz
Told be a fájlt a hostról az Alpine-ba:
pct push 113 /tmp/unbound_backup.tar.gz /root/unbound_backup.tar.gz

Természetesen az ID-k mások lesznek/lehetnek Nálad, nálam 112 a régi LXC és 113 az új. Ugorjunk ismét az Alpine LXC konzolba és csomagoljuk ki a mappánkat:
cd /root
tar -xzvf unbound_backup.tar.gz
Majd a megjelenő ETC mappát rakjuk a helyére:
cp -r etc/unbound/* /etc/unbound/
Ha nincs hiba, akkor a cd /etc/unbound parancsra az importált beállításainkat találjuk. Térjünk vissza a /root könyvtárba, itt a tömörített és a kicsomagolt etc könyvtár is törölhető.

Az Alpine-on az Unbound felhasználónak hozzáférést kell kapnia a fájlokhoz, különben nem fog elindulni:
chown -R unbound:unbound /etc/unbound

Ezután egy gyors önteszt:
unbound-checkconf
Ha azt írja, hogy "no errors", akkor indítsd el:
rc-update add unbound default
rc-service unbound start

Nálam fatal volt:
unbound-checkconf
/var/lib/unbound/root.key: No such file or directory

Nem gond, kellett egy root key a bódottához:
Mappa létrehozása (ha nincs)
mkdir -p /var/lib/unbound

Kulcs generálása
unbound-anchor -a /var/lib/unbound/root.key

Jogosultság beállítása
chown unbound:unbound /var/lib/unbound/root.key

Ennél a pontnál még egyszer ellenőrizzük, hogy indul-e automatikusan majd minden:
rc-status default

Itt látnod kell mindkettőt:
adguardhome [ started ] és unbound [ started ]

### Még egy (opcionális, kihagyható) apróság:
Mobilnetünk van, nem túl acélos sebességgel, tehát minden bit érték... Normális le/fel sebességnél erre nincs szükség.
Unbound a DNS cache-t ramban tartja, ami azzal jár, hogy az LXC minden újraindításakor üres a cache. Ezt részben kezeli, hogy az AGH-n belül is van egy kis méretű cache, de az csak a leggyakoribb lekérdezésekre elég és rövid ideig tárolja. Jobb, ha időzítve, pl. óránként mentjük az Unbound cache-t és restartnál az utolsót visszatöltjük.

Alpine konzolban crontab -e
Sajnos itt vi a szerkesztő, amit nehéz kedvelni... szerintem nem is lehet. Valahogy az utolsó sor alá szúrjuk be:
0 * * * * unbound-control dump_cache > /var/lib/unbound/cache.dump
Elsőre mindig hibásan szúrja be, az eleje lemarad. Fura. Kilépéshez és mentéshez esc egyszer, majd shift ZZ. Ezzel óránkénti cache mentésünk már lesz. Kell egy script, ami az Unbound indulása után fut le (tehát LXC vagy Unbound service restartnál is), ellenőrzi, hogy az Unbound elindult (ha nincs kész, akkor nem lehet visszatölteni). Ha minden OK, akkor DNS dump visszatölt, kész. Ha nem OK, akkor pár próba után elengedi a feladatot és kilép.

Jöhetnek a megjegyzések: DNS cache lejár: igen, optimistic van, lejártat is kiszolgálja, ami 98%-ban teljesen jó. Minek, ha újraépül: mert a DNS feloldás így kb. mindig ugyan olyan gyors (gyakori oldalakra), mert mobilnet és mert ez a tuning akkor is jó, ha csak placebo hatása van...

Alpine konzolba:
nano /usr/local/bin/unbound-cache-load.sh
Ezt másoljuk bele:
#!/bin/sh
CACHE_FILE="/var/lib/unbound/cache.dump"
LOG="/var/log/unbound-cache.log"
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG"; }
[ ! -f "$CACHE_FILE" ] && { log "Nincs cache fájl, kihagyva."; exit 0; }
RETRIES=5
WAIT=3
for i in $(seq 1 $RETRIES); do
if unbound-control status >/dev/null 2>&1; then
log "Unbound fut, cache visszatöltés..."
if unbound-control load_cache < "$CACHE_FILE" 2>> "$LOG"; then
log "Cache visszatöltve."
else
log "load_cache sikertelen."
fi
exit 0
fi
log "Unbound még nem fut ($i/$RETRIES), várakozás ${WAIT}s..."
sleep $WAIT
done
log "Unbound nem indult el $((RETRIES * WAIT))s alatt. Cache nincs visszatöltve."
exit 0

Mentsük el és készítsük el a service-t is:
nano /etc/init.d/unbound-cache-load
Ez lesz a tartalma:
#!/sbin/openrc-run
description="Unbound DNS cache visszatöltése induláskor"
depend() {
after unbound
}
start() {
ebegin "Unbound cache visszatöltése"
/usr/local/bin/unbound-cache-load.sh
eend $?
}
stop() {
return 0
}

Kellenek jogosultságok is:
chmod +x /usr/local/bin/unbound-cache-load.sh
chmod +x /etc/init.d/unbound-cache-load
rc-update add unbound-cache-load default

Unbound-ot is fel kell erre készíteni:
nano /etc/unbound/unbound.conf.d/remote-control.conf
Itt a remote-control: control-enable: yes kell legyen.
Ellenőrzéshez adjunk neki időt... nézzük meg, van-e dump fájlunk:
cd /var/lib/unbound/
ls
Itt kell lennie egy cache.dump nevű fájlnak. Ha van, akkor a crontab-os dump működik.
Visszatöltés tesztelése: nézzük meg, van-e log file:
nano /var/log/unbound-cache.log
Ha van, akkor látjuk, hogy mi történt. Ha nincs, akkor manuálisan indítsuk a dump visszatöltést:
rc-service unbound-cache-load start

Ha hibákat dob, akkor lehet keresni az okot. Nálam a sortörésnél a láthatatlan karakterek okoztak bajt, ezért is írtam a bevezetőbe a kiegészítést a kód formázásról.
###

OK, állítsuk le a régi, Debian LXC-t és az új, Alpine alapút is. Proxmox webUI-n a Debian LXC network részén másoljuk ki a mac address-t, erre cseréljük az Alpine LXC mac addressét. Ne felejtsük el az IP címeket is megcserélni, a Debian-t vegyük ki az autostartból, Alpine-nál kapcsoljuk be a "start at boot"-ot.
A módosítással az Alpine LXC indulásakor nem fog feltűnni a csere a routernek, ha mac+IP kombóval használtuk.

Ezzel a rendszerváltás kész, lehet pezsgőzni...


stockcake.com celebration-champagne-burst free to use

Ha esetleg nem volt elég a parancssorból, akkor lapozz és kiderül, hogy miért ez a megabájt-vadászat...
Csak erős idegzetűeknek, az irgalmatlan mennyiségű konzol használat miatt! :)

Ramdisk: OpenWRT és AGH

Rövid kitérő az Openwrt-re is, tényleg csak pár mondatban. Nemrég váltottam le az Opnsense tűzfalat OpenWRT-re. Más a két rendszer, itthonra az Opnsense overkill és az OpenWRT Smart Queue Management-re szükségem van a mobilnet miatt. Nem elhanyagolható, hogy az OpenWRT minimális erőforrásal beéri. Mérete is szerény, alap telepítéssel 124 MB és még frissíteni is tudja a csomagokat.
OK, a Tailscale elsőre megakadt a torkán a 65 MB-os "ápgréddel" (erre is van több megoldás, de nem térek el a témától...ugye?).

Proxmoxon a korábbi cikkben leírt módon hozzunk létre egy Immutable (nem módosítható) mappát:
mkdir /mnt/ramdisk
chmod 777 /mnt/ramdisk/
chown nobody:nogroup /mnt/ramdisk/
chattr +i /mnt/ramdisk/
lsattr -d /mnt/ramdisk/

----i---------e------- /mnt/ramdisk/ - ha ezt látjuk, akkor jó.

A mappa alap esetben nem írható, csak akkor, ha csatolunk bele valamit (ami írható...).
Ehhez az FSTAB-ot használjuk:
nano /etc/fstab
A végére ugráljunk le és szúrjuk be ezt a két sort:
# RAMDISK
tmpfs /mnt/ramdisk tmpfs defaults,noatime,nosuid,nodev,size=500M 0 0

Kb. ez az egyetlen rész a jelen írásban, ahol maradandó kárt tudunk tenni a rendszerünkben,
ezért itt az "egysoros" parancs, ami az fstab végére bepattintja a ramdisk-et:
echo -e "\n# RAMDISK\ntmpfs /mnt/ramdisk tmpfs defaults,noatime,nosuid,nodev,size=500M 0 0" | sudo tee -a /etc/fstab

Mentés és systemctl daemon-reload kell, hogy a PVE lássa is a módosítást, majd egy mount -a parancs és elvileg kész is a ramdisk, teszteljük:
mkdir /mnt/ramdisk/teszt
cd /mnt/ramdisk/teszt

Ez létrehozott egy mappát a ramdisken. Ha nem volt hiba és mindent jól csináltunk,
akkor törölhetjük a teszt mappánkat:
cd /root
rm -r /mnt/ramdisk/teszt

Mindjárt itt a vége, még pár ezer parancs és kész, nyugi!
A következő hőstett a Proxmox webUI-n a Datacenter, storage menüben lesz:

Add directory a lenyílóban és adjuk meg a ramdisk mappa elérését (/mnt/ramdisk), adjunk neki valami fancy nevet, lehet pl. ramdisk. A content (tartalom) résznél válasszuk ki a disk image-t és container-t. Kész.

Ugorjunk vissza a node-ra (PVE nálam), jelöljük ki az LXC-t és állítsuk le. A resources résznél kattintsunk
a root disk-re, ami a konténerünk "merevlemeze". Felette így aktív lesz a volume action legördülő menü, amiben válasszuk a move storage (tároló átmozgatása) lehetőséget:

Innen már egyenes az út, target storage a ramdisk, delete source (forrás törlése) jelölőbe egy pipa és kész. Indulhat az LXC, most már a ramdiskről. Az OpenWRT esetében is hasonló az eljárás, annyi eltéréssel,
hogy itt volume action helyett disk action a fenti menüpont neve. Kész...

Majdnem kész... :) A ramdisknek hátránya, hogy ha a gép leáll, akkor a tartalma az hussss... és annyi. Ha az (áram) hálózat nem stabil, akkor UPS ajánlott (igazán minden PC-nél az...). A változások is a ramdiskbe mentődnek, pl. ha frissítjük az openWRT-t, egy Proxmox reboot után ismét frissítenünk kellene...

Ezért a rendszeres mentések mellett kell egy mentés a Proxmox leállításakor is. Másik probléma a boot: a ramdisk létrejön, csatolja és... üres. Erre is kell egy script, ami helyreállítja a legfrissebb mentést a ramdisk-re és elindítja azt.

Claude és Qwen3 AI-al készítettük el, az adatokat és a feltételeket én adtam, a két scriptet és a két systemd service-t "cross reference" és "Peer Review Loop" a két AI legózta össze.

Ha pontosan megadjuk mi a terv, mi és hol található, akkor hibátlanul megírja az ilyen és hasonló scripteket bármelyik AI. Legalábbis azt hiszi mindegyik. De amint másik AI-al is összevetjük, kiderülnek apró hibák, amik jó esetben csak ezt a scriptet kaszálják el. Ezért érdemes másod vagy akár harmad véleményt is kérni. CGPT (free) itt is elhasalt, Gemini gondolkodót is inkább nem script jellegű feladatra tartom jobbnak.

Sokat próbálgattuk a "szabványos" utat: leálláskor VM/LXC stop, backup. Induláskor legutolsó mentést megkeres, helyreállít... Nehézkes. A leállásnál már sok szolgáltatást lelő a PVE, mire a mentést kezdené.
A szabályos mentés is viszonylag sok idő, a kis méret ellenére.

Ezért inkább csalunk. ;)
Leállításkor -a lehető legkorábban- a ramdisken lévő VM/LXC megállítjuk, rsync egy SSD-re és ennyi. A visszatöltése is sokkal egyszerűbb, gyorsabb. A lényeg, hogy még az előtt a helyükre kerüljenek a mappák és a lemezek, mielőtt a PVE a guest rendszereket indítaná.

Első, hogy Proxmox újraindításakor a legfrissebb mentéseket töltse a ramdiskbe.
nano /usr/local/bin/ramdisk-restore.sh
Ez egy új file, másoljuk bele ezt (Neked át kellhet írni itt-ott természetesen, ha mások voltak a csatolási pontok vagy a VM ID-k):

#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

RAMDISK="/mnt/ramdisk/images"
CACHE_DIR="/mnt/ssd/ramdisk_cache"
LOG="/root/ramdisk.log"
ERR="/root/ramdisk.error.log"

log() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] RESTORE: $*"
echo "$msg" >> "$LOG"
}
err() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $*"
echo "$msg" >> "$ERR"
echo "$msg" >> "$LOG"
}

log "=== Visszaállítás indítása (Boot) ==="

# 1. Mount ellenőrzés
for mnt in "/mnt/ssd" "/mnt/ramdisk"; do
if ! mountpoint -q "$mnt"; then
err "$mnt nincs csatolva. Kilépés."
exit 1
fi
done

# Storage aktiválás ha szükséges
if ! pvesm status 2>/dev/null | grep -q "^ramdisk"; then
log "Ramdisk storage aktiválása..."
pvesm set ramdisk --disable 0 >> "$LOG" 2>> "$ERR"
fi

# 2. Ramdisk célmappa biztosítása
mkdir -p "$RAMDISK"

# 3. Adatok visszatöltése az SSD-ről
if [ -d "$CACHE_DIR" ] && [ "$(ls -A "$CACHE_DIR" 2>/dev/null)" ]; then
log "Gyorsítótár megtalálva, visszatöltés..."
if rsync -a --sparse "$CACHE_DIR/" "$RAMDISK/" >> "$LOG" 2>> "$ERR"; then
log "Adatok visszamásolva a RAM-ba."
else
err "Rsync SIKERTELEN."
exit 1
fi
else
err "Nincs adat az SSD gyorsítótárban ($CACHE_DIR) – első indítás?"
exit 1
fi

log "=== Visszaállítás kész, pve-guests indítja a guest-eket ==="

A script ellenőrzi, hogy az fstab csatolások létrejöttek-e, illetve ha nem aktív a tárhely, akkor bekapcsolja. Ezután az rsync mentéseket megkeresi, ha talál, akkor helyreállítja a ramdisk-re.

Fontos, hogy hiba esetén ne akadjon fel a rendszer, ezért a legrosszabb esetben csak kilép, helyreállítás nélkül. Ilyenkor manuálisan kell beavatkozni, pl. ha nem jött létre a ramdisk, akkor másik tárolóra kell helyreállítani. Igen, lehetett volna benne fallback restore az NVME tárhelyre is, de ehhhh... ne bonyolítsuk.
Ha nincs ramdisk, vagy más okból nem áll helyre, akkor ott mindenképp log olvasás lesz a vége. Ebben segít a root könyvtárba mentett ramdisk.log és a ramdisk.error.log fájl, nem kell journal-t is olvasgatni (jó esetben).

Ilyen kritikus hibánál érdemes a Proxmox által mentett VM-et és LXC-t visszaállítani inkább. Nálam napi VM+LXC mentés van, minden hajnalban (ajánlom másnak is). Ezért ha valami nem sikerül, akkor a helyreállítással maximum az aznapi frissítések és módosítások vesznek el. Egyik sem kritikus, frissítéseket leszedik újra, módosítani jó esetben ritkán kell a router beállításokon. Praktikus tanács, hogy nagyobb "beavatkozás" előtt és után is mentsük. És ennek semmi köze a ramdiskhez, csak hasznos szokás.

A következő script a Proxmox leállításakor menti a ramdiskből a virtuális gépek "merevlemezét". Itt is fontos, hogy ne legyen blokkoló hatása a leállításra. Nézzünk egy "worst case"-t: nem ment és a ramunk huss... Induláskor így egy korábbi lemez másolatot találhat, ami nem biztos, hogy friss*.

Másik lehetőség, hogy a VM/LXC nem áll le. A mentés ilyenkor is lefut, de lehet, hogy "dirty state" lesz a lemez eredménye. Ebből 99%-ban helyreáll és nem probléma, a fennmaradó 1%-ra ott a Proxmox napi mentés. A scriptbe nem került semmi ennek a kezelésére (pedig ötleteim vannak :) ), mert még nem fordult elő a már kb. két hetes használat alatt.

###
*Erre is van megoldás (opcionális, kihagyható): crontab és egy script, ami hajnalban a PVE által vezényelt snapshot előtt leállítja a ramdiskben futó gépeket, menti a ramdisket és újraindítja a gépeket. A holtidő kb egy perc, de ezzel akkor is lesz egy viszonylag friss mentés a ramdisk mentésekben, ha a leállításkor a mentés nem jön össze. Email értesítőt is be lehet állítani, ha sikertelen, akkor időben tudunk róla és lehet intézkedni.
Proxmox konzolba be és először az időzítést adjuk meg:
crontab -e
Majd a végére szúrjuk be (lentebb van ebből egy másik verzió is):
# RAMDISK napi mentése
30 3 * * * /usr/local/bin/ramdisk-daily.sh
Mentés. Ezzel minden hajnalban 3.30-kor végrehajt egy mentést.
Hozzuk is létre a scriptet:
nano /usr/local/bin/ramdisk-daily.sh
Új file, könnyű dolgunk lesz, mert csak meghívjuk a scriptet, ami leállításkor futna. Ha az végzett, akkor indítja őket és kész.
#!/bin/bash
# ramdisk-daily.sh
/usr/local/bin/ramdisk-backup.sh
# Ha a backup sikeres volt, indítjuk a gépeket
if [ $? -eq 0 ]; then
qm start 121 && log "VM 121 újraindítva."
pct start 113 && log "LXC 113 újraindítva."
else
log "Backup sikertelen, gépek nem indulnak."
fi

A fenti verzió csak log-ot ment. Az alábbi levelet is küld az eredményről. A gépek indítása után vár kicsit és pingel. Ha a ping nem hibával tér vissza, akkor elküldi a mail-t. Ha nincs net és lejár a próbálkozások száma, akkor log-ba írja a bánatát. Lehet a sleep nem a legprofibb, de itt jól működik.
#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LOG="/root/ramdisk.log"
DAILY_LOG="/root/ramdisk-daily.log"
ERR="/root/ramdisk.error.log"
MAIL_STATUS="Sikeres"
log() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] DAILY: $*"
echo "$msg" >> "$DAILY_LOG"
}
err() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $*"
echo "$msg" >> "$ERR"
echo "$msg" >> "$DAILY_LOG"
MAIL_STATUS="SIKERTELEN"
}
log "=== Napi sync indítása ==="
# 1. Backup futtatása
/usr/local/bin/ramdisk-backup.sh
if [ $? -eq 0 ]; then
# 2. VM 121 indítása
log "VM 121 indítása..."
if qm start 121; then
log "VM 121 fut."
else
err "VM 121 indítása sikertelen."
fi
# 3. LXC 113 indítása
log "LXC 113 indítása..."
if pct start 113; then
log "LXC 113 fut."
else
err "LXC 113 indítása sikertelen."
fi
else
err "Backup sikertelen, gépek nem indulnak."
fi
log "=== Napi sync kész ==="
# 4. Várakozás hálózatra
log "Várakozás hálózatra..."
sleep 5
NETWORK=0
for i in $(seq 1 12); do
ping -c1 -W2 8.8.8.8 >/dev/null 2>&1 && NETWORK=1 && break
sleep 5
done
# 5. Email küldés
if [ "$NETWORK" -eq 0 ]; then
log "Hálózat nem érhető el, email nem küldhető."
else
mail_body="Ramdisk napi sync: ${MAIL_STATUS}
--- Log ---
$(tail -n 15 "$LOG")"
echo -e "Subject: Ramdisk napi sync: ${MAIL_STATUS}\n\n${mail_body}" | /usr/libexec/proxmox-mail-forward
log "Email elküldve."
fi

###

Jöjjön a lemezeket mentő script:
nano /usr/local/bin/ramdisk-backup.sh

Ez is új, másoljuk bele:
#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

RAMDISK="/mnt/ramdisk/images"
CACHE_DIR="/mnt/ssd/ramdisk_cache"
LOG="/root/ramdisk.log"
ERR="/root/ramdisk.error.log"

log() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] SAVE: $*"
echo "$msg" >> "$LOG"
}
err() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $*"
echo "$msg" >> "$ERR"
echo "$msg" >> "$LOG"
}

log "=== Mentés indítása (Leállás) ==="

# 1. Szabad hely ellenőrzése az SSD-n (min. 2GB)
FREE_SSD=$(df -m /mnt/ssd | awk 'NR==2 {print $4}')
if [ "$FREE_SSD" -lt 2048 ]; then
err "Kevés a hely az SSD-n ($FREE_SSD MB). Mentés megszakítva!"
exit 1
fi

# 2. Vendéggépek leállítása (konzisztens fájlrendszer miatt)
log "VM 121 leállítása..."
if qm stop 121 --timeout 40; then
log "VM 121 leállt."
else
err "VM 121 leállítása sikertelen – rsync így is fut (dirty state)."
fi

log "LXC 113 leállítása..."
# pct stop nem támogatja a --timeout opciót, a timeout paranccsal oldjuk meg
if timeout 40 pct stop 113; then
log "LXC 113 leállt."
else
err "LXC 113 leállítása sikertelen – rsync így is fut (dirty state)."
fi

# 3. Célmappa létrehozása, ha még nem létezne
mkdir -p "$CACHE_DIR"

# 4. Adatok szinkronizálása
log "Rsync indítása: $RAMDISK -> $CACHE_DIR"
if rsync -a --sparse --delete "$RAMDISK/" "$CACHE_DIR/" >> "$LOG" 2>> "$ERR"; then
log "=== Mentés sikeresen befejeződött ==="
else
err "=== Rsync SIKERTELEN ==="
exit 1
fi

Már csak a systemd-nek kell megmondani, hogy a scripteket futtassa:
nano /etc/systemd/system/ramdisk-restore.service
Ez lesz a tartalma:
[Unit]
Description=Ramdisk restore - LXC 113 és VM 121
After=local-fs.target pve-cluster.service pvedaemon.service
Requires=pve-cluster.service pvedaemon.service
Before=pve-guests.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/ramdisk-restore.sh
[Install]
WantedBy=multi-user.target

A service a fenti helyreállító scriptet indítja el, miután a csatolások létrejöttek, de mielőtt a Proxmox elkezdené a "start at boot - yes" (Proxmox indulásakor elindítandó) jelölésű VM-eket és LXC-ket indítani. Mivel az AGH és az OpenWRT a hálózat alapja, nem lenne szerencsés őket pl. a NAS után indítani. A Home Assistant meg olyan, mint én: nem túl boldog, ha ébredéskor nincs net...

Még egy service kell a mentésnek is... mindjárt vége...
nano /etc/systemd/system/ramdisk-backup.service
Ez lesz a tartalma:
[Unit]
Description=Ramdisk backup - LXC 113 és VM 121
DefaultDependencies=no
# Leálláskor a systemd megfordítja a sorrendet:
# Előbb leállítja ezt a service-t (ExecStop), és CSAK UTÁNA a listában lévőket.
After=local-fs.target pve-cluster.service pvedaemon.service pve-guests.service
# Biztosítjuk, hogy a tényleges kikapcsolás előtt végezzen
Before=umount.target shutdown.target reboot.target halt.target

[Service]
Type=oneshot
# Indításkor nem csinál semmit, csak "él"
ExecStart=/bin/true
# Itt történik a varázslat leálláskor
ExecStop=/usr/local/bin/ramdisk-backup.sh
# Ez a kulcs: a service "aktív" marad az indítás után
RemainAfterExit=yes
# Adjunk elég időt a mentésnek (5 perc)
TimeoutStopSec=300

[Install]
# Normál indításkor aktiválódjon
WantedBy=multi-user.target

Itt van egy kis timeout (várakozás). Érdemes tesztelni, hogy kb. hány másodperc a VM + LXC leállítás és a backup, azt az időt kicsit megnövelni és beírni timeout-nak. Ez amolyan "legrosszabb eset" jelenleg, még nem finomítgattam rajta. A service sorrendet itt is Claude és Qwen3 rakta össze közösen, mert nem mindegy, hogy mikor fut a script: pl. ha a mentésre használt tárhelyünk csatolása eltűnik, akkor nincs mentés és hasonló finomságok történhetnek.

Az új service-nek jogokat is kell adnunk és a futtatásukat engedélyezni kell:
chmod +x /usr/local/bin/ramdisk-restore.sh
chmod +x /usr/local/bin/ramdisk-daily.sh
chmod +x /usr/local/bin/ramdisk-backup.sh
systemctl daemon-reload
systemctl enable ramdisk-restore.service
systemctl enable ramdisk-backup.service

Teszteljük a napi mentést (vigyázat, a ramdiskben a gépeket leállíja!):
bash -x /usr/local/bin/ramdisk-daily.sh

Ha csak visszatölteni szeretnénk a ramdiskbe:
bash -x /usr/local/bin/ramdisk-restore.sh

Ha valamit később módosítunk, akkor újra kell tölteni a service-okat, hogy érvénybe lépjenek a módosítások:
systemctl daemon-reload && systemctl enable --now ramdisk-restore.service
systemctl daemon-reload && systemctl enable --now ramdisk-backup.service

Probléma esetén a /root könyvtárban vannak a logok, illetve a
journalctl -u ramdisk-restore.service -n 50 vagy journalctl -u ramdisk-backup.service -n 50
lehet az első diagnosztikai lépés. Ehhez kapcsolódik a logrotate: ha nem állítjuk be, akkor a log fájlunk csak növekszik... nem jó.
nano /etc/logrotate.d/ramdisk
Az utolsó három log elég szerintem, mail is jön, nem fogjuk nézegetni, ha nincs baj:
/root/ramdisk.log
/root/ramdisk-daily.log
/root/ramdisk.error.log {
daily
rotate 3
compress
missingok
notifempty
}

Mentés, bezárás. Innen a rendszer intézi már.

Azt hiszem ennyi volt. :)

Konklúzió

Megérte? Nincs egyértelmű válasz. Ha van elég ram a rendszerben, akkor szerintem érdemes kipróbálni. Nálam a felhasználás nem indokolja a ramdisk-et (nincs gigabites internetem, nem sokat töltünk le-fel, stb.). Régebben elpöntyögtek ezek SATA SSD-n is, nem volt gond. Élettartam sem redukálódik jelentősen, ahogy én használom... de akkor minek?

Ez egy homelab, aminek a lelke a hőstettek végrehajtása, problémák megoldása... Ha nincs, akkor generálunk egyet és megoldjuk. A lényeg a kísérletezés, tanulás. Az 500 MB RAM "feláldozása" nem vészes, gyakorlatilag még így is kevesebb a ram felhasználásom, mint Opnsense-vel volt. Ramdisken nem terhelik az NVME felé a kapcsolatot az apró, de folyamatos írás/olvasással. Szép kísérlet és megnyugtató, hogy mindent megtettem a sebesség maximalizálásáért (nem röhög, a fél mikroszekundum is idő). :)

Előnyök:
Latency: SATA SSD ~100 µs; NVME SSD ~10-20 µs; Ramdisk ~0,1-1 µs
IOPS (véletlen): SATA SSD ~90K; NVME SSD ~1M+; Ramdisk 10M+
Azonnali boot és restart: hiba esetén másodpercek alatt újraindul mindkét rendszer
Zero wear: SSD kímélve, nincs írás a DNS/query logoktól, cache-tól
Lehet csak placebo-hatás, de a Tailscale kapcsolat mintha előbb felépülne, távolról pl. Home Assistant gyorsabban tölt be


AI generált kép, notegpt.io

Biztonság:
az /mnt/ramdisk mappa alap esetben nem módosítható. Ha a ramdisk nem jön létre valamiért és nem működne az automatikus helyreállítás, akkor manuálisan az NVME-re helyreállítva a rendszer ismét percek alatt működőképes. Külön mentett error.log egyszerűsíti a hiba megtalálását. Ramdisk mérete fix, de az LXC és a VM mérete is, így nem tud "kifutni" a tárhelyből.

Alternatívák:
Alpine linuxnál a diskless mode-t is, nézegettem, de az LXC költöztetés egyszerűbbnek tűnt. Vannak megoldások a cache és logok "kiszervezésére" tmpfs-be (nálam a Proxmoxnak van egyébként tmpfs is beállítva), ez is macerásabb lett volna, mint a teljes rendszert a ramba átpattintani. Debian alapokon, nagy VM/LXC mérettel mást mutatna a matek, ott ez lehet a jobb megoldás. Ha kevés a ram, akkor sem érdemes a ramdiskre "herdálni", a swap jóval lassabb és ha a rendszer swappolni kezd, akkor jó eséllyel el is köszöntünk a ramdisk előnyétől...


ramdisk, by deep.ai

A váltás lényegét Claude AI is összefoglalta:
"SATA SSD solidan teljesít, de otthoni szerver esetén az állandó kis írások (logok, DNS cache, lease fájlok) lassan "koptatják" – és egy router vagy DNS szerver számára a ~100 µs latencia felesleges kompromisszum.

NVMe sebességben messze veri a SATA-t, de OpenWrt vagy AGH+Unbound alá kifejezetten pazarlás – ezek az alkalmazások nem tudják kihasználni az előnyeit, viszont ugyanúgy szenvednek a sok kis írástól.

Ramdisk esetén a képlet egyszerű: nincs "write-wearing", nincs latencia, a memória töredékét használja (500 MB a 32 GB-ből), és ezek az alkalmazások pont erre lettek tervezve – kis méret, ismert konfig. A reboot utáni automatikus visszaállítás pedig megoldható néhány sor systemd service-vel.

A tanulság: nem mindig a gyorsabb tároló a jobb választás, hanem az, amelyik illik az alkalmazás természetéhez."

Kérdés, észrevétel jöhet kommentbe -mint mindig. Köszönöm, hogy benéztél! :R