چگونه از پنج VPS به یک سرور اختصاصی با Proxmox مهاجرت کردم و از تغذیه هاستینگها دست کشیدم
خلاصه: زیرساخت پراکنده از پنج VPS نزد سه ارائهدهنده → یک سرور اختصاصی Ryzen 7 9700X / 64GB ECC / 2× NVMe ZFS-mirror، با Proxmox VE. در داخل — VM/LXC بر اساس نقشها، NetBird-mesh به جای port forwarding، یک نود خروجی روی VPS جداگانه برای دور زدن مسدودیتها و TLS-termination، PBS برای بکآپها. سود مالی، کنترل، و اعصاب در وضعیت مثبت. در این مقاله — چرا، چگونه، و چه اشتباهاتی در مسیر داشتم تا شما تکرار نکنید.
چرا اصلاً این کار را شروع کردم
تا پایان سال گذشته متوجه شدم که برای پنج VPS مختلف نزد سه هاستینگ پول پرداخت میکنم. یکی — برای انجمن Discourse، دومی — برای انجمن قدیمی PHP با MySQL، سومی — برای صورتحساب و رباتهای تلگرام، چهارمی — VPN/پروکسی، پنجمی — استاتیک و ابزارهای کوچک مختلف. و همچنین n8n، Vaultwarden، و چند Uptime Kuma که به طور متقابل یکدیگر را مانیتور میکردند (چرا که نه).
چه چیزهایی بد بودند:
- پول. مجموعاً تقریباً همان هزینهای میشد که یک سرور اختصاصی مناسب با مشخصات مشابه داشت (اما آنجا اشتراکی بود، اینجا اختصاصی).
- هیچ جداسازیای وجود نداشت. اگر حافظه یک ربات مشتری شروع به نشت کند — انجمن من شروع به کند شدن میکند. روی همان سرور. عالی بود.
- بکآپها — از راهی اشتباه. هر VPS بکآپ rsync-cron خودش را در S3 داشت، سطوح نگهداری متفاوت، هیچ افزایشی، بازیابی — یک ماجراجویی کامل.
- شبکه مانند سالاد. SSH از طریق پورتهای مختلف، عبور داده شده از Cloudflare Tunnels، از طریق WireGuard که به صورت دستی بین دو VPS راهاندازی شده بود، با پیکربندیها در سه نقطه. هر بار که یک ماشین جدید اضافه میکردم — یک روز طول میکشید تا ادغام شود.
- آپدیت-آخرالزمان. روی پنج Ubuntu/Debian مختلف با نسخهها و بستههای مختلف، آپدیتها باید دستی انجام میشدند و هرگز نمیتوانستند همزمان باشند. هر شش ماه یک بار من به قهرمانانه کوئست "همه چیز را آپدیت کن، هیچ چیز را خراب نکن" را انجام میدادم.
- CPU و RAM بیکار میماندند. هر VPS برای "اوج" رزرو شده بود، اما به طور متوسط تنها ۱۵-۲۰٪ استفاده میشد. پول به هوا پرتاب میشد.
به طور کلی — یک مورد کلاسیک که زیرساخت بر اساس اصل "اوه، یک سرویس دیگر لازم است — یک VPS میخرم" رشد کرده بود. وقت آن بود که همه اینها را یکپارچه کنم.
چه چیزی را انتخاب کردم و چرا
سختافزار
سرور اختصاصی گرفتم:
- CPU: AMD Ryzen 7 9700X (8 هسته / 16 رشته، Zen 5)
- RAM: 64 GB DDR5 ECC 5200 MHz
- دیسکها: 2× NVMe 512 GB enterprise → ZFS mirror
- شبکه: 1 Gbps unmetered
- قیمت: تقریباً دو VPS متوسط نزد همان OVH
هایپروایزر
Proxmox VE 9.x. جایگزینها را بررسی کردم، اما به طور خلاصه:
- Docker خام — جداسازی ندارد، اسنپشاتهای مناسب ندارد، بکآپ فقط با ابزارهای compose، دیسک — یک سطل زباله واحد.
- VMware ESXi — دیگر رایگان نیست، مجوز Broadcom عالی است، ممنون.
- XCP-ng — خوب است، اما شخصاً Proxmox را از حفظ میدانم و جامعه آن زندهتر است.
- Kubernetes — نه، من یک نفر هستم، نیازی ندارم هواپیما بسازم تا به فروشگاه بروم.
Proxmox همه آنچه را که نیاز دارم به من میدهد: ماشینهای مجازی KVM برای هر چیزی که نیاز به جداسازی دارد (Docker، کرنلهای خاص، توزیعهای مختلف)؛ کانتینرهای LXC جایی که میتوان منابع را ذخیره کرد (پایگاه داده، مانیتورینگ، سرویسهای کوچک)؛ PBS داخلی برای بکآپها؛ ZFS از جعبه خارج؛ اسنپشاتها؛ مهاجرت زنده (اگر روزی سرور دوم ظاهر شود)؛ رابط وب که میتوان با موس روی آن کلیک کرد وقتی نمیخواهیم در ترمینال بنویسیم.
معماری: طرح کلی
ابتدا آنچه به دست آوردم را نشان میدهم، سپس توضیح میدهم چگونه به آن رسیدم.
منطق به این صورت است:
- روی سرور اختصاصی Proxmox زندگی میکند. این سرور IP عمومی
Y.Y.Y.Yرا رویvmbr0دارد. - در داخل یک bridge دوم
vmbr1با شبکه خصوصی10.10.10.0/24ساخته شده است. این معادل "LAN داخلی" است — همه VM ها و LXC ها به آن متصل هستند، خارج از طریق NAT از هاست، آنها هیچ پورت عمومی ورودی ندارند. - روی خود هاست فقط سه چیز اجرا میشود:
Caddy(reverse proxy داخلی)،nftables(فایروال) وNetBird(ایجنت VPN). هیچ Docker روی هاست، هیچ منطق برنامهای روی هاست. هاست یک گاو مقدس است، وظیفه آن هایپروایزر بودن و سقوط نکردن است. - ماشینهای مجازی بر اساس نقشها تقسیم شدهاند: یکی برای انجمن، یکی برای سرویسهای پسزمینه و رباتها، یکی برای Dokploy با برنامههای کاربر، و غیره. بین آنها دید مستقیم بر روی
10.10.10.xوجود دارد، خارج — فقط از طریق Caddy هاست. - کانتینرهای LXC — برای همه چیزهای "سبک": اینستنسهای Postgres از نسخههای مختلف، Proxmox Backup Server، داشبوردهای مانیتورینگ. آنها نیز در
vmbr1هستند. - یک نود خروجی جداگانه ("Peer Caddy") — یک VPS کوچک نزد یک ارائهدهنده دیگر، در شبکهای که برای مخاطبان من مناسب است. Caddy روی آن نصب شده است که TLS (Let's Encrypt) را خاتمه میدهد و HTTP را از طریق NetBird-mesh به داخل سرور اختصاصی پروکسی میکند. DNS همه دامنههای عمومی به این VPS اشاره میکند، نه به سرور اختصاصی.
- NetBird mesh سرور اختصاصی، نود خروجی و لپتاپ من را به هم متصل میکند (و همچنین چند سرور قدیمی که هنوز همه چیز از آنها منتقل نشده است). این WireGuard بر روی احراز هویت SSO است، بدون پورتهای باز از بیرون.
چرا چنین جداسازی از طریق نود خروجی — یک بحث جداگانه است که دوباره به آن خواهم پرداخت.
نصب Proxmox: چگونه آن را راهاندازی کردم
سرور اختصاصی را سفارش دادم، در اولین بوت Proxmox را از طریق حالت rescue/KVM نصب کردم (OVH هر دو را دارد — KVM برای من راحتتر است، کل فرآیند را میبینم). هنگام نصب:
- ZFS RAID1 روی هر دو NVMe (
ashift=12, compression=lz4 بلافاصله فعال شد) - پارتیشنبندی پیشفرض، Proxmox خودش
rpool/ROOT,rpool/data, swap را ایجاد میکند
بعد — پاکسازی اولیه پس از نصب. این یک ضرورت است، بدون آن Proxmox خطاهای اشتراک را ایجاد میکند و بهینه کار نمیکند.
1# 1. حذف مخزن enterprise (اشتراک ندارد)
2sed -i 's/^deb/#deb/' /etc/apt/sources.list.d/pve-enterprise.list
3echo "deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription" \
4 > /etc/apt/sources.list.d/pve-no-subscription.list
5apt update && apt full-upgrade -y
6
7# 2. حذف پنجره هشدار "No valid subscription"
8sed -Ezi.bak "s/(Ext\.Msg\.show\(\{[^}]+?title: gettext\('No valid sub)/void\(\{ \/\/\1/g" \
9 /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js
10systemctl restart pveproxy
11
12# 3. Hostname / timezone
13hostnamectl set-hostname dedik-waw
14timedatectl set-timezone Europe/Warsaw
Hardening SSH
بلافاصله. نه "بعداً". بعداً — هرگز نمیرسد.
1cat > /etc/ssh/sshd_config.d/hardening.conf << 'EOF'
2Port 22222
3PermitRootLogin prohibit-password
4PasswordAuthentication no
5MaxAuthTries 3
6ClientAliveInterval 300
7ClientAliveCountMax 2
8EOF
9
10mkdir -p ~/.ssh
11echo "ssh-ed25519 AAAA... your-key" >> ~/.ssh/authorized_keys
12chmod 600 ~/.ssh/authorized_keys
13systemctl restart sshd
پورت 22 در فایروال بسته شد، فقط پورت غیر استاندارد باقی ماند. این security through obscurity نیست، بلکه کاهش نویز پسزمینه در لاگها است — در پورت 22 در همان ساعت اول ۵۰۰۰۰ تلاش برای بروتفورس وارد میشود، در لاگها چیزی دیده نمیشود. در ۲۲۲۲۲ — سکوت است و میتوان به طور واقعی ناهنجاریها را نظارت کرد.
ZFS — تنظیم برای NVMe و 64GB RAM
ZFS به طور پیشفرض میخواهد نیمی از RAM را برای ARC مصرف کند. این برای سرور فایل خوب است و برای هایپروایزر کاملاً مضر است، زیرا حافظه برای ماشینهای مجازی لازم است. ARC را به ۱۶ گیگابایت منطقی فشرده میکنیم:
1cat > /etc/modprobe.d/zfs.conf << 'EOF'
2options zfs zfs_arc_max=17179869184
3options zfs zfs_arc_min=4294967296
4EOF
5update-initramfs -u
توزیع حافظه من:
- ~16 GB — ZFS ARC
- ~44 GB — VM/LXC
- ~4 GB — سیستم، بافرها، سربار
تنظیمات مفید خود pool:
1zfs set compression=lz4 rpool
2zfs set atime=off rpool
3zfs set xattr=sa rpool
4zfs set dnodesize=auto rpool
5zfs set relatime=on rpool
6
7zfs set recordsize=64K rpool/data # برای دیسکهای VM
8zfs set sync=standard rpool/data
9
10zpool set autotrim=on rpool # برای NVMe حیاتی است
compression=lz4 حدود ۲۰-۳۰٪ فضا را تقریباً رایگان با CPU ذخیره میکند. recordsize=64K برای دستگاههای بلوکی VM — بهترین مصالحه بین عملکرد و افزونگی نوشتن است.
شبکه داخلی و فایروال
Bridge دوم برای شبکه خصوصی با NAT به بیرون ایجاد کردم:
1auto vmbr1
2iface vmbr1 inet static
3 address 10.10.10.1/24
4 bridge-ports none
5 bridge-stp off
6 bridge-fd 0
7 post-up echo 1 > /proc/sys/net/ipv4/ip_forward
8 post-up iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -o vmbr0 -j MASQUERADE
9 post-down iptables -t nat -D POSTROUTING -s 10.10.10.0/24 -o vmbr0 -j MASQUERADE
حالا هر VM/LXC در bridge vmbr1 یک آدرس محلی 10.10.10.x دریافت میکند و از طریق هاست به اینترنت میرود، اما از بیرون قابل مشاهده نیست.
nftables با policy drop. فقط آنچه باید باز باشد، باز است، بقیه خاموش میافتند. حداقل مجموعه:
1table inet filter {
2 chain input {
3 type filter hook input priority 0; policy drop;
4
5 iif lo accept
6 ct state established,related accept
7 ip protocol icmp accept
8 ip6 nexthdr icmpv6 accept
9
10 tcp dport 22222 accept # SSH
11 tcp dport 8006 accept # Proxmox UI (فقط از NetBird، در ادامه ببینید)
12 tcp dport { 80, 443, 8080 } accept # Caddy
13 udp dport 29899 accept # NetBird
14
15 iif vmbr1 accept # شبکه داخلی — همه مجاز هستند
16 iif wt0 accept # رابط NetBird — نیز مورد اعتماد است
17 }
18
19 chain forward {
20 type filter hook forward priority 0; policy drop;
21 iif vmbr1 oif vmbr0 accept
22 ct state established,related accept
23 }
24}
دسترسی به Proxmox UI (پورت 8006) را فیزیکی از اینترنت از طریق CF/firewall بستم و فقط از طریق NetBird به آن دسترسی دارم. از طریق IP عمومی رابط به هیچ وجه پاسخ نمیدهد. همینطور برای PBS UI، داشبوردها و همه چیزهای مدیریتی — فقط از طریق mesh. از بیرون فقط پورتهای واقعاً عمومی سرویسها باز هستند.
NetBird mesh: چرا WireGuard کلاسیک نه
من مدت طولانی از WireGuard معمولی استفاده کردم و خوب بود، تا زمانی که تعداد سرورها به بیش از سه رسید. پس از آن — مدیریت پیکربندیها دردناک شد: اضافه کردن هر peer به "آپدیت پیکربندی در همه نودها، allowed_ips را فراموش نکن، دیمون را ریاستارت کن، بررسی کن که مسیر به peer دیگر را خراب نکرده باشی" تبدیل شد.
NetBird — یک صفحه مدیریت بر روی WireGuard است. از نظر فنی در پشت صحنه همه چیز همان wg است، اما:
- نودها از طریق سرور سیگنالینگ یکدیگر را پیدا میکنند، NAT-traversal خودکار است
- احراز هویت از طریق SSO (برای من — از طریق Authentik)، بدون اشتراکگذاری کلید
- دسترسی از طریق رابط وب با استفاده از سیاستها مدیریت میشود، میتوان گروههای ماشین و قوانین بین آنها را ایجاد کرد
- پروکسی SSH داخلی: میتوان از طریق
ssh user@machine.netbird.cloudدسترسی داشت و احراز هویت SSO را دریافت کرد (با تأیید در Authentik). حتی نیازی به باز کردن پورت 22 روی نود از بیرون نیست.
من NetBird-agent را راهاندازی کردم:
- روی هاست Proxmox
- روی هر VM که باید توسط مدیر یا VM های دیگر قابل مشاهده باشد
- روی نود خروجی
- روی لپتاپم
در نتیجه، من از لپتاپم به هر ماشینی با یک دستور، بدون port forwarding، بدون حفرههای فایروال، بدون هاستهای bastion اضافی دسترسی دارم. و هیچ SSH باز روی هیچ یک از VM های خصوصی وجود ندارد — همه آنها فقط در vmbr1 به علاوه mesh wt0 هستند.
ماشینهای مجازی در مقابل کانتینرها: چگونه خودم را برای آن حل کردم
قانون سادهای که تقریباً همیشه کار میکند:
| چه زمانی | چه چیزی را انتخاب کنیم |
|---|---|
| بارهای کاری Docker | VM (Docker در LXC گاهی اوقات سرکش است، به خصوص با overlay2) |
| پایگاه داده بدون Docker | LXC (سبکتر، سریعتر، دسترسی مستقیم به دیسک از طریق ZFS) |
| سرویسهای سیستمی (PBS، مانیتورینگ، ابزارهای کوچک) | LXC |
| برنامههایی که نیاز به کرنل خاص / ترفندهای شبکه دارند | VM |
| گرههای VPN (WG, AmneziaWG) | LXC (حداقل سربار) |
در نتیجه، من به این صورت رسیدم:
ماشینهای مجازی (KVM):
forum— Discourse در کانتینر راهانداز استاندارد. Docker در داخل.services— بسیاری از موارد کوچک: رباتهای webhook، ربات AI، پنل صورتحساب، Vaultwarden، Uptime Kuma. همه در Docker compose، یک پوشه برای هر سرویس.legacy— انجمن قدیمی PHP (IPS) با native PHP-FPM و Caddy روی VM. نمیخواستم آن را در Docker بستهبندی کنم — خیلی قدیمی بود، آسانتر بود که همانطور که بود باقی بماند.dokploy— Docker Swarm + Dokploy برای برنامههای کاربر (Next.js, Postgres, Redis)، استقرار از طریق Git.
LXC:
pbs— Proxmox Backup Server (در ادامه ببینید).pg16,pg17,pg18— سه نمونه Postgres جداگانه از نسخههای مختلف. نکته: برنامههای مختلف به نسخه متفاوتی نیاز دارند، و من نمیخواهم هر کدام را بالا و پایین ببرم.dashboards— یک کانتینر با Homarr (صفحه شروع)، Uptime Kuma و Beszel hub. هر سه در یک compose، چون منطقاً مربوط به یک چیز هستند — مشاهده.
هر VM یک IP استاتیک در 10.10.10.x (بر اساس محدودهها، یافتن آن راحتتر است)، 2-8 هسته vCPU و 2-8 گیگابایت RAM بسته به بار کاری دریافت میکند. هستهها را میتوان با خیال راحت بیش از حد رزرو کرد — من در مجموع بیش از هستههای فیزیکی برای VM ها تخصیص دادهام، و این به خوبی کار میکند، تا زمانی که هیچ کس همزمان به CPU فشار وارد نکند.
Reverse proxy: Caddy دو طبقه
در داخل Proxmox، Caddy را روی هاست نصب کردم، نه در VM. چرا؟ زیرا باید پورتهای عمومی سرور اختصاصی را گوش دهد و بر اساس Host-header به VM مورد نظر مسیریابی کند، و برای این کار یک VM جداگانه با port forwarding راهاندازی کنم — یک لایه اضافی بدون سود. Caddy سبک است، به زبان Go نوشته شده، یک واحد systemd، پیکربندی در یک فایل.
این Caddy هاست فقط پورت 8080 HTTP را گوش میدهد و بر اساس 10.10.10.x به بکاندها مسیریابی میکند. هیچ TLS روی آن وجود ندارد.
1:8080 {
2 @forum host forum.example.com www.forum.example.com
3 handle @forum {
4 reverse_proxy http://10.10.10.111:80 {
5 header_up X-Forwarded-Proto https
6 header_up X-Real-IP {header.X-Real-IP}
7 header_up Host {host}
8 }
9 }
10
11 @panel host panel.example.com api.panel.example.com
12 handle @panel {
13 reverse_proxy http://10.10.10.111:8081 {
14 header_up X-Forwarded-Proto https
15 header_up X-Real-IP {header.X-Real-IP}
16 header_up Host {host}
17 }
18 }
19
20 @dokploy host app1.example.com app2.example.com
21 handle @dokploy {
22 reverse_proxy http://10.10.10.114:80 {
23 header_up X-Forwarded-Proto https
24 header_up X-Real-IP {header.X-Real-IP}
25 header_up Host {host}
26 }
27 }
28}
و TLS-termination و گواهیها — روی یک نود خروجی جداگانه، در Docker، بر اساس همان اصل:
1{
2 email me@example.com
3}
4
5forum.example.com {
6 reverse_proxy http://100.x.y.z:8080 {
7 header_up X-Forwarded-Proto {scheme}
8 header_up X-Forwarded-For {remote_host}
9 header_up X-Real-IP {remote_host}
10 header_up Host {host}
11 }
12}
100.x.y.z — آدرس NetBird سرور اختصاصی است. درخواست به نود خروجی از طریق HTTPS میرسد، رمزگشایی میشود، از طریق NetBird-mesh به صورت HTTP به سرور اختصاصی میرود، در آنجا Caddy Proxmox بر اساس Host مطابقت داده و به VM داخلی مسیریابی میشود. بین نود خروجی و سرور اختصاصی HTTP بر اساس طراحی است — ما به mesh اعتماد داریم، هیچ ترافیک خارجی در اینجا وجود ندارد.
چرا اصلاً نود خروجی
چند دلیل:
- دور زدن مسدودیتها. بخشی از زیرشبکههای OVH در روسیه مسدود شده است. نود خروجی نزد یک ارائهدهنده است که IP آن مسدود نشده است. DNS دامنههای عمومی به آنجا اشاره میکند.
- TLS-termination در یک مکان. گواهیها فقط توسط آن صادر میشوند، IP آن تنها IP برای چالش Let's Encrypt است. این کار تمام بررسیهای DNS-cleared را ساده میکند و اجازه میدهد سرور اختصاصی از طریق 80/443 از اینترنت کاملاً نامرئی باشد.
- یک لایه جداسازی اضافی. اگر کسی شروع به DDoS کند — او به نود خروجی حمله میکند، نه به سرور اختصاصی. من حداقل داده را در نود خروجی دارم، بازسازی آن — ۱۰ دقیقه طول میکشد.
- جداسازی فرانت عمومی از بکاند. من میتوانم با خیال راحت Caddy را در سرور اختصاصی آپدیت کنم / آزمایش کنم، در حالی که رابط واقعی به اینترنت جداگانه و پایدار دارم.
یک عیب: حدود ۵-۱۵ میلیثانیه به هر درخواست به دلیل یک هاپ اضافی اضافه میشود. برای وب نامحسوس است.
همچنین برای برخی سرویسها Caddy مستقیم روی هاست روی 80/443 بدون نود خروجی وجود دارد — برای آن دامنههایی که نیازی به عبور دادن از نقطه خروجی ندارم (مانند نقاط پایانی وضعیت، مانیتورینگ، سرویسی که DNS آن به هر حال به سرور اختصاصی اشاره میکند). این به صورت موازی کار میکند: Caddy روی هاست هم :8080 (داخلی از نود خروجی) و هم :80/:443 (مستقیم از اینترنت) را گوش میدهد، مسیرها متفاوتند.
مهاجرت: چگونه بدون اشک و تقریباً بدون قطعی منتقل شدم
این ترسناکترین مرحله بود. پنج سرور، حدود سی سرویس، انجمن پروداکشن با کاربران زنده، صورتحساب با اشتراکهای فعال، پایگاه دادههایی که به هیچ وجه نباید از دست بروند.
استراتژی — مهاجرت سرویس به سرویس، به ترتیب "از کمترین حیاتی به بیشترین حیاتی":
- ابتدا ابزارهای کوچک و سایتهای استاتیک منتقل شدند (اگر مشکلی بود — کسی متوجه نمیشد).
- سپس رباتها و سرویسهای پسزمینه (آنها نیز یک دقیقه قطعی را تحمل میکنند).
- سپس پایگاه دادهها (با بازیابی از پیش تأیید شده).
- سپس برنامههایی که به این پایگاههای داده نگاه میکنند.
- در نهایت — انجمن اصلی با یک دور نهایی همگامسازی طولانی و تغییر DNS.
کانال مهاجرت
ابتدا NetBird را روی سرورهای قدیمی راهاندازی کردم. این بلافاصله دو چیز را حل کرد: من میتوانم با خیال راحت از طریق SSH به شبکههای داخلی دسترسی داشته باشم، و rsync از طریق WireGuard از طریق NetBird اجرا میشود، بدون اینکه دادهها را در اینترنت باز نشان دهد.
فرمان جنگی برای هر سرویس تقریباً به این صورت بود:
1# از سرور اختصاصی جدید، از طریق IP NetBird سرور قدیمی:
2rsync -avzP --delete \
3 -e "ssh -p 5322" \
4 root@100.76.108.210:/var/discourse/shared/standalone/ \
5 /target/discourse/shared/standalone/
برای پایگاه دادهها — dump + restore، نه کپی فایل. هرگز فایلهای Postgres/MySQL را "داغ" کپی نکنید، این بلیط یک طرفه است.
1# روی قدیمی
2docker exec -it shm-vsem-mysql mysqldump -u root -p shm-vsem | \
3 gzip > /tmp/shm-vsem.sql.gz
4
5# روی جدید، از طریق NetBird
6scp -P 5322 root@100.76.108.210:/tmp/shm-vsem.sql.gz /tmp/
7zcat /tmp/shm-vsem.sql.gz | docker exec -i shm-vsem-mysql mysql -u root -p shm-vsem
برای Discourse — discourse backup / discourse restore بومی از طریق ./launcher enter app. در داخل، به طور خودکار dump Postgres + uploads + پیکربندیها را جمعآوری میکند و دقیقاً به همان شکل بازیابی میکند.
تغییر DNS
پس از اینکه سرویس در مکان جدید راهاندازی شد و بررسی شد که از طریق آدرس داخلی کار میکند — من هر دو نصب را به مدت ۵-۱۵ دقیقه به صورت موازی اجرا کردم تا از همگامسازی دادهها مطمئن شوم، و سپس DNS را به سرور جدید تغییر دادم. TTL رکوردها را از یک روز قبل از تغییر به ۶۰-۳۰۰ ثانیه کاهش داده بودم.
برای Discourse، که کاربران فعال دائماً پست میگذارند، من این کار را انجام دادم:
- همه چیز را در مکان جدید راهاندازی کردم.
- اعتبارسنجی را اجرا کردم (ورود، ارسال، آپلود فایل در S3، جستجو).
- در نصب قدیمی
read_only_modeرا فعال کردم (Discourse این قابلیت را از جعبه دارد). - یک rsync نهایی uploads + یک dump نهایی پایگاه داده انجام دادم.
- روی جدید راهاندازی کردم، read-only را غیرفعال کردم.
- DNS را تغییر دادم.
- روی قدیمی تا یک هفته هیچ تغییری ندادم — برای "اگر چه؟".
قطعی واقعی برای کاربران — حدود دو دقیقه در هر سرویس.
شگفتیها در طول مسیر
- مجوزها هنگام
pct restore. LXC تحتunprivileged 1UID ها را با شیفت ۱۰۰۰۰۰ نگاشت میکند. اگر در سرور قدیمی فایلها زیر UID 1000 دارید — در سرور جدید آنها زیر UID 101000 خواهند بود و برنامه آنها را نخواهد دید. این یا باchownپس از restore حل میشود، یا با--unprivileged 0اگر ریسکها را درک میکنید. - Docker ipv6 در ماشینهای مجازی OVH گاهی اوقات بد راهاندازی میشد — با غیرفعال کردن ipv6 در Docker daemon (
"ipv6": false) حل شد. - زمان در VM. چندین بار اختلاف زمان سیستمی بین هاست و VM را گرفتم که TLS و امضاها را خراب میکرد. راه حل —
systemd-timesyncdیاchronyروی هر VM، وhost.use-timeدر ایجنت Proxmox. - مهاجرت Discourse بین دو نسخه. اگر Discourse در سرور قدیمی جدیدتر از آن چیزی است که در سرور جدید راهاندازی کردهاید —
restoreموفقیتآمیز نخواهد بود. نسخه باید در نصب جدید همسان یا بالاتر باشد. - رجیستری ایمیج برای Dokploy. وقتی متادیتای Dokploy را از طریق dump
dokploy-postgresمنتقل کردم، لینکهایی به رجیستری محلی قدیمی روی IP قدیمی در پایگاه داده باقی ماند. سرویسها هنگام تلاش برای شروع به100.76.117.115:5000میرفتند و باNo such imageسقوط میکردند. راه حل — بازسازی هر برنامه در UI Dokploy؛ ساخت محلی ایمیج را روی سرور جدید قرار میدهد.
بکآپها: PBS در داخل همان سرور اختصاصی + offsite
اینجا یک بحث فلسفی جداگانه با خودم داشتم: بکآپ گرفتن روی همان سختافزار یا نه. پاسخ: هم بله، هم نه.
سطح ۱ — ZFS-snapsht روی خود pool. آنها تقریباً رایگان هستند (copy-on-write)، فوراً ایجاد میشوند، فوراً بازیابی میشوند. من اسنپشاتهای خودکار rpool/data را هر ۱۵ دقیقه با نگهداری ۲۴ ساعته، و سپس روزانه با نگهداری یک هفتهای نگه میدارم. از zfs-auto-snapshot استفاده میشود. محافظت در برابر "وای، من همین الان پروداکشن DB را حذف کردم":
1apt install zfs-auto-snapshot
2# بعد خودش از طریق cron frequent/hourly/daily/weekly/monthly ایجاد میکند
سطح ۲ — Proxmox Backup Server در یک LXC جداگانه روی همان هاست. اینها بکآپهای افزایشی کامل VM/LXC از طریق vzdump هستند، در سطح چانکها deduplicate شدهاند. PBS اسنپشاتها را در یک مجموعه داده ZFS جداگانه ذخیره میکند، آنها را به عنوان یک مخزن میبیند، هر VM یک زنجیره افزایشی خاص خود را دارد.
تنظیمات در Proxmox: Datacenter → Backup → Add. برنامه: هر روز ساعت ۴ صبح، نگهداری keep-daily=7 keep-weekly=4 keep-monthly=3. همه اینها با موس.
قرار دادن PBS در LXC روی همان هاست — یک مصالحه. مزیت: نیازی به سختافزار جداگانه نیست، بکآپ از طریق localhost انجام میشود، سرعت مانند SSD محلی است، retention/dedup به خوبی کار میکند. عیب: اگر سرور اختصاصی کاملاً از کار بیفتد — بکآپها نیز از بین میروند. بنابراین وجود دارد...
سطح ۳ — همگامسازی مخزن PBS در S3 offsite. PBS میتواند sync job را به فضای ذخیرهسازی سازگار با S3 انجام دهد. من هر شب اسنپشاتها را به یک bucket جداگانه در S3 Selectel (میتواند هر چیزی باشد — Backblaze، Wasabi، Cloudflare R2) منتقل میکنم. نگهداری در آنجا — دو هفته، چون بیشتر از این لازم نیست: برای بلندمدت PBS محلی وجود دارد، و offsite — یک بیمه در برابر "کل مرکز داده سوخت".
سطح ۴ — دادههای برنامه به طور جداگانه. Discourse به خودی خود بکآپهای خود را ایجاد میکند و آنها را در S3 قرار میدهد (این یک ویژگی بومی آن است). بنابراین حتی اگر PBS و کل سرور اختصاصی از بین برود — من هنوز هم بکآپهای سازگار Discourse را در فضای ابری آنها دارم.
1# بازیابی یک VM کامل از PBS — واقعاً یک دستور:
2pvesm list backup-pbs # برای دیدن آنچه موجود است
3qmrestore backup-pbs:backup/vzdump-qemu-201-2026_04_06-04_00_03.vma.zst 999 \
4 --storage local-zfs
5# و بعد از یک دقیقه، شما یک کپی از forum-VM در لحظه ۴ صبح روی VMID 999 دارید.
این یک نکته حیاتی است: بکآپهایی که سعی نکردهاید بازیابی کنید — بکآپ نیستند. من هر ماه یک restore آزمایشی از یک VM تصادفی روی یک VMID خالی انجام میدهم، بررسی میکنم که بالا میآید، برنامه داخل آن کار میکند، و آن را حذف میکنم. خستهکننده است، اما یک بار دقیقاً به همین دلیل متوجه شدم که یکی از cron ها در /tmp/... مینویسد، که هنگام بکآپ نادیده گرفته میشود، و برنامه پس از restore نیاز به یک مرحله دستی دارد.
مانیتورینگ
من دوست ندارم مجموعه کامبو مانند Prometheus + Grafana + Alertmanager + Loki را جمع کنم، وقتی ۱۵ ماشین دارم. بنابراین روی سه ابزار سبک در یک LXC متوقف شدم:
- Beszel — معیارهایی را از ایجنتهای روی هر VM جمعآوری میکند (CPU، RAM، دیسکها، رابطهای شبکه، کانتینرهای Docker). Hub در LXC زندگی میکند، ایجنتها — روی هر VM/LXC از طریق واحد systemd. Beszel احراز هویت خودش را از طریق PocketBase دارد، که گاهی اوقات ناراحتکننده است (در ادامه در مورد گرهها ببینید)، اما به طور کلی کار میکند.
- Uptime Kuma — بررسی از طریق HTTP/HTTPS/Ping/TCP. من همه چیزهای عمومی (دامنهها)، همه سرویسهای داخلی (از طریق NetBird) و پینگ همه نودهای mesh را به آنجا وارد کردهام. هشدارها — در تلگرام.
- Homarr — صفحه شروع با لینک به همه پنلهای مدیریتی. تا مجبور نباشم به خاطر بسپارم که رابط PBS UI روی کدام پورت است، Dokploy روی کدام، Vaultwarden روی کدام. فقط Homarr را باز میکنم و کلیک میکنم.
هر سه در یک Docker compose، در یک LXC، فقط از طریق NetBird در دسترس هستند.
گره با Beszel، تا شما به آن گره نزنید: Beszel دو جدول کاربر در PocketBase دارد —
_superusers(برای CLI/API) وusers(برای رابط وب). اگر رمز عبور را از طریق CLIsuperuser upsertبازنشانی کنید — فقط_superusersرا بازنشانی میکنید، و در UI شما باusersوارد میشوید و رمز عبور کار نمیکند. با درخواست PATCH به/api/collections/users/records/<id>از طریق API REST درمان میشود.
در نهایت چه چیزی به دست آوردم
پس از حدود سه هفته مهاجرت، وقتی آخرین سرویسها مستقر شدند، نتیجهگیری کردم:
| پارامتر | قبلاً | حالا |
|---|---|---|
| سرورها / فاکتورها | 5 در 3 هاستینگ | 1 سرور اختصاصی + 1 VPS کوچک |
| پرداخت در ماه | ~$X | ~$X/2 |
| منابع آزاد | "به نظر میرسد کافی است" | 8 vCPU و 30 گیگابایت RAM در ذخیره |
| بکآپها | rsync-cron در S3 در هر VPS | PBS + offsite + ZFS-snapsht |
| بازیابی | "خب، حدود یک روز" | 2-5 دقیقه در هر VM از PBS |
| دسترسی SSH | 5 پورت و کلید مختلف | یک NetBird-mesh با SSO |
| جداسازی سرویسها | سطل زباله مشترک | هر کدام در VM/LXC خودشان |
| اسنپشات قبل از آپدیت | "دعا کن" | qm snapshot 201 pre-update |
| رابط وب برای وظایف روتین | کدام رابط وب؟ | Proxmox UI |
مهمترین چیزی که این به من داد از نظر عاطفی — من دیگر از دست زدن به چیزی نمیترسم. هر اقدام خطرناکی (آپدیت، مهاجرت، آزمایش) اکنون با یک اسنپشات شروع میشود و یا با یک کامیت یا با بازگشت در ۳۰ ثانیه به پایان میرسد. من شروع به امتحان کردن چیزهای جدید کردم، زیرا هزینه اشتباه در یک مرتبه افت کرد.
چکلیست، اگر تکرار خواهید کرد
اگر خودتان را در حال تجربه همان علائمی که من داشتم یافتید — در اینجا یک چکلیست کوتاه وجود دارد، که به ترتیب منطقی است:
- هزینه کل همه VPS ها را محاسبه کنید، و با قیمت سرورهای اختصاصی در OVH/Hetzner/LeaseWeb مقایسه کنید. شگفتزده خواهید شد.
- RAM ECC بگیرید، اگر قصد استفاده از ZFS دارید. صرفهجویی نکنید.
- حداقل دو دیسک در آینه بگیرید. یک دیسک — گزینه فروش نیست.
- Proxmox را از طریق KVM/IPMI نصب کنید، نه از طریق rescue + debootstrap. درد کمتری دارد.
- بلافاصله کلیدهای SSH، پورت غیر استاندارد را تنظیم کنید، رمز عبور را غیرفعال کنید، fail2ban را نصب کنید.
- بلافاصله ZFS ARC را محدود کنید. به طور پیشفرض نیمی از RAM شما را میبلعد.
- یک bridge دوم
vmbr1برای شبکه خصوصی با NAT ایجاد کنید. همه VM/LXC ها را به آنجا ببرید. هیچ IP عمومی روی ماشینهای مجازی وجود ندارد. - NetBird (یا Tailscale، یا Headscale) را قبل از شروع مهاجرت راهاندازی کنید. این کانال مهاجرت و دسترسی مدیر شماست.
- Proxmox UI را از بیرون باز نکنید. فقط از طریق mesh VPN.
- یک VPS خروجی کوچک در یک ارائهدهنده دیگر برای TLS-termination و دور زدن مسدودیتها — اجباری نیست، اما بسیار راحت است. هزینه ناچیز است، منافع زیاد.
- PBS در یک LXC جداگانه + همگامسازی offsite به S3. بکآپها باید خودکار باشند.
- حداقل یک بار در ماه restore آزمایشی انجام دهید. در غیر این صورت، شما بکآپ ندارید، بلکه فایلهایی برای آرامش خودتان دارید.
- سرویس به سرویس مهاجرت کنید، به ترتیب افزایش حیاتی بودن. سعی نکنید "همه چیز را در آخر هفته منتقل کنید".
- TTL در DNS را یک روز قبل از تغییر، نه یک ساعت قبل، کاهش دهید.
- مستندات برای هر سرویس بنویسید: پیکربندیها در کجا هستند، چگونه راهاندازی شوند، چگونه بکآپ گرفته شوند، چگونه بازیابی شوند. شش ماه بعد، خودتان از خودتان تشکر خواهید کرد.
آنچه هنوز باید انجام دهم
برای کامل بودن: مهاجرت من هنوز ۱۰۰٪ به پایان نرسیده است. باقی مانده است:
- چند پنل Remnawave از سرور قدیمی (برای آخر هفته آینده برنامهریزی شده است).
- انتقال Caddy با پلاگینها (آنجا یک ساخت سفارشی است)، فعلاً موقتاً کار میکند.
- CrowdSec قدیمی — جداگانه از نو نصب میکنم، منتقل نمیکنم.
اما همه چیزهای حیاتی (انجمنها، صورتحساب، رباتها، پایگاه دادهها) — در حال حاضر روی سرور اختصاصی هستند، پایدار کار میکنند، بکآپ گرفته میشوند و مانیتور میشوند.
اگر سوالی در مورد مراحل خاص، پیکربندیها یا گرههایی که با آنها روبرو شدم به طور مفصلتر دارید — در نظرات بنویسید، سعی خواهم کرد توضیح دهم. به خصوص علاقهمندم بشنوم که چگونه مشکلات مشابهی را روی هایپروایزرهای دیگر (XCP-ng, ESXi، یا کلاً روی Docker Swarm خام) حل میکنید — شاید چیزی را از قلم انداختهام.
موفق باشید در یکپارچهسازی زیرساختهایتان. فاکتورهای کمتر، کنترل بیشتر — این ارزشش را دارد.