SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor

ติดตั้ง phpMyAdmin บน VPS Ubuntu 24.04 ให้ปลอดภัย

ย้ายจากโฮสต์แชร์มาอยู่ VPS แล้วคิดถึงหน้าจัดการฐานข้อมูล ติดตั้ง phpMyAdmin จากแพ็กเกจ Ubuntu 24.04 ล็อกให้เข้าได้เฉพาะผ่าน SSH tunnel และสร้างผู้ใช้สิทธิ์น้อยที่สุด

ติดตั้ง phpMyAdmin บน VPS แล้วต้องล็อกอะไรต่อ

ติดตั้ง phpMyAdmin บน VPS ทำได้จากแพ็กเกจในคลัง universe ของ Ubuntu เอง ใช้ apt คำสั่งเดียว ไม่ต้องดาวน์โหลดไฟล์ zip มาแตกไว้ในเว็บรูท ส่วนที่กินเวลาจริงคือการทำให้หน้าเว็บนั้นเข้าถึงได้เฉพาะจากคุณ ไม่ใช่จากทั้งอินเทอร์เน็ต

คนที่เพิ่งย้ายจากโฮสต์แชร์มาอยู่ VPS ของตัวเองมักพบว่าสิ่งที่หายไปพร้อมแผงควบคุมเดิมคือหน้าจอจัดการฐานข้อมูล นั่นคือเครื่องมือเดียวที่คนส่วนใหญ่คิดถึงจริง ๆ ของอย่างอื่นในแผงควบคุมมีคำสั่งแทนได้หมด

คำสั่งทุกบรรทัดในหน้านี้เขียนสำหรับ Ubuntu 24.04 แพ็กเกจชื่อ phpmyadmin ในคลังของรุ่นนี้เป็น phpMyAdmin 5.2.1 (ข้อมูล ณ กันยายน 2026)

หลักของทั้งหน้านี้: อย่าเดาว่าแพ็กเกจวางไฟล์ไว้ที่ไหน ตั้งค่าอะไรให้ หรือเลือกคำตอบใดให้คุณ ให้ถามเครื่องเอาทุกครั้ง คำสั่งที่ใช้ถามอยู่ในหัวข้อ "ถามเครื่องว่าแพ็กเกจทำอะไรไปบ้าง"

เตรียมฐานข้อมูลและ PHP ก่อน

phpMyAdmin เป็นแค่หน้าเว็บ มันไม่มีฐานข้อมูลในตัว และไม่รันตัวเองถ้าไม่มีเว็บเซิร์ฟเวอร์กับ PHP ติดตั้งสามอย่างนี้ก่อน แล้วค่อยติดตั้งตัวหน้าเว็บทีหลัง ลำดับนี้สำคัญ เพราะตัวติดตั้งของ phpMyAdmin จะมองหาเว็บเซิร์ฟเวอร์ที่มีอยู่แล้วบนเครื่องเพื่อเสนอให้คุณเลือก

sudo apt update
sudo apt install -y mariadb-server apache2 libapache2-mod-php php-mysql
sudo systemctl enable --now mariadb apache2
sudo systemctl is-active mariadb apache2

enable --now สั่งให้ทั้งสองบริการเริ่มทำงานเดี๋ยวนี้ และตั้งให้เริ่มเองทุกครั้งที่บูต อย่าถือว่าการติดตั้งแพ็กเกจเริ่มบริการให้เสมอ เพราะอิมเมจบางแบบที่ผู้ให้บริการเตรียมไว้กันการเริ่มบริการอัตโนมัติตอนติดตั้ง แล้วคุณจะเจอว่าทุกอย่างลงครบแต่ไม่มีอะไรทำงาน

is-active รายงานสถานะของบริการตรง ๆ ถ้าค่าที่ได้ไม่ใช่สถานะกำลังทำงาน ให้หาเหตุผลด้วย journalctl -u mariadb -n 50 ก่อนไปต่อ อย่าข้ามไปขั้นถัดไปโดยหวังว่ามันจะหายเอง เพราะตัวติดตั้งของ phpMyAdmin จะพยายามต่อฐานข้อมูลระหว่างติดตั้ง และจะล้มตามกันไป

จากนั้นรันสคริปต์ตั้งค่าความปลอดภัยของ MariaDB ด้วย sudo mariadb-secure-installation บนเทอร์มินัลที่คุณนั่งอยู่หน้าจอจริง ไม่ใช่ในสคริปต์อัตโนมัติ

สคริปต์นี้เป็นแบบถามตอบทีละข้อ ให้อ่านคำถามบนจอแล้วตอบตามสถานการณ์ของคุณ อย่าจำลำดับคำตอบจากคู่มือเล่มไหนมากดตาม เพราะจำนวนและลำดับคำถามเปลี่ยนไปตามเวอร์ชันของ MariaDB ถ้าคุณกำลังสร้างเครื่องนี้ขึ้นมาใหม่ทั้งชุด วิธีวาง LAMP stack บน Ubuntu 24.04 อธิบายส่วน Apache กับ PHP ไว้ละเอียดกว่าที่ย่อไว้ตรงนี้

ติดตั้งแพ็กเกจ phpmyadmin แบบไม่ต้องนั่งตอบคำถาม

แพ็กเกจนี้ตั้งค่าตัวเองผ่าน debconf ซึ่งเป็นระบบถามตอบของ Debian และ Ubuntu และใช้ dbconfig-common สร้างฐานข้อมูลภายในของ phpMyAdmin เอง ผลคือถ้ารัน apt install แบบปกติ การติดตั้งจะหยุดกลางคันเพื่อรอคำตอบจากคุณ ซึ่งเป็นปัญหาเวลารันผ่านสคริปต์หรือผ่าน SSH ที่หลุดง่าย

sudo DEBIAN_FRONTEND=noninteractive apt install -y phpmyadmin
echo $?

DEBIAN_FRONTEND=noninteractive สั่งให้ debconf ไม่แสดงหน้าจอถาม และใช้คำตอบที่แพ็กเกจกำหนดไว้แทน การติดตั้งจึงจบเองโดยไม่ค้าง สิ่งที่คุณแลกไปคือคุณยังไม่รู้ว่ามันตอบอะไรไปบ้าง หัวข้อถัดไปแก้ตรงนั้น

echo $? พิมพ์รหัสจบของคำสั่งก่อนหน้า ค่า 0 แปลว่า apt ทำงานจบสมบูรณ์ ค่าอื่นแปลว่าไม่สำเร็จ และคุณต้องอ่านข้อความที่ apt พิมพ์ไว้ก่อนหน้านั้นจริง ๆ ไม่ใช่กดต่อ

ถามเครื่องว่าแพ็กเกจทำอะไรไปบ้าง

นี่คือส่วนที่คู่มือส่วนใหญ่ข้าม แล้วเขียนพาธกับค่าดีฟอลต์จากความจำแทน ปัญหาคือค่าพวกนั้นเปลี่ยนตามเวอร์ชันของแพ็กเกจ และคุณจะไปแก้ไฟล์ที่ไม่มีอยู่จริง สามคำสั่งนี้ให้คำตอบจากเครื่องของคุณเอง

sudo debconf-show phpmyadmin
dpkg -L phpmyadmin | grep -E '/index\.php$'
dpkg -L phpmyadmin | grep -i apache

คำสั่งแรกพิมพ์คำถาม debconf ทุกข้อของแพ็กเกจนี้ พร้อมคำตอบที่ถูกบันทึกไว้ตอนติดตั้ง อ่านบรรทัดที่เกี่ยวกับเว็บเซิร์ฟเวอร์และเกี่ยวกับ dbconfig ให้ครบ นั่นคือสิ่งที่เครื่องคุณตัดสินใจไปแล้ว

คำสั่งที่สองหาไฟล์หน้าแรกของเว็บแอป ไดเรกทอรีที่ไฟล์นั้นอยู่คือเว็บรูทของ phpMyAdmin คุณจะต้องใช้พาธนี้ตอนตั้งค่า Apache หรือ nginx ในหัวข้อถัดไป จดไว้

คำสั่งที่สามหาไฟล์ตั้งค่า Apache ที่แพ็กเกจแถมมาให้ เปิดไฟล์นั้นด้วย less แล้วมองหาบรรทัดที่ขึ้นต้นด้วยคำว่า Alias ค่าที่ตามหลังคือ URL ที่หน้าเว็บนี้ไปโผล่บนเซิร์ฟเวอร์ของคุณ จดไว้เหมือนกัน

ถ้าคำตอบ debconf ข้อไหนไม่ถูกใจ แก้ทีหลังได้โดยไม่ต้องถอนแพ็กเกจ สั่ง sudo dpkg-reconfigure phpmyadmin จากเทอร์มินัลจริง คำสั่งนี้ถามคำถามชุดเดิมอีกครั้งแบบมีหน้าจอ แล้วนำคำตอบใหม่ไปใช้ตั้งค่าซ้ำ

ทำไม URL ของ phpMyAdmin ที่เปิดสาธารณะถึงโดนสแกนภายในไม่กี่ชั่วโมง

บ็อตสแกนช่องโหว่ไม่ได้ค้นหาเว็บของคุณ มันไล่ยิง URL ชุดเดิมไปทุกหมายเลข IP ทั้งอินเทอร์เน็ต และ URL มาตรฐานของ phpMyAdmin อยู่ในลิสต์นั้นมาสิบกว่าปีแล้ว ที่อยู่ IPv4 ทั้งโลกมีราว 4 พันล้านหมายเลข เครื่องสแกนสมัยใหม่กวาดครบได้ในเวลาระดับชั่วโมง เพราะฉะนั้น VPS ที่เพิ่งเปิดวันนี้ก็มีคนมาเคาะประตูวันนี้ ไม่มีใครต้องรู้จักโดเมนของคุณก่อน และการที่ยังไม่มีใครลิงก์มาหาคุณก็ไม่ได้ช่วยอะไร

คุณพิสูจน์ด้วยล็อกของตัวเองได้ หลังเปิดเว็บเซิร์ฟเวอร์ทิ้งไว้สักวัน ลองนับ

sudo grep -rci myadmin /var/log/apache2/ || echo 0

ตัวเลขที่ออกมาคือจำนวนคำขอที่พยายามเดา URL นี้บนเครื่องของคุณ ไม่ใช่สถิติจากที่อื่น

สิ่งที่บ็อตทำต่อมีสองอย่าง ลองรหัสผ่านที่คนใช้ซ้ำกันบ่อย และลองช่องโหว่ของ phpMyAdmin รุ่นเก่า ข้อแรกอันตรายกว่า เพราะหน้าล็อกอินของ phpMyAdmin ส่งชื่อผู้ใช้กับรหัสผ่านต่อไปยัง MariaDB โดยตรง การเดาถูกหนึ่งครั้งจึงเท่ากับได้สิทธิ์ในฐานข้อมูลทันที ไม่มีด่านที่สองให้ผ่านอีก

ผูกเว็บเซิร์ฟเวอร์ไว้กับ 127.0.0.1

วิธีที่ได้ผลที่สุดไม่ใช่การซ่อน URL แต่คือการไม่ให้พอร์ตนั้นรับการเชื่อมต่อจากภายนอกเลย ถ้าพอร์ตผูกอยู่กับ 127.0.0.1 เคอร์เนลจะปฏิเสธการเชื่อมต่อจากเน็ตการ์ดสาธารณะตั้งแต่ก่อนถึง Apache บ็อตจึงไม่มีอะไรให้คุยด้วย

หาไฟล์ที่สั่งให้ Apache เปิดพอร์ตก่อน

grep -rn '^Listen' /etc/apache2/

ผลลัพธ์บอกชื่อไฟล์และเลขบรรทัด เปิดไฟล์นั้นแล้วเปลี่ยนบรรทัด Listen 80 เป็น Listen 127.0.0.1:80 จากนั้นตรวจไวยากรณ์ รีสตาร์ต แล้วตรวจของจริง

sudo apache2ctl configtest
sudo systemctl restart apache2
sudo ss -ltnp | grep ':80'

บรรทัดกลางต้องเป็น restart ไม่ใช่ reload เพราะ reload ของ Apache คือการรีสตาร์ตแบบ graceful ซึ่งไม่ปิดและเปิด socket ที่ฟังอยู่ใหม่ การแก้บรรทัด Listen จึงไม่มีผลจนกว่าจะรีสตาร์ตเต็มรูปแบบ อาการที่เจอคือพอร์ตยังผูกอยู่กับที่อยู่เดิม หรือหยุดตอบไปทั้งพอร์ต ทั้งที่ configtest บอกว่าไวยากรณ์ถูกต้อง

ss -ltnp แสดงที่อยู่ที่แต่ละพอร์ตผูกไว้จริงในเคอร์เนล ถ้าคอลัมน์ที่อยู่ยังเป็น 0.0.0.0 หรือ * แปลว่ายังมีไฟล์อื่นสั่ง Listen ซ้ำอยู่ ให้กลับไปอ่านผลของ grep -rn อีกรอบให้ครบทุกบรรทัด ไม่ใช่แค่บรรทัดแรก

ข้อควรระวังที่คนเจอบ่อย ถ้า VPS ตัวนี้เสิร์ฟเว็บไซต์จริงอยู่ด้วย การย้าย Listen 80 ทั้งบรรทัดจะทำให้เว็บไซต์นั้นล่มทันที ทางออกคือปล่อยพอร์ต 80 ไว้ตามเดิม แล้วเพิ่มพอร์ตที่สองที่ผูกกับ 127.0.0.1 อย่างเดียวสำหรับ phpMyAdmin โดยเฉพาะ แทนที่ /PATH/FROM/DPKG-L ด้วยไดเรกทอรีที่คุณจดไว้จากคำสั่ง dpkg -L

Listen 127.0.0.1:8081

<VirtualHost 127.0.0.1:8081>
    DocumentRoot /PATH/FROM/DPKG-L
    <Directory /PATH/FROM/DPKG-L>
        Require all granted
    </Directory>
</VirtualHost>

แล้วอย่าเปิดพอร์ต 8081 บนไฟร์วอลล์ ปล่อยให้มันเป็นพอร์ตที่มีแต่ตัวเครื่องเองคุยได้ ถ้าคุณยังไม่ได้ตั้งไฟร์วอลล์เลย กฎพื้นฐานของ ufw บน VPS ใช้เวลาไม่กี่นาทีและควรทำก่อนหัวข้อถัดไป

เข้าหน้าเว็บผ่าน SSH tunnel

เมื่อพอร์ตฟังอยู่แค่ในเครื่อง คุณต้องมีทางเข้าไปถึงมัน SSH มีให้อยู่แล้วและไม่ต้องติดตั้งอะไรเพิ่ม รันคำสั่งนี้บนเครื่องของคุณเอง ไม่ใช่บน VPS

ssh -N -L 8081:127.0.0.1:8081 user@vps.example.com

คำสั่งนี้บอก SSH ว่า ให้เปิดพอร์ต 8081 บนเครื่องผม แล้วส่งทุกอย่างที่เข้ามาทางนั้นผ่านช่อง SSH ที่เข้ารหัสแล้ว ไปออกที่ 127.0.0.1:8081 ฝั่ง VPS ในมุมมองของ Apache การเชื่อมต่อนั้นมาจากตัวเครื่องเอง จึงผ่านการผูกที่ 127.0.0.1 ได้ ส่วน -N แปลว่าไม่ต้องเปิด shell ให้ เพราะคุณต้องการแค่ท่อ

เปิดหน้าต่างนี้ทิ้งไว้ แล้วเปิดเบราว์เซอร์ไปที่ http://127.0.0.1:8081/ ถ้าคุณใช้วิธี VirtualHost แยกพอร์ตข้างบน หรือต่อท้ายด้วยค่า Alias ที่จดไว้ ถ้าคุณใช้การตั้งค่าที่แพ็กเกจแถมมาบนพอร์ต 80 ปิดหน้าต่างเมื่อไรท่อก็หายไปเมื่อนั้น

ข้อดีที่มองข้ามกันคือด่านล็อกอินของคุณกลายเป็น SSH key ไม่ใช่รหัสผ่านในช่องกรอกบนหน้าเว็บ ซึ่งแข็งแรงกว่ามาก ตราบใดที่คุณ ปิดการล็อกอิน SSH ด้วยรหัสผ่านและจำกัดผู้ใช้ที่เข้าได้ ไว้แล้ว ถ้ายังเปิด PasswordAuthentication อยู่ คุณแค่ย้ายเป้าให้บ็อตไปยิงที่พอร์ต 22 แทน

ถ้า tunnel ต่อไม่ติดทั้งที่ SSH ปกติเข้าได้ ให้ตรวจว่า AllowTcpForwarding ในไฟล์ตั้งค่าของ sshd ไม่ได้ถูกปิดไว้ ผู้ให้บริการบางรายหรือสคริปต์เสริมความปลอดภัยบางตัวปิดค่านี้ และอาการที่ได้คือ SSH ล็อกอินได้ แต่เบราว์เซอร์ปฏิเสธการเชื่อมต่อที่พอร์ตปลายทาง

ทางเลือก: เข้าผ่าน tailnet ด้วย Tailscale

SSH tunnel ต้องพิมพ์คำสั่งทุกครั้ง ถ้าคุณเข้าหน้านี้วันละหลายรอบหรือมีทีมหลายคน เครือข่ายส่วนตัวแบบ Tailscale สะดวกกว่า และยังไม่ต้องเปิดพอร์ตสาธารณะเหมือนเดิม แนวคิดเดียวกับ การใช้ tailnet แทนการเปิดพอร์ตบนเราเตอร์ สองคำสั่งกลางต้องให้คุณยืนยันตัวตนกับบัญชี tailnet บนหน้าจอ จึงรันในสคริปต์อัตโนมัติไม่ได้

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
sudo tailscale serve --bg localhost:8081
sudo tailscale serve status

tailscale serve รับหน้าที่เป็นตัวกลาง มันฟังอยู่บนอินเทอร์เฟซของ tailnet แล้วส่งต่อไปยังพอร์ตใน 127.0.0.1 ของเครื่องเดียวกัน Apache ยังผูกอยู่กับ localhost เหมือนเดิมและไม่รู้ตัวว่ามีอะไรเปลี่ยน คุณต้องเปิดฟีเจอร์ HTTPS certificates ในหน้าแอดมินของ tailnet ก่อน ไม่อย่างนั้นคำสั่งนี้จะออกใบรับรองให้ไม่ได้

เลิกแชร์เมื่อไรก็สั่งปิดได้

sudo tailscale serve --https=443 off

สิ่งที่วิธีนี้ยังไม่ได้แก้คือใครในบ้านหรือในทีมที่อยู่บน tailnet เดียวกันก็เข้าถึงหน้านี้ได้ ถ้านั่นไม่ใช่สิ่งที่คุณต้องการ ให้ใช้ ACL ของ tailnet จำกัดเครื่องที่คุยกับ VPS ตัวนี้ได้

ถ้ายืนยันว่าจะเปิดสาธารณะ ต้องเพิ่มอะไร และมันกันอะไรไม่ได้

บางคนมีเหตุผลจริง เช่น ลูกค้าต้องกดเองจากเครื่องที่ติดตั้งอะไรไม่ได้ ถ้าเป็นแบบนั้น นี่คือสิ่งที่ต้องเพิ่ม พร้อมขอบเขตของมันตามจริง

บังคับ TLS ก่อนอย่างอื่น ถ้าหน้านี้วิ่งบน http รหัสผ่านฐานข้อมูลของคุณเดินทางเป็นข้อความเปล่าผ่านทุกอุปกรณ์ระหว่างทาง ออกใบรับรองให้โดเมนจริงด้วย certbot กับ Let's Encrypt แล้วบังคับ redirect ไป https ข้อนี้ไม่ใช่ตัวเลือก มันคือเงื่อนไขขั้นต่ำ

ใส่ด่านรหัสผ่านของเว็บเซิร์ฟเวอร์ไว้ข้างหน้า HTTP Basic authentication ทำงานก่อนที่คำขอจะไปถึงโค้ด PHP บ็อตที่ยิง URL ตรง ๆ จึงเจอ 401 แล้วจบ ไม่ได้แตะตัวแอปเลย

sudo apt install -y apache2-utils

แล้วสร้างไฟล์รหัสผ่านด้วย sudo htpasswd -c /etc/apache2/pma.htpasswd USERNAME ซึ่งจะถามรหัสผ่านใหม่บนหน้าจอสองครั้ง จากนั้นเติมบล็อกนี้ในไฟล์ตั้งค่าของไดเรกทอรีนั้น

<Directory /PATH/FROM/DPKG-L>
    AuthType Basic
    AuthName "Restricted"
    AuthUserFile /etc/apache2/pma.htpasswd
    Require valid-user
</Directory>

สิ่งที่มันไม่กัน: การเดารหัสผ่านของด่านนี้เอง เพราะ Basic auth ไม่มีการจำกัดจำนวนครั้งในตัว และไม่กันคนที่รู้รหัสด่านนี้อยู่แล้ว ตั้งรหัสให้ยาวและไม่ซ้ำกับรหัสฐานข้อมูล

เปลี่ยน URL ให้ไม่ใช่ค่าเดิมของแพ็กเกจ ข้อนี้ลดจำนวนบรรทัดขยะในล็อกได้จริง แต่ไม่ใช่มาตรการความปลอดภัย เพราะ URL เดินทางไปกับทุกคำขอ ค้างอยู่ในประวัติเบราว์เซอร์ และหลุดไปกับ Referer ใครเห็นครั้งเดียวก็ใช้ได้ตลอดไป อย่านับข้อนี้เป็นชั้นป้องกัน

จำกัด IP ต้นทางด้วยไฟร์วอลล์ sudo ufw allow from 203.0.113.5 to any port 443 proto tcp กันได้จริงและกันได้แข็งแรง ถ้าหมายเลข IP ของคุณนิ่ง เน็ตบ้านและเน็ตมือถือส่วนใหญ่เปลี่ยน IP เมื่อรีเซ็ตอุปกรณ์ แล้วคุณจะล็อกตัวเองออกโดยไม่รู้ตัว

พูดกันตรง ๆ ทุกข้อรวมกันยังอ่อนกว่าการไม่เปิดพอร์ตเลย เพราะทั้งหมดนี้ขึ้นอยู่กับความลับที่เดินทางผ่านเน็ตทุกวัน ส่วน tunnel ไม่มีอะไรให้เดา และอย่าลืมเปิดอัปเดตอัตโนมัติด้วย sudo apt install -y unattended-upgrades เพราะ phpMyAdmin ที่เปิดสาธารณะคือโค้ดที่คนทั้งโลกยิงทดสอบได้ตลอดเวลา

ถ้าใช้ nginx แทน Apache

ตัวติดตั้งของแพ็กเกจตั้งค่าเว็บเซิร์ฟเวอร์ให้อัตโนมัติเฉพาะ Apache กับ lighttpd คนที่ใช้ nginx ต้องเขียน server block เอง และนี่คือสาเหตุที่คนใช้ nginx ติดตั้งเสร็จแล้วเปิดหน้าเว็บไม่ขึ้น ทั้งที่แพ็กเกจลงสำเร็จ

หา socket ของ PHP-FPM ก่อน อย่าเดาเลขเวอร์ชัน

sudo apt install -y nginx php-fpm
grep -rn '^listen' /etc/php/*/fpm/pool.d/

ค่าที่อยู่หลัง listen = คือ socket ที่ PHP-FPM บนเครื่องคุณใช้จริง อ่านจากไฟล์ pool ของเวอร์ชันที่ติดตั้งอยู่ ไม่ใช่จากความจำ แล้วเขียน server block โดยแทนพาธทั้งสองด้วยค่าที่หาได้จริง

server {
    listen 127.0.0.1:8081;
    server_name _;
    root /PATH/FROM/DPKG-L;
    index index.php;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/SOCKET/FROM/POOL-CONF;
    }
}
sudo nginx -t

nginx -t ตรวจไวยากรณ์และบอกไฟล์กับบรรทัดที่ผิด ให้รันทุกครั้งก่อนสั่ง sudo systemctl reload nginx ไม่อย่างนั้นการพิมพ์ผิดหนึ่งตัวทำให้เว็บทั้งเครื่องหยุดตอบ โครงสร้างไฟล์และลำดับการจับคู่ location อธิบายไว้ใน คู่มืออ่านไฟล์ตั้งค่า nginx reverse proxy

สร้างผู้ใช้ฐานข้อมูลแบบสิทธิ์น้อยที่สุด

นิสัยที่ติดมาจากโฮสต์แชร์คือใช้บัญชีเดียวทำทุกอย่าง บน VPS คุณเป็นคนแจกสิทธิ์เอง และหลักคือ หนึ่งแอป หนึ่งฐานข้อมูล หนึ่งผู้ใช้ ให้เฉพาะสิทธิ์ที่แอปนั้นใช้จริง

สร้างรหัสผ่านแบบสุ่มก่อน อย่าคิดเอง

openssl rand -base64 24

แล้วสั่งงาน MariaDB จากเชลล์ทีละคำสั่งด้วย -e วิธีนี้ไม่ต้องเข้า prompt แบบถามตอบ และคุณย้อนอ่านบรรทัดที่รันไปแล้วได้จากประวัติคำสั่ง ใส่รหัสผ่านที่สุ่มได้แทน PASTE_RANDOM_PASSWORD

sudo mariadb -e "CREATE DATABASE shop_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
sudo mariadb -e "CREATE USER 'shop_app'@'localhost' IDENTIFIED BY 'PASTE_RANDOM_PASSWORD';"
sudo mariadb -e "GRANT SELECT, INSERT, UPDATE, DELETE ON shop_db.* TO 'shop_app'@'localhost';"
sudo mariadb -e "FLUSH PRIVILEGES;"
sudo mariadb -e "SHOW GRANTS FOR 'shop_app'@'localhost';"

SHOW GRANTS ให้คุณอ่านสิทธิ์ที่เซิร์ฟเวอร์เก็บไว้จริง ถ้าเห็นคำว่า ALL PRIVILEGES หรือเห็น *.* แปลว่าคุณให้สิทธิ์กว้างเกินไป ให้ถอนแล้วให้ใหม่

ใช้ utf8mb4 เสมอสำหรับงานภาษาไทย ชุดอักขระเก่าที่ชื่อ utf8 ในตระกูล MySQL เก็บได้ไม่ครบทุกอักขระ ผลคืออีโมจิและอักขระบางตัวกลายเป็นเครื่องหมายคำถามตอนบันทึก

ข้อจำกัดที่ต้องรู้ไว้ ผู้ใช้ที่มีแค่สี่สิทธิ์ข้างบนจะรันไฟล์ migration ที่มี ALTER TABLE ไม่ได้ ถ้าแอปของคุณต้องแก้โครงสร้างตาราง ให้เพิ่ม CREATE, ALTER, INDEX, DROP เฉพาะช่วงที่ต้องใช้ แล้วถอนคืนด้วย REVOKE เมื่อเสร็จ ส่วนการเลิกใช้ผู้ใช้หนึ่งคนคือ DROP USER 'shop_app'@'localhost';

ถ้าผู้ใช้ที่เพิ่งสร้างล็อกอินผ่านหน้าเว็บไม่ได้ ให้ดูที่ส่วน host ของบัญชี MariaDB ถือว่า localhost หมายถึงการต่อผ่าน unix socket ส่วน 127.0.0.1 หมายถึงการต่อผ่าน TCP สองค่านี้ไม่ใช่ค่าเดียวกัน และสิทธิ์ที่ให้กับค่าหนึ่งไม่มีผลกับอีกค่าหนึ่ง ดูภาพรวมของบัญชีทั้งหมดด้วยคำสั่งนี้

sudo mariadb -e 'SELECT user, host, plugin FROM mysql.user;'

คอลัมน์ plugin อธิบายอีกเรื่องที่คนติดกันมาก บัญชี root ของ MariaDB บน Ubuntu ใช้ปลั๊กอิน unix_socket ซึ่งยืนยันตัวตนจากผู้ใช้ระบบที่รันคำสั่ง ไม่ใช่จากรหัสผ่าน หน้าล็อกอินของ phpMyAdmin ส่งรหัสผ่านไปให้เซิร์ฟเวอร์ตรวจ จึงล็อกอินด้วย root ไม่ได้ และนั่นเป็นพฤติกรรมที่ถูกต้องแล้ว ไม่ใช่ข้อผิดพลาดที่ต้องแก้

งานหลายอย่าง mysql CLI เร็วกว่าการเปิดเบราว์เซอร์

ถ้าคุณจะรันคำสั่งเดียวแล้วปิด การเปิด tunnel เปิดเบราว์เซอร์ ล็อกอิน แล้วไล่คลิกหาตาราง ใช้เวลามากกว่าการพิมพ์บรรทัดเดียวหลายเท่า

sudo mariadb -e 'SHOW DATABASES;'
sudo mariadb shop_db -e 'SHOW TABLES;'
sudo mariadb-dump --single-transaction shop_db > shop_db.sql

--single-transaction ทำให้การสำรองข้อมูลตาราง InnoDB อ่านสถานะ ณ จุดเวลาเดียวกันโดยไม่ล็อกตาราง เว็บไซต์จึงทำงานต่อได้ระหว่างสำรอง

สำรองก่อนแก้อะไรผ่านหน้าเว็บทุกครั้ง phpMyAdmin ไม่มีปุ่มย้อนกลับ และคำสั่ง UPDATE ที่ลืมใส่ WHERE ทำงานสำเร็จอย่างเงียบ ๆ เหมือนคำสั่งที่ถูกต้องทุกประการ ความต่างคือมันแก้ทุกแถวในตาราง สิ่งที่ phpMyAdmin ทำได้ดีกว่า CLI จริง ๆ คือการไล่ดูโครงสร้างตารางที่ไม่คุ้น การแก้ค่าทีละช่อง และการให้คนที่ไม่เขียน SQL ดูข้อมูลได้ ถ้างานของคุณไม่ใช่สามอย่างนี้ CLI จบเร็วกว่า

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

FAQ

ติดตั้ง phpmyadmin สำเร็จแล้วแต่เปิดหน้าเว็บไม่ขึ้น ต้องดูอะไร

ไล่จากล่างขึ้นบน ตรวจว่าพอร์ตมีคนฟังอยู่จริงด้วย sudo ss -ltnp ถ้าไม่มี แปลว่าเว็บเซิร์ฟเวอร์ไม่ได้ทำงานหรือผูกพอร์ตอื่น ถ้ามีแล้วยังไม่ขึ้น ให้ดูว่า URL ที่คุณเปิดตรงกับค่า Alias ในไฟล์ตั้งค่าที่แพ็กเกจแถมมาหรือไม่ หาไฟล์นั้นด้วย dpkg -L phpmyadmin | grep -i apache ถ้าคุณใช้ nginx สาเหตุมักเป็นเรื่องเดียว ตัวติดตั้งของแพ็กเกจตั้งค่าให้อัตโนมัติเฉพาะ Apache กับ lighttpd คุณต้องเขียน server block เอง

เพิ่งแก้บรรทัด Listen แล้วเว็บหายไปทั้งพอร์ต เกิดอะไรขึ้น

เกือบทุกครั้งคือสั่ง reload แทน restart การรีโหลดแบบ graceful ของ Apache ไม่ปิดและเปิด socket ที่ฟังอยู่ใหม่ บรรทัด Listen ที่เพิ่งแก้จึงยังไม่มีผล และ configtest ก็บอกว่าผ่าน เพราะมันตรวจแค่ไวยากรณ์ สั่ง sudo systemctl restart apache2 แล้วดูที่อยู่ที่ผูกจริงด้วย sudo ss -ltnp อีกรอบ ถ้าบริการไม่ขึ้นหลังรีสตาร์ต ให้อ่านเหตุผลจาก journalctl -u apache2 -n 50

ทำไมล็อกอิน phpMyAdmin ด้วยบัญชี root ของ MariaDB ไม่ได้

เพราะบัญชี root ของ MariaDB บน Ubuntu ใช้ปลั๊กอินยืนยันตัวตนชื่อ unix_socket ซึ่งตรวจจากผู้ใช้ระบบที่รันคำสั่ง ไม่ได้ตรวจจากรหัสผ่าน หน้าล็อกอินบนเว็บส่งรหัสผ่านไปให้ตรวจ จึงไม่ตรงกับวิธีที่บัญชีนั้นใช้ ตรวจได้จาก SELECT user, host, plugin FROM mysql.user; วิธีที่ถูกต้องคือสร้างผู้ใช้แยกสำหรับแต่ละฐานข้อมูลแล้วให้เฉพาะสิทธิ์ที่จำเป็น ไม่ใช่เปลี่ยน root ให้ใช้รหัสผ่านได้

เปิด phpMyAdmin ให้เข้าจากอินเทอร์เน็ตตรง ๆ ได้ไหม

ได้ แต่คุณต้องรับความเสี่ยงที่ชัดเจนไว้ด้วย หน้าล็อกอินนี้ส่งรหัสผ่านต่อไปยังฐานข้อมูลโดยตรง การเดาถูกหนึ่งครั้งจึงได้สิทธิ์ในข้อมูลทันทีโดยไม่มีด่านที่สอง ถ้าจำเป็นจริง ให้บังคับ https ใส่ HTTP Basic authentication ไว้ข้างหน้า และจำกัด IP ต้นทางบนไฟร์วอลล์ การเปลี่ยน URL ให้เดายากไม่นับเป็นชั้นป้องกัน เพราะ URL หลุดได้จากประวัติเบราว์เซอร์และ Referer

ตอบคำถามตอนติดตั้งไปผิด แก้ทีหลังได้ไหม

ได้ ใช้ sudo dpkg-reconfigure phpmyadmin แล้วมันจะถามคำถามชุดเดิมอีกครั้งพร้อมนำคำตอบใหม่ไปตั้งค่าซ้ำ ถ้าอยากดูก่อนว่าตอนนี้เครื่องเก็บคำตอบอะไรไว้บ้าง ให้รัน sudo debconf-show phpmyadmin ซึ่งพิมพ์คำถามทุกข้อพร้อมค่าปัจจุบันออกมา ไม่ต้องถอนแพ็กเกจแล้วติดตั้งใหม่