คำตอบสั้น ๆ: ตั้งค่า listen_addresses และ pg_hba.conf ให้ PostgreSQL รับการเชื่อมต่อจากภายนอกเฉพาะ IP ที่อนุญาต ใช้ scram-sha-256 และ SSL พร้อมตั้ง Firewall ให้สอดคล้องกัน
คู่มือนี้อธิบาย PostgreSQL ทีละขั้นตอน พร้อมคำสั่งที่ใช้ได้จริงและปัญหาที่พบบ่อย
ค่าเริ่มต้นของ PostgreSQL รับการเชื่อมต่อจากภายในเครื่องเท่านั้น เมื่อแอปพลิเคชันอยู่คนละเซิร์ฟเวอร์กับฐานข้อมูล หรือต้องให้ระบบรายงานจากสำนักงานดึงข้อมูล ต้องปรับค่าสองส่วน คือ listen_addresses ใน postgresql.conf เพื่อให้ PostgreSQL ฟังบน Network Interface ภายนอก และ pg_hba.conf เพื่อกำหนดว่าใครเชื่อมต่อจาก IP ใด เข้าฐานข้อมูลใด และยืนยันตัวตนด้วยวิธีใด
บทความนี้แสดงวิธีเปิดการเชื่อมต่อแบบจำกัดเฉพาะ IP ที่ไว้ใจได้ ใช้รหัสผ่านแบบ scram-sha-256 และบังคับเข้ารหัส SSL พร้อมตั้ง Firewall ให้สอดคล้องกัน
สิ่งที่ต้องเตรียม
- PostgreSQL 14 ขึ้นไปที่ติดตั้งแล้ว ตาม ติดตั้ง PostgreSQL และสร้างผู้ใช้บน Ubuntu หรือบน AlmaLinux/Rocky Linux
- สิทธิ์
sudoบนเซิร์ฟเวอร์ฐานข้อมูล - IP สาธารณะแบบคงที่ของเครื่องที่จะเชื่อมต่อเข้ามา ตัวอย่างในบทความใช้
198.51.100.25และเซิร์ฟเวอร์ฐานข้อมูลคือ203.0.113.10 - Role และฐานข้อมูลที่จะใช้ ตัวอย่างคือ
appuserและappdb
หมายเหตุ: ถ้าผู้ที่ต้องเข้าถึงคือผู้ดูแลระบบที่ต้องการเปิดดูข้อมูลเป็นครั้งคราว ไม่ใช่แอปพลิเคชัน ไม่จำเป็นต้องเปิดพอร์ต 5432 สู่ภายนอกเลย ใช้ SSH Tunnel ด้วย DBeaver แทนจะปลอดภัยกว่า
ขั้นตอนที่ 1: หาตำแหน่งไฟล์ตั้งค่า
ตำแหน่งไฟล์ต่างกันตามระบบปฏิบัติการ วิธีที่แน่นอนที่สุดคือถามจาก PostgreSQL เอง
sudo -u postgres psql -c "SHOW config_file;" -c "SHOW hba_file;"
| ระบบ | ตำแหน่งโดยทั่วไป |
|---|---|
| Ubuntu (แพ็กเกจของ Ubuntu หรือ PGDG) | /etc/postgresql/16/main/postgresql.conf และ pg_hba.conf ในโฟลเดอร์เดียวกัน |
| AlmaLinux/Rocky (แพ็กเกจของ OS) | /var/lib/pgsql/data/ |
| AlmaLinux/Rocky (แพ็กเกจ PGDG) | /var/lib/pgsql/16/data/ |
สำรองไฟล์ทั้งสองก่อนแก้ไข (แทนพาธด้วยค่าที่ได้จากคำสั่งข้างบน)
sudo cp /etc/postgresql/16/main/postgresql.conf /etc/postgresql/16/main/postgresql.conf.bak
sudo cp /etc/postgresql/16/main/pg_hba.conf /etc/postgresql/16/main/pg_hba.conf.bak
ขั้นตอนที่ 2: ตั้ง listen_addresses
เปิด postgresql.conf แล้วหาบรรทัด listen_addresses (ค่าเริ่มต้นถูก Comment ไว้และมีค่าเป็น localhost) แก้เป็น
listen_addresses = 'localhost,203.0.113.10'
การระบุ IP ของเซิร์ฟเวอร์เองจะฟังเฉพาะ Interface นั้น ถ้าเซิร์ฟเวอร์มีหลาย IP หรือ IP อาจเปลี่ยน ใช้ '*' เพื่อฟังทุก Interface ได้ แล้วให้ pg_hba.conf และ Firewall เป็นตัวจำกัดสิทธิ์ ค่านี้ต้อง รีสตาร์ต จึงมีผล การ Reload อย่างเดียวไม่พอ
sudo systemctl restart postgresql
บน AlmaLinux/Rocky ชื่อ Service อาจเป็น postgresql หรือ postgresql-16 ตามแหล่งที่ติดตั้ง ตรวจว่าฟังพอร์ตถูกต้องแล้ว
sudo ss -ltnp | grep 5432
ควรเห็นบรรทัดที่มี 203.0.113.10:5432 หรือ 0.0.0.0:5432 (ดูเพิ่มเติมที่ ตรวจสอบพอร์ตที่เปิดอยู่บน Linux ด้วย ss และ lsof)
ขั้นตอนที่ 3: เพิ่มกฎใน pg_hba.conf
แต่ละบรรทัดใน pg_hba.conf มี 5 คอลัมน์หลัก
| คอลัมน์ | ตัวอย่าง | ความหมาย |
|---|---|---|
| TYPE | hostssl | local คือ Socket, host คือ TCP ทั้งแบบเข้ารหัสและไม่เข้ารหัส, hostssl คือ TCP ที่เข้ารหัส SSL เท่านั้น |
| DATABASE | appdb | ชื่อฐานข้อมูล ใช้ all ได้แต่ไม่แนะนำ |
| USER | appuser | ชื่อ Role |
| ADDRESS | 198.51.100.25/32 | IP หรือช่วง IP ในรูปแบบ CIDR, /32 คือ IP เดียว |
| METHOD | scram-sha-256 | วิธียืนยันตัวตน ไม่ควรใช้ trust หรือ password กับการเชื่อมต่อจากภายนอก |
เพิ่มบรรทัดนี้ไว้ท้ายไฟล์
# แอปพลิเคชันจากเซิร์ฟเวอร์ 198.51.100.25
hostssl appdb appuser 198.51.100.25/32 scram-sha-256
PostgreSQL อ่านกฎจากบนลงล่างและใช้ บรรทัดแรกที่ตรงเงื่อนไข ทันที ถ้ามีกฎที่กว้างกว่าอยู่ด้านบน เช่น บรรทัดที่ปฏิเสธ (reject) ช่วง IP เดียวกัน กฎของคุณจะไม่ถูกใช้
ต่อมา Reload ค่า ซึ่งไม่ตัดการเชื่อมต่อที่มีอยู่
sudo systemctl reload postgresql
# หรือจากใน psql
sudo -u postgres psql -c "SELECT pg_reload_conf();"
ตรวจว่า PostgreSQL อ่านไฟล์ได้โดยไม่มีบรรทัดผิดรูปแบบ คอลัมน์ error ต้องว่างทุกแถว
sudo -u postgres psql -c "SELECT line_number, type, database, user_name, address, auth_method, error FROM pg_hba_file_rules;"