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

Home ตั้งค่า Nginx Server Block สำหรับหลายเว็บไซต์ในเครื่องเดียว

ตั้งค่า Nginx Server Block สำหรับหลายเว็บไซต์ในเครื่องเดียว

เซิร์ฟเวอร์หนึ่งเครื่องที่มี IP เดียวสามารถให้บริการหลายเว็บไซต์ได้ เพราะเบราว์เซอร์ส่งชื่อโดเมนที่ต้องการมาใน Header Host (และใน SNI สำหรับ HTTPS) Nginx ใช้ค่านี้เลือกว่าจะตอบด้วยการตั้งค่าชุดใด การตั้งค่าแต่ละชุดเรียกว่า Server Block ซึ่งเทียบได้กับ VirtualHost ของ Apache

บทความนี้สาธิตการตั้งค่าสองเว็บไซต์ คือ example.com (เว็บ PHP) และ example.net (เว็บ HTML ล้วน) บนเครื่องเดียวกัน พร้อมการตั้ง Default Server เพื่อไม่ให้โดเมนแปลกปลอมที่ชี้มาที่ IP ของคุณแสดงเนื้อหาเว็บใดเว็บหนึ่ง บทความนี้สมมติว่าคุณติดตั้ง Nginx และ PHP-FPM แล้วตาม ติดตั้ง Nginx, PHP-FPM และ MariaDB (LEMP) บน Ubuntu

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

  • Ubuntu 22.04/24.04 หรือ AlmaLinux/Rocky Linux 8-9 ที่ติดตั้ง Nginx แล้ว
  • ผู้ใช้ที่มีสิทธิ์ sudo
  • โดเมนทุกโดเมนชี้ A Record มาที่ IP ของเซิร์ฟเวอร์ (ตัวอย่างใช้ 203.0.113.10)
  • สำรองโฟลเดอร์ Config เดิมไว้ก่อนแก้ไข: sudo cp -a /etc/nginx /etc/nginx.bak-$(date +%F)

โครงสร้างไฟล์ Config บนแต่ละ Distro

UbuntuAlmaLinux / Rocky Linux
ตำแหน่งไฟล์ Server Block/etc/nginx/sites-available/ แล้วสร้าง Symlink ไปที่ /etc/nginx/sites-enabled//etc/nginx/conf.d/*.conf (ไฟล์ต้องลงท้าย .conf)
ผู้ใช้ที่ Nginx รันwww-datanginx
Socket ของ PHP-FPM/run/php/php8.3-fpm.sock (24.04) หรือ /run/php/php8.1-fpm.sock (22.04)/run/php-fpm/www.sock
Default Site ที่มากับแพ็กเกจsites-enabled/defaultบล็อก server ใน /etc/nginx/nginx.conf

ตรวจชื่อ Socket ของ PHP-FPM บนเครื่องคุณด้วย ls /run/php/ (Ubuntu) หรือ ls /run/php-fpm/ (AlmaLinux/Rocky) เพราะชื่อจะเปลี่ยนตามเวอร์ชัน PHP ที่ติดตั้ง

ขั้นตอนที่ 1: สร้างโฟลเดอร์ของแต่ละเว็บ

sudo mkdir -p /var/www/example.com/public /var/www/example.net/public
echo '<?php echo "example.com OK";' | sudo tee /var/www/example.com/public/index.php
echo '<h1>example.net OK</h1>' | sudo tee /var/www/example.net/public/index.html

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

ขั้นตอนที่ 2: สร้าง Server Block สำหรับเว็บ PHP

บน Ubuntu สร้างไฟล์ /etc/nginx/sites-available/example.com บน AlmaLinux/Rocky สร้าง /etc/nginx/conf.d/example.com.conf เนื้อหาเหมือนกัน ยกเว้นบรรทัด fastcgi_pass:

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    root /var/www/example.com/public;
    index index.php index.html;

    access_log /var/log/nginx/example.com.access.log;
    error_log  /var/log/nginx/example.com.error.log;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }

    location ~ /\.(?!well-known) {
        deny all;
    }
}

คำอธิบาย:

  • server_name คือรายชื่อโดเมนที่ Server Block นี้รับ ใส่ทั้งแบบมีและไม่มี www
  • try_files บรรทัดนี้เหมาะกับ WordPress และเฟรมเวิร์กที่ส่งทุก Request ไปที่ index.php
  • location ~ /\.(?!well-known) ปฏิเสธการเข้าถึงไฟล์ที่ขึ้นต้นด้วยจุด เช่น .git หรือ .env แต่ยังปล่อย .well-known ไว้ให้ Let's Encrypt ใช้
  • Log แยกของแต่ละเว็บทำให้หาสาเหตุ Error ได้ง่ายกว่ารวมในไฟล์เดียว

บน AlmaLinux/Rocky ไม่มีไฟล์ snippets/fastcgi-php.conf ให้ใช้บล็อก PHP แบบนี้แทน:

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

ขั้นตอนที่ 3: สร้าง Server Block สำหรับเว็บ HTML ล้วน

server {
    listen 80;
    listen [::]:80;
    server_name example.net www.example.net;

    root /var/www/example.net/public;
    index index.html;

    access_log /var/log/nginx/example.net.access.log;
    error_log  /var/log/nginx/example.net.error.log;

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

บันทึกเป็น /etc/nginx/sites-available/example.net (Ubuntu) หรือ /etc/nginx/conf.d/example.net.conf (AlmaLinux/Rocky)

ขั้นตอนที่ 4: ตั้ง Default Server ที่ปฏิเสธโดเมนที่ไม่รู้จัก

เมื่อมี Request ที่ Header Host ไม่ตรงกับ server_name ใดเลย เช่น มีคนเข้าด้วย IP ตรง ๆ หรือโดเมนของคนอื่นชี้มาที่ IP คุณ Nginx จะใช้ Server Block ที่มี default_server หรือถ้าไม่มี ก็ใช้บล็อกแรกที่อ่านเจอ ซึ่งอาจเป็นเว็บลูกค้าของคุณ ผลคือเว็บของคุณไปปรากฏใต้โดเมนอื่นและกระทบ SEO ได้ ให้สร้างบล็อก Default ที่ตัดการเชื่อมต่อทิ้ง:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 444;
}

444 เป็นรหัสพิเศษของ Nginx ที่ปิดการเชื่อมต่อทันทีโดยไม่ส่งคำตอบกลับ

บน Ubuntu ให้บันทึกเป็น /etc/nginx/sites-available/000-default-deny แล้วปิดไซต์ Default เดิมเพราะมี default_server อยู่แล้ว และจะชนกัน:

sudo rm /etc/nginx/sites-enabled/default

บน AlmaLinux/Rocky ให้บันทึกเป็น /etc/nginx/conf.d/000-default-deny.conf แล้วเปิด /etc/nginx/nginx.conf ดูบล็อก server เดิมที่มากับแพ็กเกจ หากบรรทัด listen ในบล็อกนั้นมีคำว่า default_server (พบในบางเวอร์ชัน) ให้ลบคำนั้นออก หรือใส่ # หน้าบล็อกทั้งหมดหากไม่ได้ใช้

ขั้นตอนที่ 5: เปิดใช้งานและโหลดค่าใหม่

บน Ubuntu สร้าง Symlink:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/example.net /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/000-default-deny /etc/nginx/sites-enabled/

ทุก Distro ตรวจไวยากรณ์แล้ว reload:

sudo nginx -t
sudo systemctl reload nginx

nginx -t ต้องแสดง syntax is ok และ test is successful เสมอก่อน reload การ reload ไม่ตัดการเชื่อมต่อที่ค้างอยู่ และถ้า Config ใหม่ผิด Nginx จะยังใช้ค่าเดิมต่อ

บน AlmaLinux/Rocky ที่เปิด SELinux นโยบายมาตรฐานกำหนดให้ /var/www เป็น httpd_sys_content_t อยู่แล้ว เพียงรีเซ็ต Context ของไฟล์ที่สร้างใหม่ให้ตรงกับนโยบาย:

sudo restorecon -Rv /var/www

หากใช้โฟลเดอร์อื่น เช่น /srv/www ต้องเพิ่มกฎก่อน:

sudo semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"
sudo restorecon -Rv /srv/www

รายละเอียดดูที่ ใช้งาน SELinux บน AlmaLinux และ Rocky Linux โดยไม่ต้องปิด

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

ทดสอบได้ทันทีแม้ DNS ยังไม่ชี้มา โดยส่ง Header Host เองจากตัวเซิร์ฟเวอร์:

curl -H "Host: example.com" http://127.0.0.1/
curl -H "Host: example.net" http://127.0.0.1/
curl -v -H "Host: unknown.test" http://127.0.0.1/

ผลที่ควรได้คือ example.com OK, <h1>example.net OK</h1> และบรรทัดสุดท้ายจะจบด้วย Empty reply from server ซึ่งแปลว่า Default Server ทำงานถูกต้อง

ดูว่า Nginx โหลด Config ใดบ้างจริง ๆ ด้วย sudo nginx -T | grep -E "server_name|listen"

ขั้นตอนต่อไป: HTTPS

เมื่อ DNS ชี้มาแล้ว ให้ขอใบรับรองแยกของแต่ละเว็บด้วย Certbot ตาม ติดตั้ง SSL ฟรีจาก Let's Encrypt ด้วย Certbot บน Nginx Certbot จะเพิ่มบรรทัด listen 443 ssl ใน Server Block ที่ตรงกับโดเมนให้เอง

สำหรับพอร์ต 443 ควรมี Default Server ที่ปฏิเสธเช่นกัน ใน Nginx 1.19.4 ขึ้นไป (Ubuntu 22.04 มี 1.18 จากแพ็กเกจมาตรฐาน จึงยังใช้ไม่ได้ ส่วน Ubuntu 24.04 และ AlmaLinux/Rocky 9 ใช้ได้) เพิ่มบล็อกนี้ได้โดยไม่ต้องมีใบรับรอง:

server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;
    server_name _;
    ssl_reject_handshake on;
}

ตรวจเวอร์ชันของเครื่องคุณด้วย nginx -v

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

ทุกโดเมนแสดงเว็บเดียวกัน

มักเกิดจากสะกด server_name ผิด ลืมสร้าง Symlink ใน sites-enabled หรือบน AlmaLinux ตั้งชื่อไฟล์ไม่ลงท้าย .conf ไฟล์จึงไม่ถูกโหลด ตรวจด้วย sudo nginx -T ว่ามี Server Block ของโดเมนนั้นจริงหรือไม่

nginx -t แจ้ง a duplicate default server

มีมากกว่าหนึ่งบล็อกที่ประกาศ default_server บนพอร์ตเดียวกัน มักเป็นไฟล์ default ของ Ubuntu หรือบล็อกใน nginx.conf ของ AlmaLinux ที่ยังไม่ได้ปิด

could not build server_names_hash

เมื่อมีชื่อโดเมนยาวหรือจำนวนมาก ให้เพิ่มบรรทัดนี้ในบล็อก http { } ของ /etc/nginx/nginx.conf แล้วทดสอบอีกครั้ง (บน Ubuntu มีบรรทัดนี้อยู่แล้วแต่ถูก Comment ไว้):

server_names_hash_bucket_size 64;

เว็บ PHP ขึ้น 502 Bad Gateway

Nginx ติดต่อ PHP-FPM ไม่ได้ ตรวจว่า Service ทำงานอยู่ (systemctl status php8.3-fpm บน Ubuntu หรือ php-fpm บน AlmaLinux) และ Path ของ Socket ใน fastcgi_pass ตรงกับไฟล์ที่มีจริง รายละเอียดดู /var/log/nginx/example.com.error.log และบทความ ทำความเข้าใจ HTTP Error 403, 404, 500, 502, 503 และ 504

หากเพิ่มเว็บไซต์แล้วยังแสดงผลไม่ถูกต้อง ติดต่อทีมซัพพอร์ต THAI DATA CLOUD ได้ที่ https://thaidata.cloud/contact/

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

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