คู่มือ · ทดสอบเมื่อสิงหาคม 2026 บน Batocera v43

ROM ของ Batocera บน NAS ผ่าน NFS

กล่อง Batocera ของคุณมีดิสก์ที่สักวันจะเต็ม NAS ของคุณมีที่ว่าง คู่มือนี้ย้ายระบบที่คุณเลือกไปไว้บนแชร์ในเครือข่าย แล้วทำ symlink กลับมาที่เดิม Batocera จึงไม่รู้ถึงความต่าง — และครอบคลุมสองเรื่องที่พังเป็นประจำ: สิทธิ์ไฟล์ที่ทำให้เซฟพังแบบเงียบ ๆ และ boot hook ที่เปลี่ยนไประหว่างเวอร์ชัน

ทำไมต้องใช้ symlink แทนการย้ายทั้งหมด

Batocera วาง /userdata ทั้งหมดไว้บนแชร์เครือข่ายได้ แต่นั่นคือการตัดสินใจแบบทั้งหมดหรือไม่มีเลย ซึ่งทำให้คอนฟิก เซฟ และภาพปกที่ดึงมาไปอยู่หลังเครือข่ายด้วย การทำ symlink ทีละโฟลเดอร์ระบบยืดหยุ่นกว่า: ระบบใหญ่ที่กินพื้นที่หลายร้อยกิกะไบต์อยู่บน NAS ส่วนระบบเล็กที่ไวต่อความหน่วงอยู่บนดิสก์ในเครื่อง และกล่องยังบูตและเล่นได้แม้ NAS ปิดอยู่

หลักง่าย ๆ: ระบบที่ใช้แผ่นอยู่บน NAS — PS2, GameCube, Wii, Dreamcast, PSX, PS3 — เพราะใหญ่มาก และอ่านข้อมูลก้อนใหญ่ต่อเนื่องซึ่งเครือข่ายกิกะบิตรับได้สบาย ระบบยุคตลับอยู่ในเครื่อง — NES, SNES, Mega Drive, Game Boy, อาร์เคด — เพราะเล็กจนไม่มีผล และตอนดึงภาพปกจะโหลดไฟล์จิ๋วนับพัน ซึ่งเป็นงานที่เครือข่ายทำได้แย่ที่สุดพอดี

ก่อนเริ่ม

ตลอดคู่มือนี้ NAS คือ 192.168.1.10 กล่อง Batocera คือ 192.168.1.20 โฟลเดอร์ที่ export คือ /srv/batocera และถูกเมานต์บน Batocera ที่ /media/nas เปลี่ยนเป็นของคุณเอง — แต่ให้จุดเมานต์อยู่ใต้ /media และอ่านหมายเหตุเรื่องนี้ในขั้นที่ 6 ก่อนจะเลือกอะไรแปลก ๆ

ขั้นที่ 1 — สร้างและ export แชร์

บน NAS ที่เป็น Linux ธรรมดา สร้างโฟลเดอร์แล้วเพิ่มบรรทัด export

บน NAS
mkdir -p /srv/batocera
echo "/srv/batocera 192.168.1.20(rw,sync,no_subtree_check,no_root_squash,insecure)" >> /etc/exports
exportfs -ra
exportfs -v

no_root_squash คือตัวเลือกที่สำคัญ Batocera รันทุกอย่างเป็น root ตามค่าเริ่มต้น NFS จะแปลงผู้ใช้ root จากระยะไกลเป็น nobody — ROM จึงอ่านได้ปกติแต่การเขียนจะล้มเหลว ถ้าคุณย้ายเซฟมาไว้บนแชร์ทีหลัง มันจะหยุดบันทึกแบบเงียบ ๆ โฟลเดอร์ ROM แบบอ่านอย่างเดียวรอดจากการ squash แต่อะไรที่ต้องเขียนไม่รอด

บน NAS ที่มีหน้าเว็บ ให้หาค่าตั้งที่เทียบเท่าแทนการแก้ไฟล์ด้วยมือ — Unraid เรียกว่า NFS rule ใต้ Share Settings, Synology มีดรอปดาวน์ "Squash" ที่ต้องตั้งเป็น No mapping และ TrueNAS มีฟิลด์ "Maproot User" ที่ต้องตั้งเป็น root

อย่าเชื่อหน้าเว็บ — ตรวจสอบเอง หน้าเว็บของ NAS เพิ่มและเขียนตัวเลือก export ใหม่ในแบบที่มองไม่เห็นในหน้าค่าตั้ง และแชร์สองตัวที่ตั้งค่าเหมือนกันอาจมีตัวเลือกที่ใช้งานจริงต่างกัน มีแค่ exportfs -v บน NAS ที่แสดงสิ่งที่เคอร์เนลบังคับใช้จริง ตรวจตอนนี้ และตรวจอีกครั้งหลังเปลี่ยนค่าตั้งของแชร์ทุกครั้งในอนาคต

ขั้นที่ 2 — เมานต์ด้วยมือและพิสูจน์ว่าใช้ได้

อย่าทำการเมานต์ให้อัตโนมัติก่อนที่คุณจะเคยทำมันด้วยมือ

บน Batocera
mkdir -p /media/nas
mount -t nfs -o rw,soft,timeo=150,retrans=2 192.168.1.10:/srv/batocera /media/nas
mount | grep /media/nas

คุณควรได้บรรทัดที่แสดงการเมานต์และตัวเลือกที่ตกลงกันได้ ถ้าการเมานต์ถูกปฏิเสธด้วยข้อผิดพลาดเรื่องโปรโตคอลหรือสิทธิ์ ให้เพิ่ม nfsvers=3 ในตัวเลือก — NAS บางรุ่น export เฉพาะ v3 และบางรุ่นวาง export ของ v4 ไว้ใต้ pseudo-root ซึ่งทำให้พาธเปลี่ยน

เกี่ยวกับตัวเลือกเหล่านั้น soft หมายความว่าคำขอที่ค้างจะคืนข้อผิดพลาดในที่สุดแทนการค้างตลอดไป บนเครื่องเล่นเกมนั่นคือสิ่งที่คุณต้องการ เพราะการเมานต์แบบ hard จะทำให้หน้าจอค้างไปเรื่อย ๆ ถ้า NAS หายไป timeo มีหน่วยเป็นหนึ่งในสิบวินาที timeo=150 จึงเท่ากับ 15 วินาที — กับ retrans=2 คำขอที่ล้มเหลวจะยอมแพ้หลังราว 30 วินาที

ขั้นที่ 3 — ยืนยันว่า root เขียนได้จริง

ใช้เวลาสิบวินาที และจับการตั้งค่าผิดที่พบบ่อยที่สุดได้

บน Batocera
touch /media/nas/.writetest && echo WRITE-OK || echo WRITE-FAILED
stat -c '%U:%G %a' /media/nas/.writetest
rm /media/nas/.writetest
touch ที่สำเร็จไม่ได้พิสูจน์ว่าคุณไม่ถูก squash ถ้าโฟลเดอร์แม่เขียนได้ทุกคน การเขียนก็สำเร็จอยู่ดี — แล้วทุกไฟล์ที่อีมูเลเตอร์สร้างจะเป็นของ nobody ซึ่งพังแบบสับสนในภายหลัง ผลของ stat ต้องเป็น root:root ถ้าเป็น nobody ให้กลับไปขั้นที่ 1 แปลว่า no_root_squash ไม่ได้ถูกใช้งาน

ขั้นที่ 4 — คัดลอก ROM ไปยังแชร์

คัดลอก ตรวจสอบ แล้วจึงลบต้นฉบับ

บน Batocera
rsync -aH --info=progress2 /userdata/roms/ps2/ /media/nas/ps2/
du -sh /userdata/roms/ps2 /media/nas/ps2

เครื่องหมายทับท้ายพาธสำคัญ — /ps2/ ทั้งสองฝั่งคัดลอกเนื้อในไปยังปลายทาง แทนการซ้อนโฟลเดอร์ไว้ข้างใน การเทียบ du ควรได้ยอดรวมที่ตรงกัน

สำหรับคลังขนาดใหญ่ ให้รันการคัดลอกภายใต้ nohup เพื่อให้รอดแม้เซสชัน SSH หลุด Batocera ไม่มี tmux หรือ screen มาให้

บน Batocera — สำหรับการคัดลอกที่ใช้เวลานาน
nohup rsync -aH --partial --info=progress2 /userdata/roms/ps2/ /media/nas/ps2/ > /userdata/romcopy.log 2>&1 &

tail -c 300 /userdata/romcopy.log
pgrep -a rsync || echo FINISHED

ขั้นที่ 5 — แทนที่โฟลเดอร์ด้วย symlink

เปลี่ยนชื่อแทนการลบ เพื่อให้ย้อนกลับได้ด้วยคำสั่งเดียว

บน Batocera
for SYS in ps2 gamecube wii dreamcast psx; do
  [ -d "/media/nas/$SYS" ] || continue
  mv "/userdata/roms/$SYS" "/userdata/roms/$SYS.local-backup"
  ln -s "/media/nas/$SYS" "/userdata/roms/$SYS"
done

ls -la /userdata/roms | grep media/nas

โฟลเดอร์ของแต่ละระบบตอนนี้เป็น symlink เข้าไปในแชร์ EmulationStation ตามมันไปโดยไม่รู้และไม่สนใจ เมื่อคุณบูตและยืนยันว่าเกมครบแล้ว ให้ลบโฟลเดอร์ .local-backup เพื่อเอาพื้นที่คืน

ตรวจหา symlink ที่ปลายทางชี้ไม่ถึง — โฟลเดอร์ที่คัดลอกไม่สำเร็จจะโผล่ตรงนี้ แทนที่จะเป็นระบบที่ว่างเปล่าอย่างลึกลับในหน้าจอ:

บน Batocera
for d in /userdata/roms/*; do [ -L "$d" ] && [ ! -e "$d" ] && echo "BROKEN: $d"; done

ทางเลือก — เซฟและข้อมูลอีมูเลเตอร์

เคล็ดลับเดียวกันใช้กับ /userdata/saves ได้ ซึ่งสะดวกถ้าคุณเล่นเกมเดียวกันบนหลายเครื่อง แต่ก็เพิ่มเดิมพันขึ้นมาก: เซฟถูกเขียนตลอดเวลา จึงสมเหตุสมผลเฉพาะเมื่อขั้นที่ 3 ผ่านอย่างสะอาด และการเมานต์ตอนบูตในขั้นที่ 6 เชื่อถือได้แล้ว

บน Batocera
mkdir -p /media/nas/saves
rsync -aH /userdata/saves/ /media/nas/saves/
mv /userdata/saves /userdata/saves.local-backup
ln -s /media/nas/saves /userdata/saves
รูปแบบความล้มเหลวที่ต้องเข้าใจก่อนทำ ถ้าแชร์ไม่ถูกเมานต์ตอนบูต /media/nas ก็ยังมีอยู่เป็นโฟลเดอร์ว่าง symlink จึงชี้ไปยังพาธว่างที่ดูถูกต้อง เกมจะเขียนเซฟลงพื้นที่ในเครื่อง และคุณจะมีเซฟสองชุดที่แยกทางกัน อีมูเลเตอร์แบบแยกบางตัว — รวมถึง RPCS3 และ Dolphin — ไปไกลกว่านั้นโดยสร้างคอนฟิกเปล่าทับลงไป นี่คือเหตุผลที่สคริปต์บูตในขั้นถัดไปลองซ้ำ แทนการพยายามเมานต์ครั้งเดียว

ขั้นที่ 6 — ให้เมานต์ทุกครั้งที่บูต

ส่วนที่คู่มือส่วนใหญ่ทำผิด เพราะ Batocera เปลี่ยนมัน

ระบบไฟล์รูทของ Batocera เป็นอิมเมจ squashfs แบบอ่านอย่างเดียวที่มี overlay ชั่วคราวอยู่ด้านบน อะไรที่เขียนนอก /userdata และ /boot จะถูกทิ้งตอนรีบูต /etc/fstab จึงใช้ไม่ได้ — มันไม่รอด Batocera มีฮุกของตัวเองให้แทน และฮุกที่คุณใช้ขึ้นกับเวอร์ชันของคุณ

ฮุกทำงานเมื่อใช้กับการเมานต์เครือข่ายได้ไหม?
/boot/boot-custom.sh
v32+
เป็นอย่างแรกหลัง init.d เริ่มทำงานไม่ได้ — ระบบเครือข่ายยังไม่พร้อม
/boot/postshare.sh
v35+
หลัง /userdata ถูกเมานต์ ก่อนวิดีโอเปิดตัวและ EmulationStationได้ — นี่คือตัวที่ถูกต้อง
/userdata/system/custom.sh
เลิกใช้ตั้งแต่ v38
หลังจาก EmulationStation เปิดไปแล้วไม่ได้ — เลิกใช้แล้ว และช้าเกินไปอยู่ดี
/userdata/system/services/<name>
แนะนำตั้งแต่ v43
จาก S99userservices หลัง EmulationStation เปิดแล้วใช้เป็นทางสำรองเท่านั้น — ดูด้านล่าง
ถ้าคุณเจอคู่มือเก่าที่บอกให้ใช้ custom.sh นั่นน่าจะเป็นเหตุผลที่แชร์ของคุณไม่เมานต์ มันถูกเลิกใช้ตั้งแต่ v38 และบน v43 เราพบว่ามันไม่เคยทำงานเลย — ไฟล์อยู่ตรงนั้น ถูกต้องและรันได้ แต่ไม่เคยถูกเรียก ไม่มีข้อความแจ้งข้อผิดพลาด ระบบ services มาแทนมัน แต่ services เริ่มหลังจาก EmulationStation สแกนโฟลเดอร์ ROM แล้ว แชร์ที่เมานต์ตรงนั้นจึงมาช้าเกินไป และทุกระบบบนเครือข่ายจะแสดงว่างจนกว่าคุณจะรีสตาร์ตหน้าจอ postshare.sh ทำงานก่อนการสแกน ซึ่งคือสิ่งที่คุณต้องการจริง ๆ

/boot ถูกเมานต์แบบอ่านอย่างเดียว จึงต้องเมานต์ใหม่ให้เขียนได้ก่อน — และตั้งกลับหลังจากนั้น

บน Batocera
mount -o remount,rw /boot

cat > /boot/postshare.sh <<'EOF'
#!/bin/sh
MNT=/media/nas
SRV=192.168.1.10:/srv/batocera

mkdir -p "$MNT"
n=0
while [ $n -lt 15 ]; do
  grep -q " $MNT nfs" /proc/mounts && exit 0
  mount -t nfs -o rw,soft,timeo=150,retrans=2 "$SRV" "$MNT" 2>/dev/null && exit 0
  n=$((n+1))
  sleep 2
done

mkdir -p /userdata/system/logs
echo "$(date) NAS mount FAILED" >> /userdata/system/logs/nas-mount.log
EOF

mount -o remount,ro /boot

ทำไมสคริปต์ถึงเขียนแบบนั้น

รูปแบบท้ายบรรทัด ถ้าคุณเขียนสคริปต์เหล่านี้บน Windows ให้บันทึกด้วยท้ายบรรทัดแบบ Unix (LF) ไฟล์ที่ท้ายบรรทัดเป็น CRLF จะไม่ทำงาน และอีกครั้ง จะไม่บอกคุณว่าทำไม การแก้ไขผ่าน SSH ตามที่แสดงข้างบนหลีกเลี่ยงปัญหานี้ได้ทั้งหมด

ทางสำรอง — วิธีใช้ services

ถ้า postshare.sh ไม่ทำงานบนเวอร์ชันของคุณ ให้ใช้ service แทน ชื่อไฟล์ต้องไม่มีนามสกุล และมีเฉพาะตัวอักษร ตัวเลข และขีดล่าง เพราะ services เริ่มหลัง EmulationStation ให้เพิ่มการรีสตาร์ตหน้าจอไว้ท้าย หรือยอมรีสตาร์ตด้วยมือครั้งหนึ่งหลังบูต

บน Batocera
mkdir -p /userdata/system/services

cat > /userdata/system/services/nasmount <<'EOF'
#!/bin/bash
MNT=/media/nas
SRV=192.168.1.10:/srv/batocera

case "$1" in
  start)
    mkdir -p "$MNT"
    grep -q " $MNT nfs" /proc/mounts || \
      mount -t nfs -o rw,soft,timeo=150,retrans=2 "$SRV" "$MNT"
    ;;
  stop)
    umount -l "$MNT" 2>/dev/null
    ;;
esac
EOF

chmod +x /userdata/system/services/nasmount
batocera-services enable nasmount
batocera-services list user

ขั้นที่ 7 — รีบูตแล้วตรวจสอบ

ตรวจจากบรรทัดคำสั่งก่อนจะแตะหน้าจอ

บน Batocera หลังรีบูต
mount | grep /media/nas
cat /userdata/system/logs/nas-mount.log 2>/dev/null
ls /userdata/roms/ps2 | head

บรรทัดการเมานต์ ไม่มีไฟล์ล็อก และรายการเกม คือผลที่สะอาด ถ้ามีไฟล์ล็อก แปลว่าสคริปต์ทำงานแต่การเมานต์ล้มเหลว — ตรวจว่า NAS ตื่นอยู่ และกล่อง Batocera ยังมีที่อยู่ IP ตรงกับกฎ export ของคุณ

จากนั้นปล่อยให้ EmulationStation โหลด แล้วยืนยันว่าระบบบนเครือข่ายแสดงเกม ระบบที่แสดงว่างทั้งที่โฟลเดอร์แสดงรายการได้ถูกต้อง คือแคชรายการเกมที่ค้าง ไม่ใช่ปัญหาการเมานต์ — อัปเดตรายการเกมของระบบนั้นจากหน้าจอ

การแก้ปัญหา

อาการสาเหตุที่น่าจะเป็น
แชร์หายไปหลังรีบูตทุกครั้ง แต่เมานต์ด้วยมือได้ปกติใช้ boot hook ผิดสำหรับเวอร์ชันของคุณ — แทบแน่นอนว่าคุณใช้ custom.sh ย้ายไปใช้ postshare.sh
โฟลเดอร์จุดเมานต์ไม่มีอยู่หลังรีบูตปกติ /media เป็นระบบไฟล์ชั่วคราว สคริปต์บูตต้องสร้างมันใหม่
เกมโหลดได้ แต่เซฟไม่ถูกเก็บแบบเงียบ ๆการ squash ของ root ตรวจด้วย exportfs -v บน NAS และการทดสอบ stat ในขั้นที่ 3
การบูตค้างที่จอดำหลังเพิ่มสคริปต์ลูปลองซ้ำที่ไม่จำกัดใน postshare.sh มันไม่ได้ทำงานเบื้องหลัง — การบูตรอมัน
สคริปต์ไม่เคยทำงานและไม่แสดงข้อผิดพลาดท้ายบรรทัดแบบ CRLF ของ Windows หรือชื่อไฟล์ผิด ทั้งสองล้มเหลวแบบเงียบ ๆ
mount.nfs: access denied by serverกฎ export ไม่ตรงกับ IP ปัจจุบันของกล่อง หรือ NAS ของคุณต้องใช้ nfsvers=3
หน้าจอค้างขณะเลื่อนดูระบบบนเครือข่ายส่วนใหญ่คือการโหลดภาพปกผ่านเครือข่าย ถ้ายังเป็นอยู่ ให้ตรวจ dmesg บนกล่อง Batocera — ความผิดพลาดของไดรฟ์ USB ในเครื่องแสดงอาการเหมือนกันทุกอย่าง และโทษแชร์ผิดได้ง่าย
ทุกอย่างทำงานจนกว่า NAS จะรีบูต แล้วค้างคุณใช้การเมานต์แบบ hard ใช้ soft พร้อม timeo ที่มีขอบเขต

การถอยกลับ

ไม่มีอะไรที่นี่ที่ย้อนกลับไม่ได้

บน Batocera
SYS=ps2
rm /userdata/roms/$SYS
mv /userdata/roms/$SYS.local-backup /userdata/roms/$SYS

ลบ /boot/postshare.sh ด้วยวิธีเดียวกับที่สร้าง — เมานต์ /boot ใหม่ให้เขียนได้ ลบ แล้วเมานต์กลับเป็นอ่านอย่างเดียว ROM บน NAS ไม่ถูกแตะต้องจากขั้นตอนใดเลย

อ้างอิง

ทดสอบตั้งแต่ต้นจนจบเมื่อสิงหาคม 2026 กับ Batocera v43 และแชร์ NFSv4.2 พฤติกรรมเฉพาะเวอร์ชันถูกระบุไว้ในจุดที่เราเจอ ถ้าขั้นตอนใดทำงานต่างไปบนบิลด์ของคุณ ตารางจังหวะเวลาของฮุกข้างบนคือที่แรกที่ควรดู