Det här sätter du upp
Den här guiden flyttar en app som är igång från en server du hyr någon annanstans till en ny server hos Melonslab. Du kopierar över allt medan den gamla servern fortsätter att arbeta, testar den nya servern under appens riktiga namn innan någon annan når den, och byter sedan i ett enda kort stopp: stoppa appen på den gamla servern, kopiera det som ändrats, starta den på den nya och peka om DNS till den nya adressen.
Exemplet är Plausible Analytics, uppsatt som i våra guider: rootless Podman med en användare per app, bakom Caddy. Samma steg flyttar alla appar som har sin data i filer och databaser på servern.
Varje steg nedan har körts mellan två VC-P Alloy hos Melonslab (2 vCPU, 8 GB) med Debian 13, där den ena spelade den gamla servern:
- Checklistan i steg 1 hittade varje tjänst, timer, container, volym, hemlighet och port på den gamla servern.
- Den första kopian, 1,2 GB medan Plausible var igång, tog 17 sekunder, och varje fil behöll sin ägare, även filerna som containrarna äger. När vi med flit ändrade användarens ID-intervall kunde Podman inte längre läsa databasen.
- Den nya servern svarade med samma certifikat från Let's Encrypt som den gamla innan DNS ändrades, och inloggningen i Plausible fungerade där, med alla webbplatser och besök.
- Båda databaserna återställdes på den nya servern från dumpar som togs medan den gamla var igång.
- Vid bytet gick Plausible inte att nå i 70 sekunder: 10 för att stoppa den, 5 för den sista kopian och 48 för att starta den, plus ett misstag i vårt eget skript.
- Inom fyra minuter efter DNS-ändringen gav Cloudflares och Googles publika resolvrar den nya adressen, och besök på testwebbplatsen räknades på den nya servern, med rätt land.
- När den gamla servern startades igen, som vid en återgång, var Plausible tillbaka efter 49 sekunder, med sin data som den var vid bytet.
Den nya servern använde lika mycket minne som den gamla, omkring 1,3 GB med Plausible och Caddy.
Innan du börjar
Du behöver:
- den gamla servern, med root-åtkomst över SSH med en nyckel;
- en ny server hos Melonslab med Debian 13, med minst lika mycket diskutrymme som den gamla använder. Välj ingen swap när du beställer den; om dina appar behöver swap, använd zram;
- tillgång till DNS-posterna för varje namn som den gamla servern svarar på;
- en lugn stund för bytet i steg 9.
Exemplen använder 192.0.2.50 och 2001:db8:50::a för den gamla servern, 203.0.113.10 och 2001:db8:10::a för den nya, och plausible.example.com och www.example.com som namn. Byt genomgående ut dem mot dina egna. Kommandona körs som root om inte steget säger något annat.
1. Inventera den gamla servern
Ta reda på vad den gamla servern gör innan du kopierar något. Kör det här som root på den gamla servern och spara utskriften:
# Users, and the user ID ranges their containers use
getent passwd | awk -F: '$3 >= 1000 && $3 < 65534 {print $1, $3, $6}'
cat /etc/subuid
# Users whose services start at boot
ls /var/lib/systemd/linger
# System services, timers and cron jobs
systemctl list-units --type=service --state=running --no-pager --no-legend
systemctl list-timers --no-pager --no-legend
ls /etc/cron.d /var/spool/cron/crontabs
# Each user's services, timers, containers, volumes and secrets
for u in $(ls /var/lib/systemd/linger); do
echo "== $u"
systemctl --user -M $u@ list-units --type=service,timer --state=active --no-pager --no-legend
systemd-run -M $u@ --user -qPG --wait sh -c 'podman ps -a --format "{{.Names}} {{.Image}}"; podman volume ls -q; podman secret ls --format "{{.Name}}"'
done
# Ports, firewall and kernel settings
ss -tulpn
ufw status
ls /etc/sysctl.d
# Where the data is
du -sh /home/* /srv /opt /var/lib/docker /var/lib/postgresql /var/lib/mysql 2>/dev/null
# Files that contain the old server's own addresses
grep -rIl -e 192.0.2.50 -e 2001:db8:50: /etc /home /srv 2>/dev/null
På vår gamla server visade det två användare, caddy (ID 1000) och plausible (1001), som båda startar vid uppstart; Caddy och Plausibles pod med fyra containrar, fyra volymer och tre hemligheter; Plausibles nattliga timer för säkerhetskopior; portarna 80 och 443 öppna mot internet och 8110 bara på 127.0.0.1; 63 MB under /home/caddy och 1,1 GB under /home/plausible. Den enda filen med serverns adress var dess nätverksinställningar, som stannar kvar. Om den gamla servern kör Docker visar docker ps -a och docker volume ls samma sak för Docker; vi har inte testat en flytt från Docker.
Skriv en kort lista utifrån utskriften:
- Vad som körs: varje tjänst och timer, och vilken användare som kör den.
- Var data finns: med rootless Podman ligger allt i användarnas hemkataloger: Quadlet-filerna, volymerna, avbilderna och Podmans hemligheter. Notera också allt utanför
/home. - Användare och ID-intervall: användarnamnen, deras ID och deras rader i
/etc/subuid. Steg 3 behöver dem. - Portar: de som står i
ufw status, för att öppna dem på den nya servern. - Namn: varje namn i Caddys inställningar (
grep -E '^[a-z0-9.-]+ \{' /home/caddy/Caddyfile). Vart och ett behöver nya DNS-poster i steg 9. - Certifikat: Caddy har dem i volymen
caddy-data, certbot i/etc/letsencrypt. - Hemligheter: lösenord och nycklar som måste följa med till den nya servern. Plausibles
SECRET_KEY_BASEär en sådan: utan samma värde slutar inloggningar och tvåfaktorskoder att fungera. Podmans hemligheter följer med användarens hemkatalog. - Inställningar utanför apparna: filer du har lagt till under
/etc, som/etc/sysctl.d/50-unprivileged-ports.conffrån Podman-guiden. Skapa dem för hand på den nya servern. Kopiera inte hela/etc: nätverksinställningarna, SSH-nycklarna och diskarnas uppställning hör till den gamla servern.
2. Sänk DNS-postens TTL i förväg
Varje DNS-post har en TTL, det antal sekunder som resolvrar, webbläsare och operativsystem får spara svaret. När du ändrar en post når en del besökare fortfarande den gamla adressen tills deras kopia har gått ut: med en TTL på 86400 upp till ett dygn.
Kontrollera din TTL från den nya servern:
apt install -y bind9-dnsutils
dig +noall +answer plausible.example.com A plausible.example.com AAAA
plausible.example.com. 3600 IN A 192.0.2.50
plausible.example.com. 3600 IN AAAA 2001:db8:50::a
Den andra kolumnen är TTL. Ställ in den på 300 sekunder, fem minuter, hos din DNS-leverantör, för varje namn på din lista. Gör det minst en gammal TTL före bytet, så att de långa kopiorna har gått ut till dess: med 3600 en timme före, med 86400 dagen före. Våra poster hade en TTL på 300, och publika resolvrar gav den nya adressen inom två till fyra minuter efter ändringen.
3. Förbered den nya servern
Sätt upp den nya servern på samma sätt som den gamla: säkra den först, och installera sedan, för en gammal server som vår, Podman som i steg 1 och 2 i Podman-guiden. Öppna samma portar som på den gamla servern, och installera rsync, som kopierar filerna. Det behövs på båda servrarna:
apt install -y rsync
Skapa användarna i samma ordning som på den gamla servern, och låt deras tjänster starta vid uppstart. Sätt inte upp något annat för dem: deras filer följer med i kopian.
for u in caddy plausible; do useradd -m -s /bin/bash $u; loginctl enable-linger $u; done
Varje användares containrar sparar sina filer under ett intervall av användar-ID som hör till den användaren, enligt /etc/subuid. Kopian behåller siffrorna, så ID och intervall måste vara desamma på båda servrarna. Kör det här på båda och jämför:
getent passwd caddy plausible | cut -d: -f1,3,4
grep -E '^(caddy|plausible):' /etc/subuid /etc/subgid
caddy:1000:1000
plausible:1001:1001
/etc/subuid:caddy:100000:65536
/etc/subuid:plausible:165536:65536
/etc/subgid:caddy:100000:65536
/etc/subgid:plausible:165536:65536
Debian delar ut ID och intervall i den ordning användarna skapas, så samma ordning ger samma siffror. Om de skiljer sig, till exempel för att den nya servern redan hade en annan användare, tar du bort de nya användarna igen med userdel -r, skapar dem med de gamla ID:na (useradd -u 1001 ...) och ändrar användarens rader i /etc/subuid och /etc/subgid så att de stämmer med den gamla servern, innan du kopierar. Om ett intervall krockar med en annan användares ändrar du den användarens intervall i stället. Vi testade vad som händer annars: med intervallet för plausible flyttat kunde Podman inte längre läsa databasens filer (steg 5 visar kontrollen).
4. Låt den nya servern logga in på den gamla
Kopieringen körs på den nya servern och hämtar filerna från den gamla över SSH, som root, så att den kan läsa varje fil och behålla varje ägare. Skapa en nyckel på den nya servern:
ssh-keygen -t ed25519 -N '' -C migration -f /root/.ssh/id_ed25519
cat /root/.ssh/id_ed25519.pub
Lägg till den raden sist i /root/.ssh/authorized_keys på den gamla servern. Sedan, från den nya servern:
ssh root@192.0.2.50 hostname
Första gången visar SSH den gamla serverns fingeravtryck. Jämför det med ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub på den gamla servern innan du svarar yes. Steg 10 tar bort nyckeln igen.
Om även din gamla server finns hos Melonslab, i samma nätverk som den nya, kan de två inte nå varandra förrän trafiken går via gatewayen: sätt först upp det på båda, som i guiden om att koppla ihop två servrar. Flyttar du från en annan leverantör behövs det inte.
5. Kopiera allt en gång medan det är igång
Som root på den nya servern:
rsync -aHAXS --numeric-ids --info=stats1 root@192.0.2.50:/home/ /home/
-akopierar hela trädet med rättigheter, ägare och tider;-Hbehåller hårda länkar,-Aåtkomstlistor och-Xutökade attribut, som Podmans lagring av avbilder använder.-Shåller glesa filer glesa, så att en stor, mest tom fil inte fyller disken.--numeric-idsbehåller användar-ID som siffror. Utan den matchar rsync ägare på namn, och de ID som containrar använder har inga namn.
Den första kopian tar så lång tid som din data behöver för att ta sig över internet; vår, 1,2 GB mellan två servrar i samma datacenter, tog 17 sekunder. Kör samma kommando igen när du vill: det skickar bara det som ändrats. Lägg till andra kataloger från din lista på samma sätt, som root@192.0.2.50:/srv/ /srv/.
Kontrollera att ägarna kom med. Kör det här på båda servrarna; siffrorna ska vara desamma:
find /home -xdev -printf '%U\n' | sort -n | uniq -c
1 0
1101 1000
18645 1001
1595 165605
943 165636
6 166534
De stora siffrorna är ID från intervallet för plausible: filerna som dess containrar äger. För att se dem som containrarna ser dem, som plausible på den nya servern (machinectl shell plausible@):
podman unshare ls -lnd ~/.local/share/containers/storage/volumes/*/_data
drwxrwxrwx 3 999 65533 4096 Oct 2 18:37 /home/plausible/.local/share/containers/storage/volumes/plausible-data/_data
drwx------ 19 70 70 4096 Oct 2 19:09 /home/plausible/.local/share/containers/storage/volumes/plausible-db/_data
drwxrwsrwx 13 101 101 4096 Oct 2 19:09 /home/plausible/.local/share/containers/storage/volumes/plausible-events/_data
drwxrwxrwx 2 101 101 4096 Oct 2 18:36 /home/plausible/.local/share/containers/storage/volumes/plausible-events-logs/_data
PostgreSQL äger sina filer som användare 70, och ClickHouse som 101. När vi med flit flyttade intervallet för plausible svarade samma kommando Permission denied, och databasen startade inte.
Starta om den nya servern en gång nu, med systemctl reboot. Kopian innehåller också Podmans uppgifter om vilka containrar som var igång, och fram till en omstart försöker Podman stoppa containrar som aldrig har körts på den här servern; i vårt test misslyckades det med conmon exited prematurely. Efter omstarten räknar Podman med att de är stoppade, och användarnas tjänster startar av sig själva, Caddy och appen också.
6. Gör databaserna konsekventa
Filer som kopieras från en databas medan den skriver passar inte alltid ihop: i vårt test startade PostgreSQL från en sådan kopia, men inget garanterar att den gör det. Det finns två vägar till en konsekvent kopia:
- Stoppa appen och kopiera igen. När appen är stoppad är dess filer kompletta, och den andra kopian tar sekunder eftersom bara ändringarna flyttas. Det är den väg vi rekommenderar för bytet i steg 9: den nya servern får exakt samma data som den gamla, utan något att konvertera.
- Kopiera en dump. Varje databas skriver en konsekvent kopia av sig själv medan den är igång, och du läser in den på den nya servern. Använd den för att testa med riktig data utan att stoppa den gamla servern, och för själva flytten när den nya servern kör en annan huvudversion av databasen.
Använd dumpar för testet i steg 7 och 8. Säkerhetskopian i steg 10 i Plausible-guiden gör en av PostgreSQL och en av ClickHouse. Kör den som root på den gamla servern:
systemctl --user -M plausible@ start plausible-backup.service
Kopiera den till den nya servern:
rsync -aHAXS --numeric-ids --delete root@192.0.2.50:/home/plausible/backup/ /home/plausible/backup/
Läs sedan in den, som plausible på den nya servern. Det här byter ut båda databaserna från kopian mot tomma och läser in dumparna i dem:
systemctl --user stop plausible-pod
podman volume rm plausible-db plausible-events
systemctl --user start plausible-db plausible-events
podman exec plausible-db createdb -U postgres plausible_db
podman exec -i plausible-db psql -q -U postgres plausible_db < ~/backup/plausible-db.sql
podman exec plausible-events clickhouse-client -q "RESTORE DATABASE plausible_events_db FROM File('events')"
systemctl --user start plausible-app
Återställningen slutar med RESTORED. För en annan app använder du dess egna kommandon för dumpar: pg_dump eller pg_dumpall för PostgreSQL, mysqldump --single-transaction för MariaDB och MySQL.
7. Kontrollera certifikaten
Caddys certifikat och dess konto hos Let's Encrypt ligger i volymen caddy-data, som kom med /home/caddy. Den nya Caddy använder dem så fort den startar, så det blir inget glapp medan den väntar på nya. Utan dem kan Caddy hämta ett certifikat först när DNS pekar på den, och de första besökarna efter bytet skulle få certifikatfel tills den har fått ett.
Kontrollera från din egen dator att den nya servern har ett giltigt certifikat, där --resolve skickar anropet till den nya adressen utan någon ändring i DNS:
curl -sI --resolve plausible.example.com:443:203.0.113.10 https://plausible.example.com/ | head -1
openssl s_client -connect 203.0.113.10:443 -servername plausible.example.com </dev/null 2>/dev/null | openssl x509 -noout -serial -enddate
HTTP/2 200
serial=06D869A8956CDC1FC20E1D40D8494AD90E92
notAfter=Dec 31 15:45:07 2026 GMT
curl avbryter med ett certifikatfel om certifikatet är fel. Kör raden med openssl mot 192.0.2.50 också: i vårt test visade båda servrarna samma serienummer. Caddy förnyar certifikat 30 dagar innan de går ut, vilket fungerar från den nya servern när DNS pekar på den; vårt certifikat var för nytt för att vi skulle kunna testa en förnyelse.
8. Testa den nya servern innan någon använder den
Använd appen på den nya servern under dess riktiga namn. För en webbläsare lägger du till den nya adressen i hosts-filen på din dator, /etc/hosts på Linux och macOS och C:\Windows\System32\drivers\etc\hosts på Windows:
203.0.113.10 plausible.example.com www.example.com
Din dator går nu till den nya servern för de här namnen, och alla andra fortfarande till den gamla. Logga in och klicka igenom det du använder. I Plausible loggade vårt konto in med sitt befintliga lösenord, och översikten visade webbplatsen med alla dess besök, så SECRET_KEY_BASE och båda databaserna hade flyttat med. Vi testade med Chromiums inbyggda motsvarighet till en hosts-fil, --host-resolver-rules.
Allt du ändrar under testet skrivs över av den sista kopian i steg 9, så testa fritt. Ta bort raden ur hosts-filen när du är klar.
Medan båda servrarna är igång kör båda sina timers också. Appar som skickar e-post eller anropar andra tjänster på schema kan göra det två gånger: stoppa dem på den nya servern fram till bytet, eller håll testet kort.
9. Byt över
Välj en lugn stund. Varje steg här är ett kommando eller två; vårt byte tog 70 sekunder från den gamla Plausibles sista svar till den nyas första.
Stoppa appen på den nya servern, eftersom den sista kopian ersätter dess filer:
systemctl --user -M plausible@ stop plausible-pod
Stoppa den på den gamla servern, och hindra den från att starta igen vid uppstart:
systemctl --user -M plausible@ stop plausible-pod
loginctl disable-linger plausible
Låt Caddy fortsätta köra på den gamla servern. Besökare vars DNS fortfarande har den gamla adressen får då en felsida från den i några minuter, i stället för inget svar alls. Plausible sparar besöken den har i minnet innan den stoppar, så där går inga förlorade.
Kopiera det som ändrats och starta appen, på den nya servern:
rsync -aHAXS --numeric-ids --delete --info=stats1 root@192.0.2.50:/home/plausible/ /home/plausible/
systemctl --user -M plausible@ start plausible-pod plausible-app
until curl -sf -o /dev/null --resolve plausible.example.com:443:127.0.0.1 https://plausible.example.com/api/system/health/ready; do sleep 1; done; echo ready
--delete tar bort filer som inte längre finns på den gamla servern, som allt som blev kvar efter testet. Vår kopia tog 5 sekunder och starten 48. Kopiera /home/caddy igen bara om du har ändrat Caddys inställningar på den gamla servern sedan steg 5, och stoppa i så fall Caddy på den nya servern först.
Ändra nu A- och AAAA-posterna för varje namn på din lista till de nya adresserna, 203.0.113.10 och 2001:db8:10::a. Se hur de publika resolvrarna följer efter:
dig +short plausible.example.com A @1.1.1.1
dig +short plausible.example.com A @8.8.8.8
När båda ger den nya adressen besöker du din webbplats i en vanlig webbläsare, utan raden i hosts-filen. Besöket syns i Plausibles översikt på den nya servern inom några sekunder. I vårt test gav Cloudflare den nya adressen efter två minuter och Google efter fyra, och det första besöket efter det räknades på den nya servern, från Sverige. För att se vilka som fortfarande når den gamla servern tittar du i dess logg för Caddy; Caddy loggar varje anrop som den inte kan skicka vidare, med besökarens adress:
journalctl -f CONTAINER_NAME=caddy
10. Efter flytten
Behåll den gamla servern i några dagar, med appen stoppad men all data kvar: den är din väg tillbaka (steg 11). Kontrollera det här innan du säger upp den:
- Säkerhetskopior körs från den nya servern och tar med de kopierade filerna. Om den gamla servern säkerhetskopierade till en annan plats, som med restic, sätter du upp det på den nya servern och stoppar det på den gamla, annars fortsätter den att skicka gammal data. Användarnas timers stoppades med
disable-lingeri steg 9; systemets timers och cron-jobb på den gamla servern stoppar du själv. - Övervakningen kontrollerar den nya servern. Kontroller på namn följer DNS av sig själva; kontroller på IP-adress behöver den nya.
- E-post: om servern skickar e-post ställer du in omvänd DNS för dess nya adresser, som i steg 2 i guiden om mailservern, och byter ut de gamla adresserna i din SPF-post.
- Brandväggsregler på andra ställen som släpper in den gamla serverns adress, till exempel hos en databas- eller backupserver, behöver nu den nya.
- SSH-nyckeln från steg 4. Ta bort den från den gamla servern och radera den på den nya:
sed -i '/ migration$/d' /root/.ssh/authorized_keys # on the old server
rm /root/.ssh/id_ed25519 /root/.ssh/id_ed25519.pub # on the new server
När allt har fungerat på den nya servern i några dagar ställer du tillbaka TTL till vad den var, och säger upp den gamla servern.
11. Om något är fel: gå tillbaka
Innan du ändrar DNS kostar det ingenting att gå tillbaka: starta appen på den gamla servern igen, så märker besökarna aldrig något. Som root på den gamla servern:
loginctl enable-linger plausible
Det startar användarens tjänster som vid uppstart. I vårt test svarade Plausible igen 49 sekunder senare, med sin data som den var vid bytet.
Efter DNS-ändringen gör du samma sak och ändrar tillbaka DNS-posterna till de gamla adresserna. Det som den nya servern har samlat in sedan bytet, som nya besök, finns då bara på den nya servern. För att behålla det stoppar du appen på den nya servern och kopierar dess filer tillbaka åt andra hållet, med samma rsync-kommando, kört på den gamla servern; vi har inte testat vägen tillbaka med data.
Felsökning
podman unshare ls svarar Permission denied, eller PostgreSQLs logg visar could not open file "global/pg_filenode.map": Permission denied. Användarens ID-intervall på den nya servern skiljer sig från den gamlas, så containrarna äger inte sina filer. Ändra raderna i /etc/subuid och /etc/subgid så att de stämmer med den gamla servern (steg 3), och kör sedan podman system migrate som användaren. Kör inte chown på filerna som root: då får de ägare som containrarna inte kan använda, och att reparera det kräver podman unshare chown för varje volym.
En tjänst startar inte efter den första kopian, och dess logg visar conmon exited prematurely eller att ett containernamn is already in use. Podman har kvar sina uppgifter om containrar som var igång på den gamla servern. Starta om den nya servern (steg 5).
rsync eller SSH svarar No route to host mellan två servrar hos Melonslab. De ligger i samma nätverk, och trafiken mellan dem går inte via gatewayen än. Se guiden om att koppla ihop två servrar.
curl i steg 7 avbryter med ett certifikatfel. Caddy på den nya servern har inget certifikat för namnet, eftersom /home/caddy inte kopierades, eller inte helt. Stoppa Caddy på den nya servern, kopiera /home/caddy igen och starta den.
Besökare når fortfarande den gamla servern långt efter ändringen. En TTL var fortfarande lång när du ändrade posten: vänta en gammal TTL. En del program sparar DNS-svar längre än de borde; att starta om dem hjälper.