คำตอบสั้น ๆ: ตั้งค่า 301 Redirect บน Nginx ด้วย return, rewrite และ map ครอบคลุมการบังคับ HTTPS รวมโดเมน www ย้ายหน้า และ Redirect จำนวนมาก
คู่มือนี้อธิบาย 301 Redirect ทีละขั้นตอน พร้อมคำสั่งที่ใช้ได้จริงและปัญหาที่พบบ่อย
Nginx ไม่อ่านไฟล์ .htaccess การทำ 301 Redirect จึงต้องเขียนในไฟล์ตั้งค่าของ Nginx โดยตรง ข้อดีคือทำงานเร็วกว่า เพราะ Nginx ไม่ต้องอ่านไฟล์เพิ่มทุกครั้งที่มีคำขอ และตรวจไวยากรณ์ได้ก่อนนำไปใช้จริงด้วย nginx -t
บทความนี้ครอบคลุมรูปแบบที่ใช้บ่อย ตั้งแต่บังคับ HTTPS, รวมโดเมน www, ย้ายหน้าทีละหน้า, ย้ายโฟลเดอร์ ไปจนถึงการจัดการ Redirect จำนวนหลายร้อยรายการด้วย map
สิ่งที่ต้องเตรียม (301 Redirect)
- Cloud Server ที่ติดตั้ง Nginx และผู้ใช้ที่มีสิทธิ์
sudo(ดู สร้างผู้ใช้ใหม่และให้สิทธิ์ sudo บน Linux) - รู้ว่าไฟล์ Server Block ของเว็บอยู่ที่ไหน: Ubuntu มักอยู่ใน
/etc/nginx/sites-available/(ลิงก์ไปยังsites-enabled) ส่วน AlmaLinux/Rocky อยู่ใน/etc/nginx/conf.d/ - สำเนาไฟล์ตั้งค่าเดิม เช่น
sudo cp /etc/nginx/sites-available/example.com /root/example.com.bak - ถ้าใช้ Plesk ให้ดูหัวข้อ "กรณีใช้ Plesk" ด้านล่าง
หลักการที่ควรรู้ก่อน (301 Redirect)
return 301 URL;เป็นวิธีที่แนะนำ เร็วและอ่านง่าย ใช้เมื่อรู้ปลายทางแน่นอนrewrite pattern replacement permanent;ใช้เมื่อต้องการดึงบางส่วนของ URL เดิมด้วย Regular Expression- ตัวแปร
$request_uriคือ Path พร้อม Query String แบบที่ผู้ใช้ส่งมา ส่วน$uriคือ Path ที่ Nginx ทำให้เป็นมาตรฐานแล้วและไม่มี Query String - ใน Nginx ทุกเส้นทางขึ้นต้นด้วย
/ต่างจาก.htaccess
ขั้นตอนที่ 1: บังคับ HTTPS และรวมโดเมนให้เหลือแบบเดียว
วิธีที่สะอาดที่สุดคือแยก Server Block สำหรับคำขอที่ต้องถูกส่งต่อออกจาก Server Block หลัก ตัวอย่างนี้ใช้ https://example.com เป็นโดเมนหลัก
# HTTP ทุกแบบ ไปที่ HTTPS โดเมนหลัก
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
# HTTPS แบบมี www ไปที่ไม่มี www
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://example.com$request_uri;
}
# Server Block หลัก
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
# ... ค่าเดิมของเว็บ ...
}
Server Block ที่ Redirect จาก https://www ต้องมีใบรับรอง SSL ที่ครอบคลุม www.example.com ด้วย ไม่เช่นนั้นเบราว์เซอร์จะแจ้งเตือนก่อนถึงขั้น Redirect ดูวิธีขอใบรับรองที่รวมทั้งสองชื่อได้ที่ ติดตั้ง SSL ฟรีจาก Let's Encrypt ด้วย Certbot บน Nginx
หมายเหตุ: รูปแบบ listen 443 ssl http2; ใช้ได้กับแพ็กเกจ Nginx มาตรฐานของ Ubuntu 22.04 (1.18) และ 24.04 (1.24) ถ้าติดตั้ง Nginx 1.25.1 ขึ้นไปจาก Repository ของ nginx.org ค่านี้ยังใช้ได้แต่ nginx -t จะเตือนว่าเลิกใช้แล้ว ให้เปลี่ยนเป็น listen 443 ssl; คู่กับบรรทัด http2 on; ตรวจเวอร์ชันได้ด้วย nginx -v
ขั้นตอนที่ 2: ย้ายหน้าทีละหน้า
ใส่ภายใน Server Block หลัก ใช้ location = ซึ่งจับคู่แบบตรงตัวและทำงานเร็วที่สุด
location = /about-us/ {
return 301 https://example.com/about/;
}
location = /about-us {
return 301 https://example.com/about/;
}
ต้องเขียนทั้งแบบมีและไม่มี / ปิดท้าย ถ้า URL เดิมเคยถูกเข้าถึงทั้งสองแบบ หรือใช้ Regular Expression ครั้งเดียว
location ~ ^/about-us/?$ {
return 301 https://example.com/about/;
}
ขั้นตอนที่ 3: ย้ายทั้งโฟลเดอร์
location ^~ /blog/ {
rewrite ^/blog/(.*)$ https://example.com/news/$1 permanent;
}
^~ ทำให้ location นี้ชนะ location แบบ Regular Expression อื่น (เช่นบล็อก ~ \.php$) คำว่า permanent ส่งรหัส 301 ถ้าใช้ redirect จะเป็น 302 เมื่อใช้ rewrite Nginx จะต่อ Query String เดิมท้าย URL ใหม่ให้อัตโนมัติ ถ้าไม่ต้องการ ให้ใส่ ? ต่อท้ายปลายทาง เช่น https://example.com/news/$1?
ขั้นตอนที่ 4: Redirect จำนวนมากด้วย map
ถ้ามี URL เดิมหลายสิบหรือหลายร้อยรายการ การเขียน location ทีละตัวจะดูแลยาก ใช้ map ซึ่งค้นหาเร็วแม้มีรายการมาก สร้างไฟล์ใหม่ที่ถูกโหลดในบริบท http ทั้ง Ubuntu และ AlmaLinux/Rocky โหลดไฟล์ใน /etc/nginx/conf.d/*.conf ภายใน http { } อยู่แล้ว
sudo nano /etc/nginx/conf.d/redirect-map.conf
map $uri $redirect_target {
default "";
/old-a/ /new-a/;
/old-b/ /products/b/;
/promo-2024/ /promotions/;
~^/shop/(?<path>.+)$ /store/$path;
}
จากนั้นเพิ่มใน Server Block หลัก ด้านบนก่อน location อื่น
if ($redirect_target) {
return 301 https://example.com$redirect_target;
}
การใช้ if คู่กับ return ใน Server Block เป็นรูปแบบที่ปลอดภัย รายการที่ขึ้นต้นด้วย ~ เป็น Regular Expression และใช้ Named Capture (?<path>) เพื่อนำค่าที่จับได้ไปใช้ในปลายทาง Nginx จะตรวจรายการแบบตรงตัวก่อนเสมอ แล้วจึงตรวจ Regular Expression ตามลำดับในไฟล์ ถ้ารายการ Redirect ยาวมากจนได้ข้อความ could not build map_hash ให้เพิ่ม map_hash_bucket_size 128; ในบริบท http