ติดตั้งและตั้งค่า Nginx บน VPS Ubuntu: Static Site, Reverse Proxy และ SSL

Nginx (อ่านว่า "เอ็นจิ้นเอกซ์") คือ Web Server ที่ได้รับความนิยมอย่างสูงในระดับโลก ใช้งานโดยเว็บไซต์ขนาดใหญ่อย่าง Netflix, Airbnb และ GitHub ด้วยสถาปัตยกรรม Event-driven ที่ทำให้รับ Connection พร้อมกันได้เป็นหมื่นเป็นแสน Connection โดยไม่กินทรัพยากรมากเกิน บทความนี้จะพาคุณติดตั้ง Nginx บน VPS Ubuntu 22.04 ตั้งแต่เริ่มต้น จนถึงการ Serve Static Site, ตั้ง Reverse Proxy สำหรับ Node.js และเปิด SSL ด้วย Let's Encrypt

Nginx คืออะไร และต่างจาก Apache อย่างไร

Apache และ Nginx ต่างเป็น Web Server ที่ใช้กันอย่างแพร่หลาย แต่มีแนวคิดที่แตกต่างกันอย่างสิ้นเชิงในการจัดการ Connection

Apache: Process-based / Thread-based

Apache ใช้รูปแบบ Process-based หรือ Thread-based ซึ่งหมายความว่าเมื่อมี Request เข้ามา 1 ครั้ง Apache จะสร้าง Process หรือ Thread ใหม่ขึ้นมา 1 ตัวเพื่อจัดการ Request นั้น เมื่อมี Concurrent Connection มาก ๆ (เช่น 1,000 Connection พร้อมกัน) Apache จะสร้าง Process/Thread ถึง 1,000 ตัว ซึ่งกินทั้ง RAM และ CPU อย่างมาก

Nginx: Event-driven, Non-blocking

Nginx ใช้สถาปัตยกรรม Event-driven และ Non-blocking I/O กล่าวคือ Worker Process เพียง 1 ตัวสามารถจัดการ Connection ได้หลายพันพร้อมกันโดยไม่ Block การทำงาน ทำให้ Nginx กิน RAM น้อยกว่า Apache อย่างเห็นได้ชัดเมื่อมี Traffic สูง

เลือกอะไรดี? ถ้าคุณรัน Node.js, Python (Django/Flask) หรือ PHP-FPM บน VPS และต้องการ Reverse Proxy ที่เร็วและเบา Nginx คือตัวเลือกที่ดีกว่า ถ้าคุณใช้ cPanel หรือต้องการ .htaccess Apache อาจเหมาะกว่า

ติดตั้ง Nginx บน Ubuntu 22.04

เริ่มต้นด้วยการเชื่อมต่อ VPS ผ่าน SSH จากนั้นรันคำสั่งต่อไปนี้เพื่อติดตั้ง Nginx

ขั้นตอนที่ 1: อัปเดต Package Index และติดตั้ง

apt update && apt install nginx -y

ขั้นตอนที่ 2: เปิดใช้งานและสั่ง Start Service

systemctl enable nginx
systemctl start nginx

คำสั่ง enable ทำให้ Nginx เริ่มทำงานอัตโนมัติเมื่อ Server รีสตาร์ท ส่วน start เริ่ม Service ทันที

ขั้นตอนที่ 3: ตรวจสอบสถานะและ Port 80

# ตรวจสอบว่า Nginx ทำงานอยู่
systemctl status nginx

# ตรวจสอบว่า Port 80 เปิดอยู่
ss -tlnp | grep :80

# ถ้าใช้ UFW ให้เปิด Port HTTP และ HTTPS
ufw allow 'Nginx Full'
ufw status

เปิด Browser แล้วไปที่ IP Address ของ VPS คุณ เช่น http://123.456.789.0 จะเห็นหน้า "Welcome to nginx!" ซึ่งยืนยันว่าติดตั้งสำเร็จ

โครงสร้างไฟล์สำคัญของ Nginx

ก่อนตั้งค่าอะไรเพิ่มเติม ควรทำความเข้าใจโครงสร้างไฟล์ของ Nginx บน Ubuntu

/etc/nginx/
├── nginx.conf              # ไฟล์ config หลัก (global settings)
├── conf.d/                 # Config ที่ include อัตโนมัติ (สำหรับ custom global settings)
├── sites-available/        # ไฟล์ Virtual Host ทั้งหมด (เก็บไว้ ยังไม่ active)
│   └── default             # Virtual Host เริ่มต้น
├── sites-enabled/          # Symlink ของ Virtual Host ที่ active อยู่
│   └── default -> ../sites-available/default
├── modules-available/      # Module ที่ available
├── modules-enabled/        # Module ที่ load อยู่
└── snippets/               # Config ย่อยที่ include ซ้ำได้ (เช่น SSL params)

ตั้งค่า Virtual Host สำหรับ Static Website

Virtual Host (หรือ Server Block ในภาษา Nginx) คือการตั้งค่าให้ Nginx รู้ว่าเมื่อมี Request เข้ามาที่ Domain ใด ให้ Serve ไฟล์จาก Directory ไหน และตั้งค่าอะไรบ้าง

สร้าง Directory สำหรับเว็บไซต์

# สร้าง document root
mkdir -p /var/www/mysite.com/html

# ตั้ง Ownership ให้ www-data (user ที่ Nginx ใช้รัน)
chown -R www-data:www-data /var/www/mysite.com

# ตั้ง Permission ที่เหมาะสม
chmod -R 755 /var/www/mysite.com

สร้างไฟล์ Server Block Config

nano /etc/nginx/sites-available/mysite.conf

ใส่เนื้อหาต่อไปนี้ในไฟล์ โดยเปลี่ยน mysite.com เป็นโดเมนของคุณ

server {
    listen 80;
    listen [::]:80;

    server_name mysite.com www.mysite.com;

    root /var/www/mysite.com/html;
    index index.html index.htm;

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

    # ป้องกันไม่ให้เข้าถึงไฟล์ที่ขึ้นต้นด้วยจุด (เช่น .env, .git)
    location ~ /\. {
        deny all;
    }

    # Log files
    access_log /var/log/nginx/mysite.com.access.log;
    error_log  /var/log/nginx/mysite.com.error.log;
}

Enable Virtual Host และ Reload

# สร้าง Symlink จาก sites-available ไปยัง sites-enabled
ln -s /etc/nginx/sites-available/mysite.conf /etc/nginx/sites-enabled/

# ทดสอบ Config ว่า Syntax ถูกต้อง (สำคัญมาก!)
nginx -t

# ถ้าผ่านแล้ว ให้ Reload (ไม่ Downtime)
systemctl reload nginx

สำคัญ: รัน nginx -t ทุกครั้งก่อน systemctl reload nginx เสมอ ถ้า Config มี Syntax Error แล้ว Reload โดยตรง Nginx อาจหยุดทำงานทำให้เว็บไซต์ล่มได้

Serve Static Files: root, index, try_files และ location blocks

Nginx มี Directive สำคัญหลายตัวสำหรับการ Serve Static Files ที่ควรเข้าใจ

server {
    listen 80;
    server_name mysite.com www.mysite.com;

    root /var/www/mysite.com/html;

    # ไฟล์ index ที่จะ serve เมื่อ request path เป็น directory
    index index.html index.htm;

    # Location block หลัก: ลอง serve ไฟล์ตรง ๆ ก่อน
    # ถ้าไม่เจอ ลอง directory ถ้าไม่เจออีก return 404
    location / {
        try_files $uri $uri/ =404;
    }

    # Cache รูปภาพและ Static Assets เป็น 30 วัน
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2|svg)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }

    # Block การเข้าถึง hidden files
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
}

Nginx เป็น Reverse Proxy สำหรับ Node.js / PHP-FPM

หนึ่งในการใช้งาน Nginx ที่พบบ่อยที่สุดคือการทำ Reverse Proxy รับ Request จาก Browser แล้วส่งต่อไปยัง Application Server ที่รันอยู่ด้านหลัง เช่น Node.js (port 3000) หรือ PHP-FPM (unix socket)

Reverse Proxy สำหรับ Node.js

server {
    listen 80;
    server_name myapp.com www.myapp.com;

    location / {
        proxy_pass http://localhost:3000;

        # ส่ง Header ต้นฉบับไปยัง Application
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Timeout settings
        proxy_connect_timeout 60s;
        proxy_send_timeout    60s;
        proxy_read_timeout    60s;
    }
}

Upstream Block สำหรับ Load Balancing

ถ้าคุณรัน Application หลาย Instance (เช่น Node.js Cluster หรือ Multiple App Servers) สามารถใช้ upstream Block เพื่อกระจาย Traffic ได้

# กำหนด upstream ก่อน server block
upstream myapp_backend {
    # Round-robin load balancing (default)
    server localhost:3000;
    server localhost:3001;
    server localhost:3002;

    # keepalive connections ไว้ใช้ซ้ำ (ดีต่อ performance)
    keepalive 16;
}

server {
    listen 80;
    server_name myapp.com www.myapp.com;

    location / {
        proxy_pass http://myapp_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";  # จำเป็นสำหรับ keepalive
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Reverse Proxy สำหรับ PHP-FPM

server {
    listen 80;
    server_name myphp.com www.myphp.com;

    root /var/www/myphp.com/html;
    index index.php index.html;

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

    # ส่ง PHP files ไปยัง PHP-FPM
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    }

    location ~ /\.ht {
        deny all;
    }
}

ติดตั้ง SSL ด้วย Let's Encrypt และ Certbot

Let's Encrypt เป็น Certificate Authority ฟรีที่ออก SSL Certificate ได้อัตโนมัติ ร่วมกับ Certbot ซึ่งเป็น Client ที่รองรับ Nginx โดยตรง

ขั้นตอนที่ 1: ติดตั้ง Certbot

apt install certbot python3-certbot-nginx -y

ขั้นตอนที่ 2: ออก Certificate และตั้งค่า Nginx อัตโนมัติ

# เปลี่ยน example.com เป็นโดเมนของคุณ
# Certbot จะแก้ไข Nginx config ให้อัตโนมัติและ redirect HTTP → HTTPS
certbot --nginx -d example.com -d www.example.com

Certbot จะถามข้อมูล Email สำหรับแจ้งเตือน Certificate ใกล้หมดอายุ และถามว่าต้องการ Redirect HTTP → HTTPS อัตโนมัติหรือไม่ (แนะนำให้เลือก Yes)

ขั้นตอนที่ 3: ตรวจสอบ Auto-renewal

Certbot ติดตั้ง Systemd Timer หรือ Cron Job ให้อัตโนมัติสำหรับ Renew Certificate ก่อนหมดอายุ ตรวจสอบได้ด้วย

# ทดสอบว่า Auto-renewal ทำงานได้ปกติ (ไม่ Renew จริง)
certbot renew --dry-run

# ดู Timer ของ Systemd
systemctl status certbot.timer

# หรือดู Cron Job (แล้วแต่ระบบ)
cat /etc/cron.d/certbot

Certificate ของ Let's Encrypt มีอายุ 90 วัน Certbot จะ Renew อัตโนมัติเมื่อเหลืออายุน้อยกว่า 30 วัน

ข้อกำหนด: ก่อนออก SSL Certificate ด้วย Let's Encrypt โดเมนของคุณต้องชี้มาที่ IP Address ของ VPS ก่อนแล้ว (DNS A Record ต้องถูกต้อง) มิฉะนั้น Certbot จะ Verify ไม่ผ่าน

Gzip Compression ใน Nginx

การเปิด Gzip Compression ช่วยลดขนาดไฟล์ที่ส่งไปยัง Browser ได้ 60–80% ทำให้หน้าเว็บโหลดเร็วขึ้นอย่างเห็นได้ชัดโดยเฉพาะในไฟล์ HTML, CSS, JS และ JSON

เปิดไฟล์ /etc/nginx/nginx.conf หรือสร้างไฟล์ใหม่ใน /etc/nginx/conf.d/gzip.conf

# เพิ่มใน http block ของ nginx.conf หรือสร้างไฟล์ใน conf.d/
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_types
    text/plain
    text/css
    text/xml
    text/javascript
    application/json
    application/javascript
    application/x-javascript
    application/xml
    application/xml+rss
    application/xhtml+xml
    image/svg+xml
    font/woff
    font/woff2;

Security Headers ใน Nginx

การเพิ่ม Security Headers ช่วยป้องกันการโจมตีประเภทต่าง ๆ เช่น Clickjacking, MIME Sniffing และ Information Leakage เพิ่มได้ใน Server Block หรือ Location Block

server {
    # ... config อื่น ๆ ...

    # ป้องกัน Clickjacking (ไม่ให้ฝัง iframe จาก domain อื่น)
    add_header X-Frame-Options "SAMEORIGIN" always;

    # ป้องกัน MIME Type Sniffing
    add_header X-Content-Type-Options "nosniff" always;

    # ควบคุม Referrer ที่ส่งไปยัง Site อื่น
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # ป้องกัน XSS (Cross-Site Scripting) สำหรับ Browser เก่า
    add_header X-XSS-Protection "1; mode=block" always;

    # บอก Browser ให้ใช้ HTTPS เสมอ (ต้องมี SSL ก่อน)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # ซ่อน Nginx version จาก Header
    server_tokens off;
}

หมายเหตุ: Strict-Transport-Security (HSTS) ควรเพิ่มหลังจากมั่นใจว่า HTTPS ทำงานได้ปกติแล้วเท่านั้น เพราะถ้าเปิดแล้ว SSL มีปัญหา Browser จะปฏิเสธการเข้าถึง HTTP โดยอัตโนมัติในช่วง max-age

ทดสอบ Config และ Reload อย่างปลอดภัย

Nginx มี Built-in Config Test ที่ควรรันทุกครั้งก่อน Reload หรือ Restart เพื่อป้องกัน Downtime จาก Config Error

# ทดสอบ Config Syntax (ไม่กระทบ Server ที่รันอยู่)
nginx -t

# ผลลัพธ์ที่ถูกต้องคือ:
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful

# Reload (ไม่มี Downtime — Graceful reload)
systemctl reload nginx

# Restart (มี Brief Downtime — ใช้เมื่อจำเป็น)
systemctl restart nginx

# ดู Error Log แบบ Real-time
tail -f /var/log/nginx/error.log

# ดู Access Log แบบ Real-time
tail -f /var/log/nginx/access.log

Reload vs Restart: systemctl reload nginx ทำ Graceful Reload โดย Nginx จะ Fork Worker Process ใหม่ที่ใช้ Config ใหม่ ส่วน Worker Process เดิมยังคง Serve Request ที่ค้างอยู่จนเสร็จ ทำให้ไม่มี Downtime ส่วน restart หยุดและเริ่ม Nginx ใหม่ทั้งหมด อาจทำให้ Request หายได้

ปัญหาที่พบบ่อยและวิธีแก้

502 Bad Gateway

เกิดขึ้นเมื่อ Nginx ไม่สามารถเชื่อมต่อกับ Backend ได้ (Node.js, PHP-FPM หยุดทำงาน หรือ Port ผิด)

# ตรวจสอบว่า Backend ทำงานอยู่
systemctl status php8.2-fpm
# หรือสำหรับ Node.js
ps aux | grep node

# ตรวจสอบ Port ที่ Backend ฟังอยู่
ss -tlnp | grep 3000

# ดู Error Log ของ Nginx
tail -100 /var/log/nginx/error.log

# Restart Backend
systemctl restart php8.2-fpm

Permission Denied (403 Forbidden)

มักเกิดจาก File/Directory Permission ไม่ถูกต้อง หรือ SELinux/AppArmor บล็อก

# ตรวจสอบ Ownership ของไฟล์ใน Document Root
ls -la /var/www/mysite.com/

# แก้ไข Ownership ให้ www-data
chown -R www-data:www-data /var/www/mysite.com/

# ตั้ง Permission: Directory = 755, File = 644
find /var/www/mysite.com/ -type d -exec chmod 755 {} \;
find /var/www/mysite.com/ -type f -exec chmod 644 {} \;

Config Syntax Error

เกิดเมื่อแก้ไข Config ผิด ทำให้ nginx -t fail และ Nginx ไม่ Reload

# รันเพื่อดู Error ที่ชัดเจน
nginx -t

# ตัวอย่างข้อผิดพลาดที่พบบ่อย:
# nginx: [emerg] unexpected "}" — ขาดเครื่องหมาย ;
# nginx: [emerg] "server" directive is not allowed here — วาง block ผิดที่
# nginx: [emerg] host not found in upstream — ชื่อ upstream หรือ port ผิด

# ถ้า Config พังและ Nginx หยุดทำงาน ให้ Restore config เดิมก่อน
# แล้วแก้ไขให้ถูกต้องก่อน Start ใหม่

เว็บไซต์แสดง Default Nginx Page แทนเว็บของเรา

# ตรวจสอบว่า Symlink ถูกสร้างแล้ว
ls -la /etc/nginx/sites-enabled/

# ตรวจสอบ server_name ใน Config ว่าตรงกับโดเมนที่ใช้
grep server_name /etc/nginx/sites-available/mysite.conf

# ลบ default site ถ้าไม่ต้องการ
rm /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx

พร้อมรัน Nginx บน VPS ของคุณ?

VPS AsiaGB ให้ Full Root Access ติดตั้ง Nginx, Node.js, PHP-FPM ได้เลยทันที VPS Linux เริ่มต้น 500 บาท/เดือน ดาต้าเซ็นเตอร์ไทย และ สิงคโปร์

ดู VPS AsiaGB