วิธีติดตั้ง Immich บน VPS ให้เสถียรและอัปเดตอย่างปลอดภัย
คู่มือการใช้งาน Immich บน VPS พร้อมวิธีแก้ปัญหาหน่วยความจำไม่พอจนเกิด exit 137 การตั้งค่า HTTPS ที่พอร์ต 2283 และข้อควรระวังเรื่อง pgvecto.rs เมื่ออัปเกรดเป็นเวอร์ชัน v3
สิ่งที่คุณกำลังสร้าง
Immich คือบริการสำรองข้อมูลรูปภาพและวิดีโอแบบ self-hosted ซึ่งเป็นตัวแทนของ Google Photos ได้อย่างแท้จริง โดยมีแอปพลิเคชันบนมือถือที่คอยอัปโหลดรูปภาพจากกล้องของคุณในเบื้องหลัง มีฟีเจอร์ไทม์ไลน์, อัลบั้ม, การจดจำใบหน้า และการค้นหาด้วย machine-learning ที่สามารถค้นหาคำว่า "ชายหาด" หรือชื่อบุคคลได้โดยที่คุณไม่ต้องติดแท็กใดๆ ทั้งสิ้น คุณสามารถรันบริการนี้บน VPS ของคุณเอง ไฟล์ต้นฉบับจะถูกเก็บไว้ในดิสก์ของคุณ และไม่มีใครสามารถสแกนไฟล์เหล่านั้นเพื่อนำไปใช้ประโยชน์ทางการค้าได้ หากคุณยังลังเลระหว่างตัวเลือกนี้กับตัวเลือกอื่นที่ชัดเจน การเปรียบเทียบ PhotoPrism และ Immich ของเรา ได้แสดงรายละเอียดเปรียบเทียบทั้งการใช้ RAM, แอปมือถือ และคำสั่งสำรองข้อมูลไว้เคียงข้างกัน
การติดตั้งประกอบด้วยคอนเทนเนอร์ 4 ตัวจากไฟล์ Docker Compose ของโปรเจกต์เอง ซึ่งส่วนนี้ใช้เวลาเพียง 10 นาที ส่วนที่เหลือของคู่มือนี้คือจุดที่อาจเกิดปัญหาได้: คอนเทนเนอร์สำหรับ machine-learning ใช้หน่วยความจำสูงมากบนเซิร์ฟเวอร์ขนาดเล็ก, ไฟล์ต้นฉบับใช้พื้นที่ดิสก์อย่างรวดเร็ว, แอปมือถือไม่รองรับเซิร์ฟเวอร์ที่เป็น plain-HTTP และ Immich มักมีการเปลี่ยนแปลงที่อาจส่งผลกระทบ (breaking changes) บ่อยครั้งจนการใช้ docker compose pull โดยไม่ระมัดระวังอาจทำให้ฐานข้อมูลของคุณไม่สามารถเริ่มทำงานได้ หากคุณให้ความสำคัญกับ 4 ประเด็นนี้ Immich จะเป็นระบบที่เสถียรมาก แต่หากคุณละเลย คุณอาจต้องเสียเวลาแก้ไขปัญหาตลอดทั้งสุดสัปดาห์
ข้อกำหนดเบื้องต้นและข้อควรระวังที่สำคัญ
- RAM: เอกสารอย่างเป็นทางการระบุขั้นต่ำไว้ที่ 6 GB และแนะนำที่ 8 GB โดยให้ถือว่า 4 GB รวมกับ swap เป็นขีดจำกัดต่ำสุดที่ยอมรับได้ คอนเทนเนอร์
immich-serverและ Postgres ใช้ทรัพยากรไม่มากนัก แต่คอนเทนเนอร์immich-machine-learningเป็นส่วนที่ใช้ทรัพยากรสูง เนื่องจากต้องโหลดโมเดล CLIP และโมเดลจดจำใบหน้าเข้าสู่ RAM เพื่อสร้างดัชนีการค้นหา หากรันบนเครื่องที่มี RAM 2 GB เคอร์เนลจะสั่งยุติการทำงานของโปรเซสนี้ทันที ควรเพิ่ม swap แม้ว่าคุณจะมี RAM 4 GB ก็ตาม - Disk: จัดสรรพื้นที่ให้ครอบคลุมคลังภาพทั้งหมดของคุณและเผื่อพื้นที่เพิ่ม ไฟล์ต้นฉบับของคุณจะถูกคัดลอกทั้งหมด นอกจากนี้ Immich ยังสร้างภาพขนาดย่อและภาพตัวอย่าง (ใช้พื้นที่เพิ่มประมาณ 10–20%) คลังภาพขนาด 200 GB ควรใช้พื้นที่จัดเก็บข้อมูลอย่างน้อย 300 GB ส่วน Postgres นั้นใช้พื้นที่น้อยกว่ามากเมื่อเทียบกัน
- CPU: VPS แบบ KVM รุ่นใหม่ทั่วไปสามารถใช้งานได้ แต่การประมวลผล ML บน CPU จะทำงานช้า การสร้างดัชนีการค้นหาอัจฉริยะสำหรับการนำเข้าข้อมูลจำนวนมากอาจใช้เวลาทำงานเบื้องหลังนานหลายชั่วโมง ซึ่งเป็นเรื่องปกติและไม่จำเป็นต้องใช้ GPU
- ชื่อโดเมน ที่ชี้ไปยัง VPS แอปบนมือถือต้องการ HTTPS endpoint เป็นอย่างมาก และคุณควรติดตั้ง reverse proxy ไว้ด้านหน้า การตั้งค่านี้มีรูปแบบเดียวกับ การทำ self-hosted Nextcloud ด้วย Docker, TLS และการสำรองข้อมูล โดย Immich เปรียบเสมือนคู่ขนานด้านรูปภาพของเซิร์ฟเวอร์ไฟล์ดังกล่าว
- Docker และ Compose plugin ต้องติดตั้ง Docker Engine และ Compose v2 plugin จาก apt repository ของ Docker โดยตรง ตามที่ระบุไว้ใน คู่มือพื้นฐาน Docker Compose ของเรา
ขั้นตอนที่ 1: เพิ่ม swap ก่อนดำเนินการอื่นใด
สาเหตุที่พบบ่อยที่สุดที่ทำให้ Immich ล้มเหลวบน VPS ขนาดเล็กคือ container ของ ML ถูก OOM-killed ให้จัดสรรพื้นที่ให้ kernel ทำงานได้ก่อนเป็นอันดับแรก
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -hfree -h ควรแสดงบรรทัด Swap: ที่มีค่า 4.0Gi วิธีนี้ไม่ได้ช่วยให้ ML ทำงานเร็วขึ้น แต่จะช่วยป้องกันไม่ให้ container หยุดทำงานระหว่างการทำ index บนเครื่องที่มี RAM 4 GB
ขั้นตอนที่ 2: ดาวน์โหลดไฟล์ compose และ env อย่างเป็นทางการมาใช้งานโดยตรง ห้ามคัดลอกเนื้อหา
Immich กำหนดเวอร์ชันของบริการและที่สำคัญที่สุดคืออิมเมจของฐานข้อมูลไว้ภายในไฟล์ที่แจกจ่ายมา อย่าคัดลอกไฟล์ compose จากบล็อก (รวมถึงบล็อกนี้) มาเป็นแหล่งข้อมูลหลัก ให้ดาวน์โหลด release assets โดยตรง:
sudo mkdir -p /opt/immich && cd /opt/immich
sudo wget -O docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
sudo wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.envไฟล์เหล่านี้มาจาก release ที่มีการระบุแท็กไว้แล้ว ดังนั้นการอ้างอิงอิมเมจจึงตรงกัน ไฟล์ compose กำหนดบริการไว้ 4 รายการ ซึ่งควรทำความเข้าใจหน้าที่ของแต่ละบริการก่อนเริ่มแก้ไข:
immich-server(ghcr.io/immich-app/immich-server, คอนเทนเนอร์immich_server) ทำหน้าที่เป็น API และเว็บ UI โดยฟังคำขอที่พอร์ต2283และทำการ mount ไฟล์ที่คุณอัปโหลดไว้ที่/dataimmich-machine-learning(ghcr.io/immich-app/immich-machine-learning, คอนเทนเนอร์immich_machine_learning) ทำหน้าที่ค้นหาด้วย CLIP และจดจำใบหน้า โดยจะแคชโมเดลที่ดาวน์โหลดมาไว้ใน volumemodel-cacheซึ่งบริการนี้ใช้หน่วยความจำสูงdatabase(คอนเทนเนอร์immich_postgres) คือ Postgres ที่มาพร้อมกับส่วนขยาย VectorChord ซึ่งใช้สำหรับการค้นหาความคล้ายคลึง แท็กของอิมเมจจะถูกล็อกไว้ด้วย digest ภายในไฟล์ compose โดยตรง เช่นghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:...การติดตั้งรุ่นเก่าเคยใช้pgvecto.rsแต่การรองรับถูกยกเลิกไปใน Immich v3.0 ดังนั้นทุกการติดตั้งในปัจจุบันจะเป็น VectorChord ทั้งหมด ห้ามแก้ไขแท็กนี้ด้วยตนเองโดยเด็ดขาดredis(คอนเทนเนอร์immich_redis) คืออินสแตนซ์ของ Valkey/Redis สำหรับจัดการคิวงาน (job queues)
ขั้นตอนที่ 3: กำหนดค่า .env ซึ่งเป็นที่เก็บรูปภาพและฐานข้อมูลของคุณ
เปิดไฟล์ .env และกำหนดค่า 4 รายการ ดังนี้ ทุกสิ่งที่อยู่ใต้บรรทัดที่ระบุไว้ให้คงค่าเดิมไว้
# Where original uploads are stored on the host
UPLOAD_LOCATION=/opt/immich/library
# Where the Postgres data lives. NEVER put this on an NFS/network share.
DB_DATA_LOCATION=/opt/immich/postgres
# "v3" is a floating tag that tracks the latest v3.x. Pin a full tag like
# v3.0.2 instead — then you upgrade on purpose, not by surprise.
IMMICH_VERSION=v3.0.2
# Change this to a long random string. Letters and digits only.
DB_PASSWORD=REPLACE_WITH_A_LONG_RANDOM_STRING
# Set your timezone so timestamps and "on this day" line up
TZ=Europe/London
###################################################################################
DB_USERNAME=postgres
DB_DATABASE_NAME=immichกฎ 2 ข้อที่จะช่วยให้คุณไม่ต้องปวดหัวในภายหลัง UPLOAD_LOCATION ควรชี้ไปยังดิสก์ลูกใหญ่ของคุณ หากคุณจะเชื่อมต่อ data volume ในภายหลัง ให้กำหนดค่านี้เป็น path ที่ mount ไว้ตั้งแต่เริ่มต้น เพราะการย้ายในภายหลังหมายถึงการต้องย้ายไฟล์ thumbnail และอัปเดต path ของ asset ทั้งหมด และ DB_DATA_LOCATION ต้องอยู่บนดิสก์ภายในเครื่องเท่านั้น: การรัน Postgres บน NFS หรือ SMB share จะทำให้ข้อมูลเสียหาย ซึ่งเอกสารระบุไว้ชัดเจน หากคุณใช้เฉพาะตัวอักษรและตัวเลขใน DB_PASSWORD คุณจะหลีกเลี่ยงปัญหาบั๊กที่เกิดจากการ escape อักขระใน connection string ได้
ขั้นตอนที่ 4: การรันครั้งแรกและการสร้างบัญชีผู้ดูแลระบบ
cd /opt/immich
sudo docker compose up -d
sudo docker compose psผลลัพธ์ที่ถูกต้องคือคอนเทนเนอร์จำนวน 4 รายการ ซึ่งทั้งหมดต้องอยู่ในสถานะ running และในที่สุดจะเป็น healthy:
NAME STATUS
immich_machine_learning Up (healthy)
immich_postgres Up (healthy)
immich_redis Up (healthy)
immich_server Up (healthy)การรัน up ครั้งแรกจะมีการดึงอิมเมจขนาดหลายกิกะไบต์ ดังนั้นโปรดรอสักครู่ คุณสามารถติดตามความคืบหน้าได้ด้วย sudo docker compose logs -f immich-server โดยเซิร์ฟเวอร์จะบันทึก log แจ้งว่ากำลังรอรับการเชื่อมต่อที่พอร์ต 2283 เมื่อพร้อมใช้งานแล้ว ให้เปิด http://YOUR_SERVER_IP:2283 ในเว็บเบราว์เซอร์ การเข้าใช้งานครั้งแรกจะแสดงวิซาร์ด Getting Started บัญชีแรกที่คุณสร้างขึ้นจะเป็นบัญชีผู้ดูแลระบบ โปรดตั้งรหัสผ่านที่คาดเดายาก บัญชีนี้จะมีสิทธิ์ในการจัดการการตั้งค่าเซิร์ฟเวอร์ การจัดการผู้ใช้ และการกำหนดค่า ML ที่คุณจำเป็นต้องใช้ในภายหลัง
ขั้นตอนที่ 5: แอปมือถือและการสำรองข้อมูลเบื้องหลัง
ติดตั้ง "Immich" จาก App Store หรือ Play Store บนหน้าจอเข้าสู่ระบบ แอปจะถามหา Server Endpoint URL ให้กรอก URL เต็มรวมถึง scheme เช่น https://photos.example.com (แอปจะต่อท้าย /api ให้เอง) เข้าสู่ระบบด้วยบัญชีที่คุณเพิ่งสร้าง จากนั้นเปิดหน้าจอ Backup ของแอป เลือกอัลบั้มที่ต้องการสำรองข้อมูล (โดยปกติคือ Camera และ Screenshots) และเปิดใช้งาน Background backup การสำรองข้อมูลเบื้องหลังบน iOS จะถูกจำกัดความเร็วโดยระบบปฏิบัติการ การอัปโหลดขณะเปิดแอปจะทำงานทันที ส่วนการสำรองข้อมูลเบื้องหลังจะเกิดขึ้นเมื่อระบบปฏิบัติการอนุญาตเท่านั้น
นี่คือจุดที่ผู้ใช้มักประสบปัญหา ดังนั้นโปรดอ่านขั้นตอนที่ 6 ก่อนที่จะพยายามแก้ไขปัญหาด้วยตัวเองในแอป
ขั้นตอนที่ 6: การใช้งาน HTTPS ผ่าน reverse proxy และกฎของ full-URL
แอปมือถือจำเป็นต้องใช้ HTTPS ให้ตั้ง reverse proxy ไว้หน้า port 2283 และทำ TLS termination ที่จุดนั้น หากใช้งานหลาย container อยู่แล้ว Traefik พร้อม TLS อัตโนมัติสำหรับแอป Docker หลายรายการ เป็นตัวเลือกที่จัดการง่ายที่สุด โดยใช้ label block เพียงชุดเดียวเพื่อส่งเส้นทาง photos.example.com ไปยัง container immich-server และขอ certificate ให้โดยอัตโนมัติ หากต้องการใช้ nginx คู่มือ Let's Encrypt ด้วย Certbot และ nginx จะช่วยออก certificate และสร้าง block proxy_pass http://127.0.0.1:2283; ให้ เมื่อมี proxy แล้ว การเพิ่มบริการถัดไปมักทำเพียงเพิ่ม subdomain ใหม่ นี่เป็นวิธีที่ media front end อย่าง Halcyon skin ร้านวิดีโอยุค 90s สำหรับ Jellyfin สามารถใช้งานอยู่ข้าง Immich บนเครื่องเดียวกันได้ เช่นเดียวกับ HarnessRouter แบบ self-hosted ที่นำ Codex และ Claude Code ไว้หลัง API เดียว ซึ่ง bind กับ loopback โดยตั้งใจ และจะเข้าถึงได้ก็ต่อเมื่อ proxy ทำ TLS termination อยู่ด้านหน้า ดังนั้นให้เปลี่ยน login เริ่มต้นก่อนชี้ subdomain ไปยังบริการนี้ อย่างไรก็ตาม container บางรายการไม่ควรมี public hostname เช่น เครื่องมือสำหรับผู้ดูแลเท่านั้นอย่าง เครื่องมือสแกนความปลอดภัย open-kritt แบบ self-hosted ควรอยู่นอก proxy และเข้าถึงผ่าน SSH tunnel เฉพาะเวลาที่จำเป็นต้องเปิด UI บางบริการไม่ใช้ proxy เพราะไม่ได้สื่อสารด้วย HTTP และ เซิร์ฟเวอร์ relay RustDesk แบบ self-hosted เป็นตัวอย่างที่ชัดเจนที่สุด บริการนี้ฟังอยู่บน raw TCP และ UDP หลายพอร์ต จึงต้องใช้ firewall rules แทน subdomain มีการตั้งค่า proxy รายการหนึ่งที่สำคัญสำหรับ Immich คือต้องเพิ่ม upload size limit เพราะวิดีโอจากโทรศัพท์มีขนาดใหญ่ ใน nginx ให้กำหนด client_max_body_size 50000M; ภายใน server block ค่าเริ่มต้น 1 MB จะปฏิเสธการอัปโหลดวิดีโอด้วย 413 Request Entity Too Large
กฎที่แอปพลิเคชันบังคับใช้คือ endpoint ต้องสามารถเข้าถึงได้ และในทางปฏิบัติจะต้องเป็น HTTPS การใช้ endpoint แบบ http:// หรือการระบุ IP โดยตรงโดยไม่ใส่พอร์ต คือสาเหตุที่ทำให้เกิดข้อความ "แอปไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้" ซึ่งจะอธิบายถึงความล้มเหลวในรูปแบบต่างๆ ไว้ด้านล่างนี้
ขั้นตอนที่ 7: ไลบรารีภายนอกเทียบกับการอัปโหลด และการนำเข้าโครงสร้างรูปภาพที่มีอยู่เดิม
วิธีการนำรูปภาพเข้าสู่ Immich มี 2 รูปแบบ ซึ่งมีความแตกต่างกันดังนี้:
- การอัปโหลด (Uploads) คือสินทรัพย์ที่ Immich เป็นเจ้าของ แอปพลิเคชันหรือตัวอัปโหลดบนเว็บจะคัดลอกไฟล์เข้าไปยัง
UPLOAD_LOCATIONโดย Immich สามารถเปลี่ยนชื่อ ย้าย และลบไฟล์เหล่านี้ได้ - ไลบรารีภายนอก (External libraries) คือการนำเข้าไฟล์แบบอ่านได้อย่างเดียว (read-only) ซึ่งไฟล์เหล่านั้นถูกจัดเก็บอยู่ในโฟลเดอร์บนเซิร์ฟเวอร์ของคุณอยู่แล้ว เช่น โครงสร้าง
Picturesแบบเก่า หรือการแชร์ไฟล์จาก NAS โดย Immich จะทำดัชนีไฟล์เหล่านั้นในตำแหน่งเดิมและแสดงผลในไทม์ไลน์ แต่จะไม่แก้ไขหรือลบไฟล์ต้นฉบับโดยเด็ดขาด
ในการนำเข้าโครงสร้างไฟล์ที่มีอยู่เดิม ให้ทำการ mount โฟลเดอร์ดังกล่าวแบบอ่านได้อย่างเดียวเข้าไปในคอนเทนเนอร์ของเซิร์ฟเวอร์ จากนั้นแก้ไขไฟล์ docker-compose.yml ภายใต้ immich-server: และเพิ่ม volume ดังนี้:
immich-server:
volumes:
- ${UPLOAD_LOCATION}:/data
- /etc/localtime:/etc/localtime:ro
- /srv/photos:/mnt/media/photos:roการตั้งค่า :ro ช่วยรับประกันว่า Immich จะไม่สามารถแก้ไขไฟล์ต้นฉบับได้ ให้สร้างคอนเทนเนอร์ขึ้นใหม่ด้วยคำสั่ง sudo docker compose up -d จากนั้นในหน้าเว็บ UI ให้ไปที่รูปโปรไฟล์ของคุณ → Administration → External Libraries → Create Library เลือกผู้ใช้ที่เป็นเจ้าของ คลิก Add ภายใต้หัวข้อ Folders แล้วระบุ path ภายใน คอนเทนเนอร์ คือ /mnt/media/photos ไม่ใช่ path บนโฮสต์คือ /srv/photos จากนั้นคลิก Scan การใช้ path บนโฮสต์แทน path ภายในคอนเทนเนอร์เป็นข้อผิดพลาดที่พบบ่อยที่สุดในการตั้งค่าไลบรารีภายนอก ซึ่งจะส่งผลให้การสแกนไม่พบไฟล์ใดๆ และรายงานจำนวนสินทรัพย์เป็นศูนย์
ขั้นตอนที่ 8: วินัยในการอัปเกรดที่ Immich ต้องการ
นี่คือส่วนที่แยกความแตกต่างระหว่าง Immich ที่ทำงานได้ราบรื่นกับที่พังเสียหาย Immich มีการออกเวอร์ชันใหม่ที่รวดเร็วและไม่มีการ backport การแก้ไขหรือรองรับการ downgrade การติดตาม tag v3 แบบสุ่มสี่สุ่มห้าจะทำให้ฐานข้อมูลของคุณเสียหายในที่สุด นิสัยในการล็อกเวอร์ชันแล้วอ่านบันทึกการเปลี่ยนแปลงก่อนอัปเกรดเป็นสิ่งที่ควรใช้กับ container ทุกตัวที่รันอยู่บนเซิร์ฟเวอร์ ซึ่งเป็นเหตุผลว่าทำไม agent ของ KiroCrew ที่ self-host ไว้จึงถูกล็อกไว้ที่ tag ที่ใช้งานได้ดี แทนที่จะปล่อยให้มันอัปเดตเองโดยอัตโนมัติเมื่อมีการรีสตาร์ท วินัยที่ต้องปฏิบัติมีดังนี้:
- ล็อกเวอร์ชันไว้: ตั้งค่า
IMMICH_VERSIONให้เป็น tag ที่ระบุชัดเจน เช่นv3.0.2ไม่ใช่ใช้ tagv3ที่จะดึงเวอร์ชัน v3.x ล่าสุดมาตลอด - อ่านบันทึกการเปลี่ยนแปลง (release notes) ทุกครั้ง ก่อนทำการอัปเกรด การเปลี่ยนแปลงที่อาจส่งผลกระทบ (breaking changes) โดยเฉพาะการเปลี่ยนแปลงเกี่ยวกับฐานข้อมูลหรือ vector-extension จะถูกระบุไว้ในนั้น ตัวอย่างที่ชัดเจนคือการปล่อยเวอร์ชัน v3.0 ซึ่งได้ถอด pgvecto.rs ออกไปโดยสิ้นเชิง ดังนั้นผู้ที่ยังใช้ extension เดิมอยู่จะต้องดำเนินการย้ายข้อมูล VectorChord (ซึ่งเปิดตัวตั้งแต่ v1.133) ให้เสร็จสิ้นก่อนที่จะอัปเกรดได้
- สำรองข้อมูลฐานข้อมูลก่อนเสมอ (ขั้นตอนที่ 9) ต้องทำทุกครั้ง และต้องทำเป็นสองเท่าหากบันทึกการเปลี่ยนแปลงระบุถึงฐานข้อมูล
- ดาวน์โหลดไฟล์ compose ใหม่มาด้วย
IMMICH_VERSIONจะล็อกเฉพาะ image ของ server และ ML เท่านั้น ส่วน image ของ Postgres จะถูกล็อกด้วย digest ภายในdocker-compose.ymlดังนั้นเวอร์ชันที่ต้องการ extension ฐานข้อมูลใหม่จะมาพร้อมกับไฟล์ compose ใหม่เสมอ ให้ดาวน์โหลด release assets ทั้งสองไฟล์ใหม่ แล้วนำค่า.envของคุณไปใส่ จากนั้นจึงค่อยทำการอัปเกรด - อัปเดตแอปบนมือถือในช่วงเวลาใกล้เคียงกัน เซิร์ฟเวอร์จะสื่อสารได้เฉพาะกับแอปเวอร์ชัน major ที่ตรงกันเท่านั้น และแอปจะรองรับเวอร์ชันปัจจุบันและเวอร์ชันก่อนหน้าหนึ่งเวอร์ชัน หากเซิร์ฟเวอร์อัปเกรดไปไกลกว่าแอป คุณจะเห็น
Your app major version is not compatible with the server!บนโทรศัพท์จนกว่าจะอัปเดตแอป ดังนั้นวิธีที่ปลอดภัยที่สุดคือการอัปเดตแอปก่อน
คำสั่งที่ใช้จริงเมื่อคุณเตรียมไฟล์ใหม่ไว้เรียบร้อยแล้ว:
cd /opt/immich
sudo docker compose pull
sudo docker compose up -d
sudo docker image pruneขั้นตอนที่ 9: การสำรองข้อมูล, การดัมพ์ฐานข้อมูลรวมถึงไฟล์ต้นฉบับ และการทดสอบ
การสำรองข้อมูล Immich ประกอบด้วยสองส่วน และหากขาดส่วนใดส่วนหนึ่งไปจะใช้งานไม่ได้ ฐานข้อมูล (database) จะเก็บโครงสร้างอัลบั้ม, ใบหน้า, ดัชนีการค้นหา และแผนผังความสัมพันธ์ระหว่างไฟล์กับข้อมูล ส่วน ไดเรกทอรีต้นฉบับ (originals directory) จะเก็บไฟล์รูปภาพจริง หากกู้คืนเพียงส่วนใดส่วนหนึ่ง คุณจะได้เพียงรูปภาพที่ไม่มีการจัดระเบียบ หรือได้เพียงโครงสร้างเปล่าที่ชี้ไปยังไฟล์ที่หายไป รูปแบบสองส่วนนี้ไม่ใช่เรื่องแปลกสำหรับ Immich: ระบบสนับสนุน Chatwoot ที่โฮสต์เอง ก็ต้องการการจับคู่ระหว่างการดัมพ์ Postgres กับไดเรกทอรี uploads เช่นกัน มิฉะนั้นกล่องข้อความที่กู้คืนมาจะไม่มีไฟล์แนบ การคัดลอกไดเรกทอรีข้อมูล Postgres ทั้งกิ่งดูเหมือนจะเป็นทางลัดแทนการดัมพ์ข้อมูล แต่ไม่ใช่การสำรองข้อมูลที่ใช้งานได้จริง ซึ่งเป็นกับดักที่ คู่มือการสำรองและกู้คืน Immich ฉบับสมบูรณ์ ได้อธิบายไว้ เพื่อป้องกันความผิดพลาดที่อาจทำให้คุณเหลือเพียงไทม์ไลน์ที่ว่างเปล่า
ให้ดัมพ์ฐานข้อมูลด้วย pg_dump จากภายในคอนเทนเนอร์ Postgres โดยระบุเฉพาะฐานข้อมูล immich เท่านั้น ไม่ใช่ทั้งคลัสเตอร์:
sudo docker exec -t immich_postgres pg_dump --clean --if-exists \
--dbname=immich --username=postgres | gzip > /opt/immich/immich-db-$(date +%F).sql.gzจากนั้นให้สำรองข้อมูล UPLOAD_LOCATION, โครงสร้าง /opt/immich/library ทั้งหมด โดยเฉพาะโฟลเดอร์ย่อย library/, upload/ และ profile/ ด้วย restic, rsync หรือ borg ไปยังเครื่องอื่นหรือ object storage ไม่ว่าคุณจะใช้ตารางเวลาใด ไม่ว่าจะเป็น cron entry หรือ systemd timer ระบบจำเป็นต้องมีช่องทางแจ้งเตือนเมื่อการสำรองข้อมูลล้มเหลว การใช้ systemd OnFailure= unit ที่เชื่อมต่อกับ เซิร์ฟเวอร์ ntfy ของคุณเอง จะช่วยส่งข้อความแจ้งเตือนไปยังโทรศัพท์ของคุณในคืนที่การดัมพ์ข้อมูลเกิดปัญหา แทนที่จะปล่อยให้คุณมารู้ตัวในตอนที่ต้องกู้คืนข้อมูล ให้เริ่มจากการสำรองฐานข้อมูลก่อนแล้วจึงสำรองไฟล์ เพื่อให้การดัมพ์ข้อมูลไม่อ้างอิงถึงรูปภาพที่ยังไม่ได้คัดลอก สำหรับ external libraries ให้สำรองข้อมูลแยกต่างหากจากแหล่งที่มาจริง เนื่องจาก Immich ไม่ได้เป็นเจ้าของไฟล์เหล่านั้น
ตอนนี้มาถึงส่วนที่ทุกคนมักข้ามไป: การทดสอบการกู้คืน การกู้คืนต้องทำบน stack ที่ สะอาด ซึ่งเซิร์ฟเวอร์ยังไม่เคยเริ่มทำงาน และบนอิมเมจ Postgres ที่มี vector extension เข้ากันได้กับไฟล์ดัมพ์ ซึ่งเป็นเหตุผลว่าทำไมคุณจึงไม่ควรเปลี่ยน tag ของอิมเมจฐานข้อมูลโดยพลการ บนเครื่องทดสอบที่ใช้ compose และ .env เดียวกัน ให้ล้างสถานะเก่าออกทั้งหมด เริ่มการทำงานเฉพาะฐานข้อมูล จากนั้นจึงโหลดไฟล์ดัมพ์:
cd /opt/immich
sudo docker compose down -v
sudo docker compose pull
sudo docker compose create
sudo docker start immich_postgres
sleep 10
gunzip --stdout immich-db-2026-07-15.sql.gz |
sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" |
sudo docker exec -i immich_postgres psql --dbname=immich --username=postgres --single-transaction --set ON_ERROR_STOP=on
sudo docker compose up -dการเขียนทับ sed ของ search_path เป็นสิ่งที่จำเป็นสำหรับฐานข้อมูล VectorChord หากข้ามขั้นตอนนี้ไป การกู้คืนจะหยุดชะงักกลางคัน เมื่อ stack เริ่มทำงานใหม่พร้อมกับไฟล์ต้นฉบับของคุณ ให้เปิด web UI หากรูปภาพและอัลบั้มของคุณปรากฏขึ้น แสดงว่าการสำรองข้อมูลของคุณใช้งานได้จริง หากคุณไม่เคยทดสอบขั้นตอนนี้ คุณไม่ได้มีระบบสำรองข้อมูล คุณมีเพียงความหวังเท่านั้น
รูปแบบความล้มเหลวและข้อความที่คุณจะพบ
คอนเทนเนอร์ ML ถูก OOM-killed sudo docker compose logs immich-machine-learning สิ้นสุดลงกะทันหัน docker compose ps แสดงสถานะ Restarting และ exit code คือ 137 คำสั่ง sudo dmesg | grep -i oom ยืนยันสาเหตุด้วย Out of memory: Killed process ... (python3) งานค้นหาและงานวิเคราะห์ใบหน้าจะค้าง สาเหตุเกิดจาก RAM ไม่เพียงพอสำหรับโมเดล วิธีแก้ไขตามลำดับคือ: เพิ่ม swap (ขั้นตอนที่ 1); เพิ่ม RAM ให้กับ VPS; หรือหากไม่สามารถทำได้จริง ให้ปิดการใช้งาน ML ใน Administration → Settings → Machine Learning Settings โดยปิด Smart Search และ Facial Recognition คุณจะยังคงสำรองข้อมูลและอัลบั้มได้ แต่จะสูญเสียความสามารถในการค้นหาด้วยเนื้อหา การลบบริการ immich-machine-learning ออกจากไฟล์ compose จะให้ผลลัพธ์เช่นเดียวกัน
Postgres ไม่ยอมเริ่มทำงานหลังการอัปเกรด log ของเซิร์ฟเวอร์วนซ้ำด้วยบรรทัดเช่น The database currently has VectorChord 0.5.3 activated, but the Postgres instance only has 0.4.2 available. This most likely means the extension was downgraded. หรือใน stack รุ่นเก่าคือ The pgvecto.rs extension is not available in this Postgres instance. สาเหตุเกิดจากอิมเมจฐานข้อมูลที่มีเวอร์ชัน extension เก่ากว่าข้อมูลที่คุณอัปเกรดไป ซึ่งมักเกิดจากการแก้ไข image tag ด้วยตนเองหรือการกู้คืน dump รุ่นใหม่ลงในอิมเมจรุ่นเก่า วิธีแก้ไขคือใช้อิมเมจ Postgres ที่ตรงกัน ใช้ไฟล์ compose จาก release ที่ตรงกับฐานข้อมูลของคุณ ห้ามทำการ downgrade และกู้คืนข้อมูลลงบนอิมเมจที่เข้ากันได้เท่านั้น
แอปมือถือไม่สามารถเข้าถึงเซิร์ฟเวอร์ได้ หน้าจอเข้าสู่ระบบแสดงข้อผิดพลาดการเชื่อมต่อ / Server is not reachable หลังจากที่คุณกรอก URL มี 3 สาเหตุ: คุณพิมพ์ http:// ในขณะที่พร็อกซีให้บริการเฉพาะ https://; คุณเชื่อมต่อตรงไปยัง backend แต่ไม่ได้ระบุพอร์ต ทำให้ระบบพยายามเชื่อมต่อที่ example.com (พอร์ต 443) แทนที่จะเป็น example.com:2283; หรือ reverse proxy ไม่ได้ส่งต่อ /api วิธีแก้ไขคือกรอก URL แบบเต็ม https://photos.example.com และตรวจสอบให้แน่ใจว่าสามารถโหลดผ่านเบราว์เซอร์บนมือถือได้ก่อน หากเบราว์เซอร์ใช้งานได้แต่แอปใช้งานไม่ได้ แสดงว่าพร็อกซีอาจตัด path ออก หรือใบรับรองเป็นแบบ self-signed ซึ่งแอปจะปฏิเสธใบรับรองที่ไม่น่าเชื่อถือ
พื้นที่ดิสก์เต็มระหว่างการนำเข้าข้อมูล การอัปโหลดเริ่มล้มเหลว รูปภาพตัวอย่าง (thumbnails) ว่างเปล่า และ log แสดง ENOSPC: no space left on device หรือจาก Postgres คือ could not extend file ... No space left on device คำสั่ง df -h แสดงว่าโวลุ่ม UPLOAD_LOCATION เต็ม 100% นี่คือเหตุผลที่คุณต้องกำหนดขนาดดิสก์ก่อนนำเข้าคลังข้อมูลขนาดใหญ่ กู้คืนระบบโดยการเชื่อมต่อโวลุ่มที่ใหญ่ขึ้น หยุดการทำงานของ stack ย้าย UPLOAD_LOCATION ไปยังโวลุ่มใหม่ อัปเดต .env แล้วเริ่มทำงานใหม่ หรือขยายดิสก์ที่มีอยู่หากผู้ให้บริการของคุณรองรับ Postgres อาจค้างได้หากพื้นที่เต็ม ดังนั้นควรเคลียร์พื้นที่และรีสตาร์ทคอนเทนเนอร์ฐานข้อมูลก่อนที่จะสรุปว่าข้อมูลเสียหาย
FAQ
Immich ต้องการ RAM และพื้นที่ดิสก์เท่าใด
ข้อกำหนดอย่างเป็นทางการของ Immich คือ RAM ขั้นต่ำ 6 GB และแนะนำที่ 8 GB โดยมี 4 GB พร้อม swap เป็นเกณฑ์ขั้นต่ำสำหรับการใช้งานจริงกับคลังภาพขนาดเล็ก ควรตั้งค่า swap ไว้เสมอเนื่องจากคอนเทนเนอร์ machine-learning เป็นส่วนที่ใช้ทรัพยากรสูง สำหรับพื้นที่ดิสก์ ให้เตรียมพื้นที่เท่ากับขนาดคลังภาพทั้งหมดของคุณบวกเพิ่มอีกประมาณ 10–20% สำหรับ thumbnail และ preview ที่ถูกสร้างขึ้น โดยต้องเก็บไว้บน local storage เท่านั้น ห้ามนำ Postgres data directory ไปไว้บน network share หากคุณกำลังตัดสินใจว่าจะรันบริการอื่นใดเพิ่มเติม คู่มือสิ่งที่ควร self-host ในปี 2026 ได้แสดงการใช้ทรัพยากรของ Immich เทียบกับบริการอื่นๆ ไว้
ฉันสามารถรัน Immich โดยไม่มี GPU ได้หรือไม่
ได้ คอนเทนเนอร์ machine-learning สามารถทำงานบน CPU ได้ตามปกติ GPU จะช่วยเพิ่มความเร็วในการทำดัชนี smart-search และการแปลงรหัสวิดีโอ (หากใช้ image variant ที่เหมาะสม) เท่านั้น ในกรณีที่ใช้ CPU การทำดัชนีเริ่มต้นสำหรับคลังภาพขนาดใหญ่อาจใช้เวลาหลายชั่วโมงในเบื้องหลัง แต่จะไม่ขัดขวางการสำรองข้อมูลหรือการเรียกดูภาพ หากเครื่องของคุณมีขนาดเล็กเกินกว่าจะรัน ML ได้ คุณสามารถปิดใช้งาน Smart Search และ Facial Recognition ได้ในการตั้งค่าผู้ดูแลระบบโดยที่ฟังก์ชันอื่นยังคงใช้งานได้ปกติ
ฉันจะอัปเกรด Immich อย่างปลอดภัยได้อย่างไร
ให้ตรึง (pin) IMMICH_VERSION ไว้ที่ tag เฉพาะเจาะจง เช่น v3.0.2 อ่านบันทึกประจำรุ่น (release notes) ก่อนการอัปเกรดทุกครั้ง และสำรองข้อมูลฐานข้อมูลก่อนเสมอ เนื่องจากอิมเมจ Postgres ถูกตรึงไว้ภายใน docker-compose.yml แทนที่จะใช้ IMMICH_VERSION คุณจึงต้องดาวน์โหลดทั้งไฟล์ compose และ example.env จากรุ่นที่คุณต้องการ แล้วนำค่าคอนฟิกของคุณไปใส่ใหม่ จากนั้นจึงรัน docker compose pull && docker compose up -d ห้ามปล่อยให้เวอร์ชันอัปเดตโดยอัตโนมัติโดยไม่มีการตรวจสอบ เพราะ Immich มีการเปลี่ยนแปลงที่อาจส่งผลกระทบ (breaking changes) และไม่รองรับการย้อนกลับเวอร์ชัน (downgrade)
ฉันต้องสำรองข้อมูลส่วนใดบ้าง
สองส่วนควบคู่กัน: pg_dump ของฐานข้อมูล immich และไดเรกทอรีต้นฉบับ UPLOAD_LOCATION ทั้งหมด ฐานข้อมูลจะเก็บข้อมูลอัลบั้ม ใบหน้า และการจับคู่ระหว่าง asset กับไฟล์ ส่วนไดเรกทอรีจะเก็บไฟล์ภาพจริง การกู้คืนข้อมูลจำเป็นต้องใช้ทั้งสองส่วนรวมถึงอิมเมจฐานข้อมูลที่มี vector extension ที่เข้ากันได้ ให้ทำการ dump ฐานข้อมูลก่อนแล้วจึงคัดลอกไฟล์ และทดสอบการกู้คืนบนเครื่องทดสอบอย่างน้อยหนึ่งครั้ง การสำรองข้อมูลที่ไม่ได้ผ่านการทดสอบถือว่าไม่ใช่การสำรองข้อมูล
ฉันจะนำเข้าโฟลเดอร์รูปภาพที่มีอยู่เดิมได้อย่างไร
ให้ mount โฟลเดอร์ดังกล่าวแบบอ่านอย่างเดียว (read-only) เข้าไปในคอนเทนเนอร์ immich-server ในฐานะ volume เพิ่มเติม (ตัวอย่างเช่น - /srv/photos:/mnt/media/photos:ro) สร้างคอนเทนเนอร์ใหม่ จากนั้นไปที่ Administration → External Libraries เพื่อสร้าง library และเพิ่ม path ของ container คือ /mnt/media/photos Immich จะทำดัชนีไฟล์จากตำแหน่งนั้นโดยตรงและไม่มีการแก้ไขหรือลบไฟล์ต้นฉบับ ข้อผิดพลาดที่พบบ่อยที่สุดคือการใส่ path ของ host แทนที่จะเป็น path ของ container ซึ่งจะทำให้การสแกนไม่พบไฟล์ใดๆ