Proxmox Backup Server หลัง nginx: แบ็กอัปผ่านพอร์ต 443
หน้าเว็บ PBS ผ่าน nginx ได้ง่าย แต่งานแบ็กอัปใช้โปรโตคอลของตัวเอง ดูวิธีทำ TLS passthrough ด้วย ssl_preread ตั้งพอร์ต 443 ใน Proxmox VE และจัดการ fingerprint ไม่ให้แบ็กอัปพังเงียบๆ
Proxmox Backup Server หลัง nginx ต้องแยกเป็นสองงาน
การวาง Proxmox Backup Server (PBS) ไว้หลัง nginx บนพอร์ต 443 ทำได้ แต่หน้าเว็บกับงานแบ็กอัปต้องใช้วิธีต่างกัน หน้าเว็บบนพอร์ต 8007 เป็น HTTPS ธรรมดา จึงใช้ proxy_pass แบบที่คุณคุ้นเคยได้ ส่วนงานแบ็กอัปและงานกู้คืนใช้โปรโตคอลเฉพาะของ PBS วิธีที่เชื่อถือได้คือให้ nginx ส่ง TLS ต่อไปทั้งก้อนโดยไม่ถอดรหัส เรียกว่า TLS passthrough ผ่านโมดูล stream
คู่มือนี้เขียนให้คนที่มี Proxmox VE (PVE) อยู่ที่บ้านหรือที่ออฟฟิศ แล้วส่งแบ็กอัปไปเก็บนอกสถานที่ที่ PBS บน VPS เครื่อง VPS นั้นมี nginx รับพอร์ต 443 อยู่แล้ว และมีใบรับรองจริงจาก Let's Encrypt สำหรับเว็บอื่น คุณไม่อยากเปิดพอร์ต 8007 ออกอินเทอร์เน็ตเพิ่มอีกพอร์ต ถ้ายังไม่ได้ติดตั้ง PBS ให้เริ่มที่ การติดตั้ง Proxmox Backup Server บน VPS ก่อน
ทุกคอนฟิกในหน้านี้เขียนสำหรับ PBS 4.x และอ้างอิงเอกสาร PBS ชุด 4.2.8-1 PBS 4.0 สร้างบน Debian 13 (trixie) และ ณ เดือนตุลาคม 2026 Debian 13 มี nginx เวอร์ชัน 1.26.3 ในคลังแพ็กเกจ ตัวอย่างสมมติว่า PBS กับ nginx อยู่เครื่องเดียวกัน ถ้าแยกเครื่อง ให้เปลี่ยน 127.0.0.1 เป็น IP ภายในของเครื่อง PBS ชื่อในตัวอย่างมีสามชื่อ คือ pbs.example.com สำหรับงานแบ็กอัป pbs-ui.example.com สำหรับหน้าเว็บ และ datastore ชื่อ store1 ให้เปลี่ยนเป็นชื่อของคุณเอง
ทำไมหน้าเว็บกับงานแบ็กอัปของ PBS จึงต่างกัน
เอกสาร backup protocol ของ PBS อธิบายขั้นตอนไว้ชัด client เริ่มงานแบ็กอัปด้วยคำขอ GET /api2/json/backup และแนบ header UPGRADE: proxmox-backup-protocol-v1 มาด้วย เซิร์ฟเวอร์ตอบกลับด้วย HTTP 101 Switching Protocol หลังจากนั้นการส่งข้อมูลทั้งหมดวิ่งบน HTTP/2 บนการเชื่อมต่อเดิม งานกู้คืนทำแบบเดียวกัน แต่ใช้ชื่อโปรโตคอล proxmox-backup-reader-protocol-v1
แปลว่างานแบ็กอัปไม่ใช่คำขอ HTTPS ทีละคำขอแบบหน้าเว็บ มันคือการเปลี่ยนโปรโตคอลกลางทาง แล้วใช้การเชื่อมต่อเดียวไปจนจบงาน ถ้าอยากเข้าใจว่า HTTP/2 ต่างจาก HTTP/1.1 ตรงไหน อ่าน ความต่างของ HTTP/1.1, HTTP/2 และ HTTP/3 ประกอบได้
nginx ในโหมด http มีพฤติกรรมที่ต้องรู้ เอกสาร nginx บอกว่า Upgrade และ Connection เป็น header แบบ hop-by-hop ซึ่งหมายความว่า nginx จะไม่ส่งต่อให้เซิร์ฟเวอร์ปลายทางเอง คุณต้องสั่งส่งต่ออย่างชัดเจนในคอนฟิก
คู่มือนี้ไม่ได้ทดสอบว่า nginx โหมด http ส่งต่อการ upgrade ของ PBS 4.x ได้ครบหรือไม่ และหน้าเอกสาร backup protocol ของ PBS ก็ไม่ได้พูดถึง reverse proxy เลย เราจึงไม่บอกว่ามันใช้ได้หรือใช้ไม่ได้ ทางที่เชื่อถือได้คือ TLS passthrough เพราะ nginx จะอ่านแค่ชื่อโดเมนจากข้อความเปิด TLS แล้วส่งไบต์ทั้งหมดต่อให้ PBS โดยไม่ถอดรหัส nginx จึงไม่เห็น header และไม่มีทางไปแตะ HTTP/2 ข้างใน
ศัพท์สองคำที่จะเจอบ่อยในหน้านี้ ClientHello คือข้อความแรกที่ client ส่งตอนเริ่ม TLS (transport layer security) ส่วน SNI (server name indication) คือชื่อโดเมนที่ client ใส่มาใน ClientHello ข้อมูลนี้ยังไม่ถูกเข้ารหัส nginx จึงอ่านได้โดยไม่ต้องถือกุญแจของ PBS
ส่วนที่ 1: เปิดหน้าเว็บ PBS ผ่าน nginx แบบ reverse proxy
หน้าเว็บของ PBS ใช้ reverse proxy แบบปกติได้ nginx ถอด TLS ด้วยใบรับรอง Let's Encrypt ของคุณ แล้วส่งต่อไปที่ https://127.0.0.1:8007 ถ้ายังไม่มีใบรับรองสำหรับ pbs-ui.example.com ให้ทำตาม การขอใบรับรอง Let's Encrypt ให้ nginx ด้วย certbot ก่อน และถ้าอยากทบทวนว่าแต่ละบรรทัดใน location ทำงานอย่างไร ดู คำอธิบายคอนฟิก reverse proxy ของ nginx ทีละบรรทัด
สร้างไฟล์ /etc/nginx/conf.d/pbs-ui.conf บน Debian ไฟล์ใน conf.d จะถูกโหลดเข้าไปในบล็อก http { } โดยอัตโนมัติ
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
server_name pbs-ui.example.com;
ssl_certificate /etc/letsencrypt/live/pbs-ui.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/pbs-ui.example.com/privkey.pem;
location / {
proxy_pass https://127.0.0.1:8007;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_read_timeout 1h;
}
}ถ้าคอนฟิกเดิมของคุณมีบล็อก map $http_upgrade $connection_upgrade อยู่แล้ว ให้ลบสี่บรรทัดแรกออก เพราะตัวแปรเดียวกันประกาศซ้ำไม่ได้ และ nginx -t จะไม่ผ่าน
แต่ละบรรทัดมีเหตุผลของมัน
proxy_http_version 1.1จำเป็นบน Debian 13 เพราะ nginx เปลี่ยนค่าเริ่มต้นเป็น 1.1 ตั้งแต่เวอร์ชัน 1.29.7 ก่อนหน้านั้นค่าเริ่มต้นคือ 1.0 ส่วน nginx ของ Debian 13 คือ 1.26.3 จึงยังใช้ 1.0 ถ้าคุณไม่เขียนบรรทัดนี้UpgradeและConnectionต้องส่งต่อเอง เพราะเป็น header แบบ hop-by-hop ใส่ไว้สำหรับหน้าที่อัปเดตแบบสด เช่น log ของ task ที่กำลังทำงานและหน้า shell ถ้าหน้าพวกนี้ค้างหรือว่างเปล่า ขณะที่หน้าอื่นเปิดได้ปกติ ให้ตรวจสองบรรทัดนี้ก่อนproxy_read_timeout 1hแก้ปัญหาการหลุด ค่าเริ่มต้นคือ 60 วินาที ถ้าการเชื่อมต่อไม่มีข้อมูลวิ่งนานเกินนั้น nginx จะปิดทิ้ง หน้าที่เปิดค้างไว้เฉยๆ จึงหลุดproxy_ssl_verifyไม่ได้เขียนไว้ และค่าเริ่มต้นของมันคือoffแปลว่า nginx ไม่ตรวจใบรับรองแบบ self-signed ของ PBS เลย ในตัวอย่างนี้การเชื่อมต่อวิ่งแค่ใน127.0.0.1จึงไม่ออกจากเครื่อง ถ้า PBS อยู่อีกเครื่อง ช่วงระหว่าง nginx กับ PBS จะไม่มีการตรวจตัวตนเซิร์ฟเวอร์ ให้วิ่งช่วงนั้นผ่านอุโมงค์ส่วนตัวแทน
ตรวจคอนฟิกแล้วโหลดใหม่
sudo nginx -t
sudo systemctl reload nginxnginx -t ต้องบอกว่า syntax ok และ test successful จากนั้นเปิด https://pbs-ui.example.com ในเบราว์เซอร์ คุณควรเห็นหน้า login ของ PBS โดยไม่มีคำเตือนเรื่องใบรับรอง เพราะเบราว์เซอร์เห็นใบรับรองของ nginx ไม่ใช่ของ PBS
ส่วนนี้แก้เรื่องหน้าเว็บเท่านั้น อย่าสรุปว่างานแบ็กอัปผ่านชื่อนี้ได้ด้วย เหตุผลอยู่ในหัวข้อการทดสอบด้านล่าง
ส่วนที่ 2: ส่งงานแบ็กอัปผ่านพอร์ต 443 ด้วย TLS passthrough
ส่วนนี้ให้ nginx ฟังพอร์ต 443 ด้วยโมดูล stream ซึ่งพร็อกซีในระดับ TCP แล้วใช้โมดูล ssl_preread อ่าน SNI ถ้าชื่อคือ pbs.example.com nginx จะส่งการเชื่อมต่อทั้งก้อนไปที่ PBS ชื่ออื่นทั้งหมดจะถูกส่งต่อไปที่ส่วน http ของ nginx เอง เว็บเดิมของคุณจึงยังทำงานต่อได้
ตรวจว่า nginx มีโมดูลที่ต้องใช้
เอกสาร nginx บอกว่าโมดูล ssl_preread ไม่ได้ถูกคอมไพล์มาโดยค่าเริ่มต้น ต้องสร้างด้วยตัวเลือก --with-stream_ssl_preread_module บน Debian 13 ส่วน stream แยกอยู่ในแพ็กเกจ libnginx-mod-stream ติดตั้งแล้วตรวจดู
sudo apt install libnginx-mod-stream
nginx -V 2>&1 | grep -o with-stream_ssl_preread_moduleถ้าคำสั่งที่สองพิมพ์ชื่อโมดูลออกมา แปลว่า nginx ตัวนี้มี ssl_preread ถ้าไม่พิมพ์อะไรเลย แปลว่าไม่มี และบรรทัด ssl_preread on; ด้านล่างจะทำให้ nginx -t ฟ้องว่า unknown directive "ssl_preread" กรณีนั้นคุณต้องใช้ nginx ที่สร้างมาพร้อมโมดูลนี้
ย้ายเว็บเดิมออกจากพอร์ต 443
พอร์ต 443 มีเจ้าของได้แค่ฝั่งเดียว เมื่อ stream รับ 443 แล้ว ทุก server block ในส่วน http ที่เคยฟัง 443 ต้องย้ายไปฟังพอร์ตภายใน หาบรรทัดเหล่านั้นก่อน
sudo grep -rn 'listen.*443' /etc/nginx/ทุกบรรทัดที่เจอ ทั้ง listen 443 ssl; และ listen [::]:443 ssl; ให้แทนด้วยบรรทัดเดียวนี้
listen 127.0.0.1:8443 ssl;รวมถึง server block ของ pbs-ui.example.com จากส่วนที่ 1 ด้วย บรรทัด ssl_certificate และทุกอย่างที่เหลือคงไว้เหมือนเดิม เพราะ nginx ฝั่ง http ยังเป็นคนถอด TLS ของเว็บเหล่านี้อยู่
การย้ายนี้มีผลข้างเคียงหนึ่งอย่าง access log ของเว็บเดิมจะเห็น IP ต้นทางเป็น 127.0.0.1 ทุกคำขอ เพราะตอนนี้ผู้ที่เปิดการเชื่อมต่อเข้ามาที่พอร์ต 8443 คือโมดูล stream ของ nginx เอง ถ้าคุณใช้ IP ใน log เพื่อบล็อกผู้โจมตี ให้วางแผนเรื่องนี้ก่อนย้าย การต่ออายุใบรับรองผ่านพอร์ต 80 ไม่ได้รับผลกระทบ เพราะเราไม่ได้แตะพอร์ต 80
เขียนบล็อก stream
บล็อก stream { } ต้องอยู่ระดับบนสุดของคอนฟิก ข้างนอก http { } ไฟล์ใน conf.d และ sites-enabled ของ Debian ถูกโหลดเข้าไปข้างใน http { } จึงใช้ที่นั่นไม่ได้ ให้เพิ่มบล็อกนี้ไว้ท้ายไฟล์ /etc/nginx/nginx.conf
stream {
map $ssl_preread_server_name $tls_upstream {
pbs.example.com 127.0.0.1:8007;
default 127.0.0.1:8443;
}
server {
listen 443;
listen [::]:443;
proxy_pass $tls_upstream;
ssl_preread on;
proxy_timeout 1h;
}
}รูปแบบนี้มาจากตัวอย่างในเอกสาร ssl_preread ของ nginx โดยตรง $ssl_preread_server_name คือชื่อจาก SNI ส่วน map จับคู่ชื่อนั้นกับปลายทาง ชื่อที่ไม่อยู่ในรายการจะไปที่ default คือส่วน http บนพอร์ต 8443 ถ้าเครื่องของคุณไม่มี IPv6 ให้ลบบรรทัด listen [::]:443; ออก
proxy_timeout ของโมดูล stream มีค่าเริ่มต้น 10 นาที ถ้าไม่มีข้อมูลวิ่งในช่วงนั้น nginx จะปิดการเชื่อมต่อ งานแบ็กอัปที่ยาวอาจมีช่วงเงียบ เราจึงตั้งไว้ 1 ชั่วโมง ถ้างานยาวของคุณตายหลังช่วงที่เงียบไปราวสิบนาที ให้ตรวจค่านี้เป็นอย่างแรก
ตรวจคอนฟิกและรีสตาร์ต
sudo nginx -t
sudo systemctl restart nginx
sudo ss -ltnp | grep -E ':443|:8443|:8007'ใช้ restart แทน reload เพราะเรากำลังย้ายเจ้าของพอร์ต 443 จากส่วน http ไปที่ส่วน stream เว็บจะหยุดไม่กี่วินาที ให้ทำนอกเวลางาน ผลของ ss ควรแสดงว่า nginx ฟังพอร์ต 443 และ 127.0.0.1:8443 และ proxmox-backup-proxy ฟังพอร์ต 8007
จากนั้นตรวจว่าแต่ละชื่อไปถูกที่ เว็บเดิมต้องเปิดได้ตามปกติ และชื่อ pbs.example.com ต้องได้ใบรับรองของ PBS ไม่ใช่ของ nginx
curl -sI https://your-existing-site.example.com | head -n 1
openssl s_client -connect pbs.example.com:443 -servername pbs.example.com </dev/null 2>/dev/null | openssl x509 -noout -fingerprint -sha256คำสั่งแรกต้องได้ status line ของเว็บเดิม คำสั่งที่สองพิมพ์ fingerprint แบบ SHA-256 ของใบรับรองที่ปลายทางส่งมา เก็บค่านี้ไว้ เราจะเอาไปเทียบกับค่าที่ PBS รายงานในหัวข้อถัดไป ถ้าทั้งสองค่าตรงกัน แปลว่า passthrough ทำงาน และ nginx ไม่ได้ถอด TLS ของ PBS
ถ้าเปิด https://pbs.example.com ในเบราว์เซอร์ คุณจะเห็นคำเตือนใบรับรอง เพราะเบราว์เซอร์คุยกับ PBS ตรงๆ และได้ใบรับรอง self-signed ของ PBS นี่คือเหตุผลที่เราแยกชื่อ pbs-ui.example.com ไว้สำหรับหน้าเว็บ
fingerprint คือจุดที่ทำให้งานแบ็กอัปพังแบบเงียบๆ
fingerprint คือค่าแฮช SHA-256 ของใบรับรองหนึ่งใบ การปักหมุด fingerprint (pinning) แปลว่าบอก client ให้เชื่อเฉพาะใบรับรองใบนี้ใบเดียว เอกสาร storage ของ PVE บอกว่าค่านี้คือ fingerprint ของใบรับรอง TLS ของ API ของ PBS และเขียนว่า "Required for self-signed certificates or any other one where the host does not trusts the servers CA" แปลว่าต้องใส่เมื่อใบรับรองเป็น self-signed หรือเมื่อเครื่อง PVE ไม่เชื่อถือ CA ที่ออกใบรับรองนั้น
PBS ทุกเครื่องสร้างใบรับรอง self-signed ของตัวเองโดยค่าเริ่มต้น เก็บไว้ที่ /etc/proxmox-backup/proxy.pem และ /etc/proxmox-backup/proxy.key เมื่อใช้ passthrough เครื่อง PVE จะเห็นใบรับรองใบนี้ตรงๆ จึงยังต้องปักหมุดเหมือนตอนต่อพอร์ต 8007 เปิดดูค่าบนเครื่อง PBS ในฐานะ root
proxmox-backup-manager cert infoเทียบ fingerprint ในผลลัพธ์กับค่าที่ได้จาก openssl ในหัวข้อก่อน ต้องเป็นค่าเดียวกัน (ตัวพิมพ์เล็กหรือใหญ่ไม่สำคัญ) ถ้าไม่ตรง แปลว่าชื่อนั้นยังวิ่งไปผิดที่
ทีนี้มาถึงกับดัก ใบรับรองใบใหม่มี fingerprint ใหม่เสมอ แม้จะออกให้ชื่อเดิมจาก CA เดิมก็ตาม เพราะ fingerprint คำนวณจากตัวใบรับรองทั้งใบ pin ที่ใส่ไว้จึงพังทุกครั้งที่ใบรับรองเปลี่ยน เช่น เมื่อคุณสร้างใบรับรองของ PBS ใหม่ หรือติดตั้ง PBS ใหม่ ส่วนถ้าคุณให้ PBS ขอใบรับรองผ่าน ACME (automatic certificate management environment) เอกสาร PBS บอกว่า proxmox-backup-daily-update.service จะต่ออายุให้เมื่อใบรับรองหมดอายุแล้ว หรือจะหมดภายใน 30 วัน ทุกการต่ออายุคือใบใหม่ ซึ่งหมายความว่า fingerprint เปลี่ยนตามรอบต่ออายุ
ผลของการ pin ใบรับรองที่ต่ออายุตามรอบคือ งานแบ็กอัปผ่านทุกคืนจนถึงรอบต่ออายุถัดไป แล้วก็เริ่มล้มเหลวโดยที่ไม่มีใครเปลี่ยนอะไร ถ้าไม่มีใครดูผลงานแบ็กอัป คุณจะรู้ตัวในวันที่ต้องกู้ข้อมูล
กฎที่ใช้ได้จริงมีสองข้อ
- passthrough ไปที่ใบ self-signed ของ PBS: ต้อง pin และ pin ใช้ได้ตราบที่ PBS ยังส่งใบรับรองใบเดิม จดไว้ว่าทุกครั้งที่ใบรับรองของ PBS เปลี่ยน ต้องอัปเดต fingerprint ใน PVE ด้วย และรัน
proxmox-backup-manager cert infoเทียบหลังอัปเกรด PBS ทุกครั้ง - nginx ถอด TLS ด้วยใบรับรองที่ CA เชื่อถือ: ไม่ต้อง pin ตามเอกสาร PVE เพราะเครื่อง PVE ตรวจใบรับรองผ่าน CA ในระบบได้ ฝั่ง
proxmox-backup-clientเอกสารบอกว่าค่าPBS_FINGERPRINTใช้เฉพาะเมื่อ CA ในระบบตรวจใบรับรองไม่ผ่าน แต่เอกสาร PVE ไม่ได้บอกว่าถ้ามี pin ค้างอยู่แล้วจะถูกข้ามหรือไม่ จึงให้ลบ pin ออก อย่ารอไปรู้คำตอบในวันที่ต้องกู้ข้อมูล
PBS เองก็ขอใบรับรอง Let's Encrypt ได้ แต่ถ้าใช้วิธียืนยันผ่าน HTTP เอกสารบอกว่าพอร์ต 80 ต้องเข้าถึงได้จากอินเทอร์เน็ต และต้องไม่มีโปรแกรมอื่นฟังพอร์ต 80 อยู่ บนเครื่องที่ nginx ถือพอร์ต 80 อยู่แล้ว เงื่อนไขนี้จึงไม่ตรง ทางที่ง่ายกว่าคือใช้ใบ self-signed กับ pin ตามกฎข้อแรก
ตั้งพอร์ต 443 ใน Proxmox VE และ proxmox-backup-client
ทั้ง PVE และ client ใช้พอร์ต 8007 เป็นค่าเริ่มต้น เอกสาร PVE เขียนถึงตัวเลือก port ของ storage แบบ PBS ว่า "Use this port instead of the default one, i.e. 8007." ถ้าไม่ตั้งค่านี้ PVE จะพยายามต่อพอร์ต 8007 ซึ่งเราจะปิดจากอินเทอร์เน็ตในภายหลัง
บนเครื่อง PVE ในฐานะ root สมมติว่า storage เดิมชื่อ pbs-offsite ใช้ pvesm set เปลี่ยนชื่อเซิร์ฟเวอร์ พอร์ต และ fingerprint
pvesm set pbs-offsite --server pbs.example.com --port 443 --fingerprint 'AA:BB:...'
pvesm status --storage pbs-offsite
cat /etc/pve/storage.cfgใส่ fingerprint เต็มจาก proxmox-backup-manager cert info แทน AA:BB:... คำสั่ง pvesm status ต้องแสดง storage นี้เป็น active ในไฟล์ storage.cfg ให้ดูว่าใต้บรรทัด pbs: pbs-offsite มีพอร์ต 443 และชื่อเซิร์ฟเวอร์ใหม่จริง ถ้าคุณเพิ่ม storage ใหม่จากหน้าเว็บของ PVE ให้ตรวจไฟล์นี้หลังบันทึกทุกครั้ง เพราะถ้าไม่มีพอร์ต ระบบจะกลับไปใช้ 8007
สำหรับ proxmox-backup-client บนเครื่อง Linux อื่น รูปแบบของ repository คือ [[username@]server[:port]:]datastore ชื่อผู้ใช้ของ PBS มีรูปแบบ user@realm จึงมีเครื่องหมาย @ สองตัวในสตริงเดียว ตัวอย่างนี้ใช้ผู้ใช้ office@pbs
export PBS_REPOSITORY='office@pbs@pbs.example.com:443:store1'
export PBS_FINGERPRINT='AA:BB:...'
proxmox-backup-client login
proxmox-backup-client snapshot listอีกวิธีหนึ่งคือตั้งตัวแปร PBS_PORT=443 แล้วเขียน repository โดยไม่ใส่พอร์ต เอกสารบอกว่า PBS_PORT มีค่าเริ่มต้น 8007 เมื่อไม่ได้ตั้ง ถ้า login ถามรหัสผ่านแล้วผ่าน แปลว่า client ต่อถึง PBS ได้ แต่ยังไม่ได้พิสูจน์ว่างานแบ็กอัปผ่านได้
ทดสอบด้วยงานแบ็กอัปจริง ไม่ใช่แค่ login
login และ snapshot list เป็นคำขอ API แบบ HTTPS ธรรมดา ทั้งสองคำสั่งไม่ได้ใช้การ upgrade ไปเป็น proxmox-backup-protocol-v1 เลย สองคำสั่งนี้จึงผ่านได้แม้ในเส้นทางที่งานแบ็กอัปจะพัง การทดสอบที่มีความหมายต้องมีทั้งแบ็กอัปและกู้คืน เพราะสองงานนี้ใช้โปรโตคอลคนละชื่อ
proxmox-backup-client backup etc.pxar:/etc
proxmox-backup-client snapshot list
proxmox-backup-client restore host/<hostname>/<timestamp> etc.pxar /tmp/restore-test
ls /tmp/restore-test | headคำสั่งแรกสร้าง snapshot ของ /etc บน PBS คัดลอกชื่อ snapshot จาก snapshot list ซึ่งมีรูปแบบเช่น host/office-pc/2026-10-13T02:00:00Z มาใส่ในคำสั่ง restore ถ้า /tmp/restore-test มีไฟล์จาก /etc แปลว่าทั้งขาส่งและขากู้คืนผ่านพร็อกซีได้
ฝั่ง PVE ให้สั่งแบ็กอัปเครื่องเล็กๆ หนึ่งเครื่องในฐานะ root แล้วลองกู้คืนเป็นหมายเลข VM ใหม่จากหน้าเว็บ
vzdump 105 --storage pbs-offsiteเปลี่ยน 105 เป็นหมายเลขของ container หรือ VM ที่เล็กที่สุดที่คุณมี log ของงานต้องจบด้วยสถานะสำเร็จ ถ้างานล้มเหลวเรื่องใบรับรอง ให้กลับไปเทียบ fingerprint อีกครั้ง
ถ้าอยากลองให้ nginx ถอด TLS ทั้งหมด
ถ้าคุณอยากให้ PVE ใช้ใบรับรอง Let's Encrypt และเลิก pin คุณลองชี้ storage ไปที่ชื่อของส่วนที่ 1 ได้ ชื่อนั้นวิ่งผ่าน nginx โหมด http ซึ่งเรายังไม่ได้ยืนยันว่ารองรับโปรโตคอลแบ็กอัปของ PBS 4.x
pvesm set pbs-offsite --server pbs-ui.example.com --port 443 --delete fingerprintจากนั้นทำการทดสอบทั้งหมดในหัวข้อก่อนซ้ำ ทั้งแบ็กอัปและกู้คืน ถ้าผ่านทุกครั้ง คุณใช้ทางนี้ได้ และไม่ต้องกังวลเรื่อง fingerprint ตอนต่ออายุใบรับรอง ถ้าล้มเหลว ให้กลับไปใช้ passthrough ด้วยคำสั่ง pvesm set ชุดเดิม ไม่ว่าผลจะเป็นอย่างไร ให้ทดสอบซ้ำหลังอัปเกรด PBS หรือ nginx ทุกครั้ง เพราะไม่มีเอกสารใดรับรองว่าผลที่ได้วันนี้จะเหมือนเดิมในเวอร์ชันถัดไป
ทางที่ไม่ต้องมีพร็อกซีเลย: Tailscale หรือ WireGuard
เอกสาร client ของ PBS แนะนำทางนี้เอง ในหัวข้อตัวแปรสภาพแวดล้อมมีประโยคว่า "The recommended solution for shielding hosts is using tunnels such as wireguard, instead of using an HTTP proxy." แปลว่าวิธีที่แนะนำในการซ่อนเครื่องคือใช้อุโมงค์อย่าง WireGuard แทน HTTP proxy
แนวคิดคือไม่ให้พอร์ต 8007 ออกอินเทอร์เน็ตเลย เครื่อง PVE กับเครื่อง PBS คุยกันผ่านเครือข่ายส่วนตัว ไม่มี nginx อยู่กลางทาง จึงไม่มีคำถามเรื่อง upgrade หรือ HTTP/2 ให้กังวล ตัวอย่างนี้ใช้ Tailscale ติดตั้งบนทั้งสองเครื่องด้วยสคริปต์ทางการ
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
tailscale ip -4tailscale up จะให้ลิงก์สำหรับล็อกอินเครื่องเข้า tailnet ของคุณ รันคำสั่ง tailscale ip -4 บนเครื่อง PBS เพื่อดู IP ในเครือข่าย Tailscale แล้วชี้ storage ไปที่ IP นั้น และลบค่าพอร์ตออกเพื่อกลับไปใช้ 8007
pvesm set pbs-offsite --server 100.64.0.10 --delete portเปลี่ยน 100.64.0.10 เป็น IP จริงของเครื่อง PBS ใบรับรองยังเป็น self-signed เหมือนเดิม จึงยังต้องมี fingerprint ถ้าออฟฟิศของคุณมีหลายเครื่องที่ต้องคุยกับ PBS และไม่อยากติดตั้ง Tailscale ทุกเครื่อง ดู การตั้ง subnet router ของ Tailscale บน VPS ถ้ายังไม่แน่ใจว่าควรวาง PBS ไว้ที่ไหนตั้งแต่แรก อ่าน การใช้ VPS เป็นที่เก็บแบ็กอัปนอกสถานที่ และ ความต่างระหว่าง Proxmox ที่บ้านกับ VPS
ถ้าใช้ WireGuard เอง หลักการเหมือนกัน ชี้ storage ไปที่ IP ในอุโมงค์ เครื่อง PVE ที่บ้านหรือออฟฟิศมักอยู่หลัง NAT (network address translation) ของเราเตอร์ ให้ตั้ง PersistentKeepalive = 25 ฝั่งเครื่องนั้น ค่าเริ่มต้นของ WireGuard คือปิด และเอกสาร WireGuard บอกว่า 25 วินาทีเป็นค่าที่ใช้ได้กับไฟร์วอลล์หลากหลายแบบ
ปิดพอร์ต 8007 จากอินเทอร์เน็ต
ทุกทางในหน้านี้ถือว่าพอร์ต 8007 ไม่เปิดออกอินเทอร์เน็ต เอกสาร PBS บอกว่า daemon proxmox-backup-proxy เปิด API ทั้งหมดของ PBS บนพอร์ต TCP 8007 ผ่าน HTTPS ถ้าพอร์ตนี้ยังเปิดอยู่ reverse proxy ทั้งหมดก็ไม่ได้ซ่อนอะไรเลย ให้ปิดด้วยไฟร์วอลล์ ตัวอย่างนี้ใช้ ufw
sudo ufw status verbose
sudo ufw delete allow 8007/tcp
sudo ufw allow in on tailscale0 to any port 8007 proto tcpบรรทัดที่สองลบกฎที่เคยเปิด 8007 ให้ทุกคน ถ้าไม่เคยมีกฎนี้ ufw จะแจ้งว่าไม่มีกฎดังกล่าว ซึ่งไม่เป็นปัญหา บรรทัดที่สามใช้เฉพาะเมื่อคุณเลือกทาง Tailscale ถ้าคุณใช้ passthrough บนเครื่องเดียวกัน nginx ต่อ PBS ผ่าน 127.0.0.1 จึงไม่ต้องเปิดพอร์ต 8007 ให้ใครเลย ผู้ให้บริการ VPS หลายรายมีไฟร์วอลล์แยกในแผงควบคุมด้วย ให้ตรวจที่นั่นอีกชั้น
ทดสอบจากเครือข่ายภายนอก เช่น โน้ตบุ๊กที่ต่อเน็ตมือถือ
nc -vz -w 5 pbs.example.com 8007คำสั่งนี้ต้องล้มเหลวหรือหมดเวลา ถ้ามันบอกว่าต่อสำเร็จ พอร์ต 8007 ยังเปิดอยู่ หลังปิดพอร์ตแล้ว ให้รัน proxmox-backup-client snapshot list อีกครั้งเพื่อยืนยันว่าเส้นทางที่คุณเลือกยังใช้ได้
ถ้าอยากจำกัดหน้าเว็บของ PBS ให้เข้าได้เฉพาะเครื่องที่คุณกำหนด อ่าน การบังคับใช้ client certificate ด้วย mTLS บน nginx ได้ วิธีนี้ใช้กับส่วนที่ 1 เท่านั้น เพราะในส่วนที่ 2 nginx ไม่ได้ถอด TLS
FAQ
ทำไม proxmox-backup-client login ผ่าน nginx ได้ แต่งานแบ็กอัปล้มเหลว?
login และ snapshot list เป็นคำขอ HTTPS ธรรมดาไปที่ API ของ PBS ส่วนงานแบ็กอัปเริ่มด้วย GET /api2/json/backup ที่ขอ upgrade เป็น proxmox-backup-protocol-v1 แล้ววิ่งต่อบน HTTP/2 บนการเชื่อมต่อเดิม nginx โหมด http ไม่ส่ง header Upgrade ต่อให้เอง และไม่มีเอกสารของ PBS 4.x ที่ยืนยันว่าเส้นทางนี้ใช้ได้ ให้ใช้ TLS passthrough ด้วยโมดูล stream และ ssl_preread แทน แล้วทดสอบทั้งแบ็กอัปและกู้คืนจริง
ต้องใส่ fingerprint ใน Proxmox VE ไหม ถ้า PBS อยู่หลัง nginx?
ขึ้นกับว่าใครถอด TLS ถ้าใช้ passthrough เครื่อง PVE จะเห็นใบรับรอง self-signed ของ PBS และเอกสาร PVE บอกว่าต้องใส่ fingerprint ดูค่าได้ด้วย proxmox-backup-manager cert info บนเครื่อง PBS ถ้า nginx ถอด TLS ด้วยใบรับรองที่ CA เชื่อถือ ไม่ต้องใส่ และควรลบออกด้วย pvesm set <storage> --delete fingerprint เพราะใบรับรองที่ต่ออายุตามรอบจะได้ fingerprint ใหม่ทุกครั้ง
จะตั้งพอร์ต 443 ให้ storage แบบ PBS ใน Proxmox VE ได้อย่างไร?
PVE ใช้พอร์ต 8007 เป็นค่าเริ่มต้น ให้สั่ง pvesm set <storage> --server pbs.example.com --port 443 บนเครื่อง PVE แล้วตรวจ /etc/pve/storage.cfg ว่ามีพอร์ตใหม่จริง สำหรับ proxmox-backup-client ให้ใส่พอร์ตใน repository เช่น office@pbs@pbs.example.com:443:store1 หรือตั้งตัวแปร PBS_PORT=443
ใช้ nginx stream กับเว็บเดิมบนพอร์ต 443 พร้อมกันได้ไหม?
ได้ แต่ส่วน stream กับส่วน http ฟังพอร์ต 443 พร้อมกันไม่ได้ ให้ stream รับ 443 แล้วใช้ map กับ $ssl_preread_server_name ส่งชื่อของ PBS ไปที่ 127.0.0.1:8007 และส่งชื่ออื่นทั้งหมดไปที่ 127.0.0.1:8443 ซึ่งเป็นพอร์ตใหม่ของ server block เดิม ผลข้างเคียงคือ access log ของเว็บเดิมจะเห็น IP ต้นทางเป็น 127.0.0.1
ควรใช้ reverse proxy หรือ Tailscale/WireGuard กับ Proxmox Backup Server?
ถ้าคุณควบคุมได้ทั้งเครื่อง PVE และเครื่อง PBS อุโมงค์ส่วนตัวเรียบง่ายกว่า เอกสาร client ของ PBS แนะนำอุโมงค์อย่าง WireGuard แทน HTTP proxy พอร์ต 8007 ไม่ต้องออกอินเทอร์เน็ต และไม่มีพร็อกซีอยู่กลางทาง reverse proxy เหมาะเมื่อคุณติดตั้งอะไรเพิ่มบนเครื่องต้นทางไม่ได้ และเหลือพอร์ต 443 เป็นทางเดียว