ลดความยุ่งยากในการใช้คลาวด์ พูดคุยกับเจ้าหน้าที่

Home เปิดให้เชื่อมต่อ MySQL/MariaDB จากภายนอกอย่างปลอดภัย

เปิดให้เชื่อมต่อ MySQL/MariaDB จากภายนอกอย่างปลอดภัย

ค่าเริ่มต้นของ MySQL และ MariaDB บน Ubuntu จะรับการเชื่อมต่อจากเครื่องตัวเองเท่านั้น ซึ่งปลอดภัยที่สุดสำหรับเว็บไซต์ที่แอปกับฐานข้อมูลอยู่เครื่องเดียวกัน แต่บางกรณีจำเป็นต้องเชื่อมต่อจากภายนอก เช่น ใช้โปรแกรมจัดการอย่าง MySQL Workbench, DBeaver หรือ HeidiSQL จากคอมพิวเตอร์ในออฟฟิศ หรือแยกเซิร์ฟเวอร์แอปกับเซิร์ฟเวอร์ฐานข้อมูลออกจากกัน

พอร์ต 3306 ที่เปิดสู่อินเทอร์เน็ตทั้งหมดจะถูกสแกนและเดารหัสผ่านตลอดเวลา คู่มือนี้จึงเสนอสองวิธีตามลำดับความปลอดภัย วิธีที่ 1 คือ SSH Tunnel ซึ่งไม่ต้องเปิดพอร์ตฐานข้อมูลเลย และวิธีที่ 2 คือเปิดพอร์ตเฉพาะ IP ที่อนุญาต

สิ่งที่ต้องเตรียม

  • สิทธิ์ sudo บนเซิร์ฟเวอร์ฐานข้อมูล และสิทธิ์ root ของ MySQL/MariaDB
  • IP สาธารณะของเครื่องที่จะเชื่อมต่อเข้ามา ควรเป็น IP คงที่ ตรวจได้จากเว็บไซต์ตรวจ IP หรือคำสั่ง curl -4 ifconfig.me บนเครื่องนั้น ตัวอย่างในคู่มือใช้ 203.0.113.10
  • MySQL 8 หรือ MariaDB 10.x บน Ubuntu 22.04/24.04 หรือ AlmaLinux/Rocky Linux 8-9

วิธีที่ 1 (แนะนำ): เชื่อมต่อผ่าน SSH Tunnel

SSH Tunnel ส่งการเชื่อมต่อฐานข้อมูลผ่านช่อง SSH ที่เข้ารหัสอยู่แล้ว ฐานข้อมูลยังฟังเฉพาะ 127.0.0.1 เหมือนเดิม และไม่ต้องแก้ Firewall เหมาะกับผู้ดูแลที่เข้าไปจัดการฐานข้อมูลเป็นครั้งคราว

บนเครื่องของคุณ (Linux, macOS หรือ Windows 10/11 ที่มี OpenSSH) เปิด Terminal แล้วรัน

ssh -N -L 3307:127.0.0.1:3306 user@IP-ของเซิร์ฟเวอร์

คำสั่งนี้เปิดพอร์ต 3307 บนเครื่องของคุณ แล้วส่งต่อไปยังพอร์ต 3306 ของเซิร์ฟเวอร์ผ่าน SSH ปล่อยหน้าต่างนี้เปิดไว้ระหว่างใช้งาน จากนั้นในโปรแกรมจัดการฐานข้อมูลให้เชื่อมต่อไปที่ Host 127.0.0.1 พอร์ต 3307 ด้วยผู้ใช้ฐานข้อมูลที่มี Host เป็น localhost หรือ 127.0.0.1 ตามที่สร้างไว้ในเซิร์ฟเวอร์

โปรแกรมอย่าง MySQL Workbench, DBeaver และ HeidiSQL มีตัวเลือก "Standard TCP/IP over SSH" หรือแท็บ SSH ให้ใส่ข้อมูล SSH ได้ในหน้าตั้งค่าการเชื่อมต่อโดยตรง ซึ่งให้ผลแบบเดียวกัน

วิธีที่ 2: เปิดพอร์ต 3306 เฉพาะ IP ที่อนุญาต

ใช้เมื่อแอปบนเซิร์ฟเวอร์อีกเครื่องต้องเชื่อมต่อตลอดเวลา ถ้าทั้งสองเครื่องอยู่ในเครือข่ายภายใน (Private Network) เดียวกัน ให้ใช้ IP ภายในแทน IP สาธารณะทุกจุด

ขั้นตอนที่ 1: แก้ bind-address ให้รับการเชื่อมต่อจากภายนอก

ตำแหน่งไฟล์ตั้งค่าต่างกันตามระบบ

ระบบไฟล์
Ubuntu + MariaDB/etc/mysql/mariadb.conf.d/50-server.cnf
Ubuntu + MySQL 8/etc/mysql/mysql.conf.d/mysqld.cnf
AlmaLinux/Rocky + MariaDB/etc/my.cnf.d/mariadb-server.cnf
AlmaLinux/Rocky + MySQL 8/etc/my.cnf.d/mysql-server.cnf

หาบรรทัด bind-address = 127.0.0.1 ในส่วน [mysqld] แล้วเปลี่ยนเป็น IP ของเซิร์ฟเวอร์ที่ต้องการให้รับการเชื่อมต่อ หรือ 0.0.0.0 เพื่อรับทุก Interface ของ IPv4

[mysqld]
bind-address = 0.0.0.0

บน AlmaLinux และ Rocky Linux ไฟล์มักไม่มีบรรทัด bind-address ซึ่งหมายความว่าฐานข้อมูลฟังทุก Interface อยู่แล้ว และอาศัย firewalld ปิดพอร์ตไว้ ในกรณีนั้นไม่ต้องแก้ไฟล์ ให้ข้ามไปขั้นตอนที่ 2

รีสตาร์ตบริการ ชื่อบริการขึ้นอยู่กับระบบ

sudo systemctl restart mariadb     # MariaDB ทุก Distro
sudo systemctl restart mysql       # MySQL บน Ubuntu
sudo systemctl restart mysqld      # MySQL บน AlmaLinux / Rocky Linux

ตรวจว่าฟังพอร์ตแล้ว

sudo ss -tlnp | grep 3306

ผลลัพธ์ต้องเห็น 0.0.0.0:3306 หรือ IP ที่กำหนด แทนที่จะเป็น 127.0.0.1:3306

ขั้นตอนที่ 2: สร้างผู้ใช้ที่เชื่อมต่อได้จาก IP ที่กำหนดเท่านั้น

sudo mysql
CREATE USER 'appremote'@'203.0.113.10' IDENTIFIED BY 'รหัสผ่านที่แข็งแรง';
GRANT SELECT, INSERT, UPDATE, DELETE ON shopdb.* TO 'appremote'@'203.0.113.10';

ระบุ IP ต้นทางใน Host ของผู้ใช้เสมอ หลีกเลี่ยง '%' ซึ่งหมายถึงเชื่อมต่อได้จากทุกที่ และอย่าเปิดให้ root เชื่อมต่อจากภายนอก ดูรายละเอียดเรื่องสิทธิ์เพิ่มเติมที่ สร้างฐานข้อมูลและผู้ใช้ MySQL/MariaDB พร้อมกำหนดสิทธิ์

ขั้นตอนที่ 3: อนุญาตพอร์ต 3306 เฉพาะ IP ต้นทางใน Firewall

Ubuntu ที่ใช้ UFW

sudo ufw allow from 203.0.113.10 to any port 3306 proto tcp
sudo ufw status numbered

AlmaLinux และ Rocky Linux ที่ใช้ firewalld

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10" port port="3306" protocol="tcp" accept'
sudo firewall-cmd --reload
sudo firewall-cmd --list-rich-rules

ห้ามใช้ ufw allow 3306 หรือ --add-port=3306/tcp แบบไม่ระบุต้นทาง เพราะจะเปิดให้ทั้งอินเทอร์เน็ต หากเซิร์ฟเวอร์มี Security Group หรือ Firewall ภายนอกจากฝั่งผู้ให้บริการ ให้เปิดพอร์ตนั้นเพิ่มด้วย โดยจำกัดต้นทางเป็น IP เดียวกัน ดูพื้นฐาน Firewall เพิ่มที่ ตั้งค่า Firewall ด้วย UFW บน Ubuntu และ ตั้งค่า Firewall ด้วย firewalld บน AlmaLinux และ Rocky Linux

ขั้นตอนที่ 4: บังคับใช้การเชื่อมต่อแบบเข้ารหัส

ข้อมูลและรหัสผ่านที่วิ่งผ่านอินเทอร์เน็ตควรเข้ารหัสด้วย TLS เสมอ MySQL 8 สร้างใบรับรองและเปิด TLS ให้อัตโนมัติ จึงบังคับให้ผู้ใช้ต้องใช้ TLS ได้ทันที

ALTER USER 'appremote'@'203.0.113.10' REQUIRE SSL;

MariaDB 10.x ไม่ได้เปิด TLS ไว้เป็นค่าเริ่มต้น ตรวจได้ด้วย SHOW VARIABLES LIKE 'have_ssl'; ถ้าได้ DISABLED ต้องสร้างใบรับรองและกำหนด ssl_cert, ssl_key และ ssl_ca ในไฟล์ตั้งค่าก่อน ตามเอกสาร "Securing Connections for Client and Server" ของ MariaDB มิฉะนั้นผู้ใช้ที่ตั้ง REQUIRE SSL จะเชื่อมต่อไม่ได้ หากยังไม่พร้อมตั้งค่า TLS ให้ใช้วิธีที่ 1 แทน

ตรวจสอบผลลัพธ์

จากเครื่องต้นทาง (203.0.113.10) ทดสอบว่าพอร์ตเปิด

nc -zv IP-ของเซิร์ฟเวอร์ฐานข้อมูล 3306

ควรได้ข้อความ succeeded หรือ Connected จากนั้นเชื่อมต่อจริง

mysql -h IP-ของเซิร์ฟเวอร์ฐานข้อมูล -u appremote -p shopdb

เมื่อเข้าได้แล้ว ตรวจว่าการเชื่อมต่อเข้ารหัสอยู่

SHOW SESSION STATUS LIKE 'Ssl_cipher';

คอลัมน์ Value ต้องมีชื่อ Cipher เช่น TLS_AES_256_GCM_SHA384 ถ้าว่างแปลว่ายังไม่ได้เข้ารหัส และควรทดสอบจากเครื่องอื่นที่ไม่ได้รับอนุญาตด้วยว่าเชื่อมต่อพอร์ต 3306 ไม่ได้

ปัญหาที่พบบ่อย

ERROR 2003: Can't connect to MySQL server (110 หรือ 111)

รหัส 111 (Connection refused) มักแปลว่าฐานข้อมูลยังฟังแค่ 127.0.0.1 ให้ตรวจ bind-address และผลของ ss -tlnp ส่วนรหัส 110 (Timeout) มักเป็นเพราะ Firewall บนเครื่องหรือ Firewall ภายนอกยังปิดพอร์ต หรือกฎอนุญาตระบุ IP ต้นทางผิด

ERROR 1130: Host '...' is not allowed to connect to this MySQL server

เชื่อมต่อถึงเซิร์ฟเวอร์แล้ว แต่ไม่มีผู้ใช้ที่ Host ตรงกับ IP ที่เข้ามา ดู IP ที่เซิร์ฟเวอร์เห็นจากข้อความ Error นั้น ซึ่งอาจต่างจากที่คาดไว้ถ้าเครื่องต้นทางออกอินเทอร์เน็ตผ่าน NAT แล้วสร้างผู้ใช้หรือแก้ Host ให้ตรง

ERROR 1045: Access denied

รหัสผ่านผิด หรือมีบัญชีชื่อเดียวกันหลาย Host แล้วระบบเลือกบัญชีที่ตรงกว่า ตรวจด้วย SELECT user, host FROM mysql.user WHERE user='appremote';

แอปเชื่อมต่อไม่ได้หลังตั้ง REQUIRE SSL

ไลบรารีของแอปยังไม่ได้เปิดใช้ TLS ให้ตั้งค่าการเชื่อมต่อฝั่งแอปให้ใช้ SSL/TLS หรือตรวจว่า MariaDB เปิด TLS แล้วตามขั้นตอนที่ 4

หากทำตามขั้นตอนแล้วยังติดปัญหา สามารถติดต่อทีมงาน Support ของ THAI DATA CLOUD ได้ที่ https://thaidata.cloud/contact/ โดยแจ้งชื่อเซิร์ฟเวอร์ ระบบปฏิบัติการ ขั้นตอนที่ทำไปแล้ว และข้อความ Error ที่พบ เพื่อให้ตรวจสอบได้รวดเร็วขึ้น

ผู้ให้บริการคลาวด์ไทย
เพื่อธุรกิจของคนไทย

"มุ่งมั่น" และ "มั่นคง"
พร้อมรับมือทุกการเติบโต
Trust Cloud
คลาว์ที่ปลอดภัย
คือรากฐานที่มั่นคง
cloud security