วิชา: Network Security
ผู้จัดทำ: อรรถพล คงหวาน
ออกแบบและติดตั้งระบบเครือข่ายที่ประกอบด้วย:
| องค์ประกอบ | รายละเอียด |
|---|---|
| Web Server | ติดตั้ง Adminer สำหรับจัดการ Database |
| Database Server | ติดตั้ง MariaDB |
| Reverse Proxy | ใช้ Caddy |
| Firewall | ใช้ UFW (Uncomplicated Firewall) |
| VPN | ใช้ WireGuard |
| เครื่อง Gateway | Reverse Proxy + WireGuard + Firewall อยู่ในเครื่องเดียว (Public IP) |
Internet
│
┌────────────────┴────────────────┐
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ Public User │ │ Admin/Dev │
│ (Browser) │ │ (Laptop) │
└──────┬──────┘ └──────┬──────┘
│ HTTP/HTTPS (80/443) │ WireGuard VPN (UDP 51820)
│ │
┌──────▼─────────────────────────────────▼──────┐
│ GATEWAY SERVER (Public IP) │
│ ┌──────────────────────────────────────────┐ │
│ │ UFW Firewall │ │
│ │ - Allow 80/443 from ANY (Public Web) │ │
│ │ - Allow 51820/udp from ANY (WireGuard) │ │
│ │ - Block SSH (22) from Internet │ │
│ │ - Allow SSH (22) from VPN (10.0.0.0/24)│ │
│ ├──────────────────────────────────────────┤ │
│ │ WireGuard Server (wg0: 10.0.0.1/24) │ │
│ ├──────────────────────────────────────────┤ │
│ │ Caddy Reverse Proxy (Port 80/443) │ │
│ └──────────────────────────────────────────┘ │
└───────────────────────┬────────────────────────┘
│ Private Network (eth1)
┌───────────────┴───────────────┐
│ 192.168.100.0/24 │
┌─────┴─────┐ ┌───────┴──────┐
│ Web Server│ │ DB Server │
│ (Adminer) │ │ (MariaDB) │
│192.168. │ │192.168. │
│100.10 │ │100.20 │
└───────────┘ └──────────────┘
SSH: VPN เท่านั้น SSH: VPN เท่านั้น
| การเข้าถึง | Public User | Admin (VPN) |
|---|---|---|
| เว็บ (HTTP/HTTPS) ผ่าน Caddy | ✅ | ✅ |
| SSH เข้า Gateway | ❌ | ✅ |
| SSH เข้า Web Server | ❌ | ✅ |
| SSH เข้า DB Server | ❌ | ✅ |
| เข้า MariaDB โดยตรง | ❌ | ✅ |
| Zone | Network | คำอธิบาย |
|---|---|---|
| Public Zone | <PUBLIC_IP> |
Interface หันออก Internet |
| WireGuard Zone | 10.0.0.0/24 |
VPN Tunnel — Admin เท่านั้น |
| Private Zone | 192.168.100.0/24 |
Internal Network สำหรับ Server |
| เครื่อง | IP | OS | หน้าที่ |
|---|---|---|---|
| Gateway | PUBLIC_IP / 192.168.100.1 / 10.0.0.1 | Ubuntu 22.04 | Firewall + WireGuard + Caddy |
| Web Server | 192.168.100.10 | Ubuntu 22.04 | PHP + Adminer |
| DB Server | 192.168.100.20 | Ubuntu 22.04 | MariaDB |
| Client (Admin) | 10.0.0.2 (VPN) | Windows/Linux | ผู้ดูแลระบบ ใช้ VPN |
หมายเหตุ: แทนที่
PUBLIC_IPด้วย IP จริงของ Gateway Server
sudo apt update && sudo apt upgrade -y
sudo apt install -y wireguard ufw curl gnupg2 debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy -y
sudo mkdir -p /etc/wireguard
cd /etc/wireguard
wg genkey | sudo tee server_private.key | wg pubkey | sudo tee server_public.key
sudo cat server_private.key # ใช้ใน wg0.conf
sudo cat server_public.key # แจกให้ Client
wg genkey | sudo tee client1_private.key | wg pubkey | sudo tee client1_public.key
sudo cat client1_private.key # ส่งให้ Client เก็บ
sudo cat client1_public.key # ใส่ใน Server config
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
ip route | grep default
# ตัวอย่าง: default via 203.0.113.1 dev eth0
# แสดงว่า interface ที่หันออก Internet คือ eth0
sudo nano /etc/wireguard/wg0.conf
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <SERVER_PRIVATE_KEY>
# NAT: ให้ VPN Client ออก Internet ผ่าน Gateway (Full Tunnel)
PostUp = ufw route allow in on wg0 out on eth0
PostUp = iptables -t nat -I POSTROUTING -o eth0 -j MASQUERADE
PostDown = ufw route delete allow in on wg0 out on eth0
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
PublicKey = <CLIENT1_PUBLIC_KEY>
AllowedIPs = 10.0.0.2/32
sudo chmod 600 /etc/wireguard/wg0.conf
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
sudo wg show
หลักการ: แยก Public Traffic (Web) ออกจาก Admin Traffic (SSH) อย่างชัดเจน
SSH จาก Internet ถูก Block โดย Default Deny — ไม่มี ruleallow 22ให้เห็นเลย
sudo ufw --force reset
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw default allow routed
# ─── WireGuard VPN ─────────────────────────────────────────────────
# ทุกคน connect VPN ได้ (จำเป็นสำหรับ Admin ที่จะ SSH เข้า)
sudo ufw allow 51820/udp comment 'WireGuard VPN'
# ─── Web (Public Access) ───────────────────────────────────────────
# ผู้ใช้ทั่วไปเข้าเว็บได้โดยตรง ไม่ต้องต่อ VPN
sudo ufw allow 80/tcp comment 'HTTP - Caddy Public'
sudo ufw allow 443/tcp comment 'HTTPS - Caddy Public'
sudo ufw allow 443/udp comment 'HTTPS/3 - Caddy Public'
# ─── SSH (VPN เท่านั้น) ────────────────────────────────────────────
# อนุญาต SSH เฉพาะ Traffic ที่เข้ามาทาง interface wg0 (VPN) เท่านั้น
# ⚠️ จงใจไม่ใส่ "ufw allow 22" — SSH จาก Internet จะถูก Block
sudo ufw allow in on wg0 to any port 22 proto tcp comment 'SSH via VPN only'
# ─── VPN Routing ───────────────────────────────────────────────────
# อนุญาต VPN Client เข้าถึง Private Network (Web + DB)
sudo ufw allow in on wg0 to 192.168.100.0/24 comment 'VPN to Private Network'
# อนุญาต VPN Client ออก Internet (Full Tunnel)
sudo ufw allow in on wg0 out on eth0 comment 'VPN Full Tunnel to Internet'
sudo nano /etc/ufw/before.rules
เพิ่มส่วนนี้ที่ บนสุดของไฟล์ (ก่อน *filter):
# NAT สำหรับ WireGuard Full Tunnel
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE
COMMIT
sudo nano /etc/default/ufw
# เปลี่ยน: DEFAULT_FORWARD_POLICY="DROP"
# เป็น: DEFAULT_FORWARD_POLICY="ACCEPT"
sudo ufw enable
sudo ufw status verbose
ผลลัพธ์ที่ควรได้:
Status: active
Default: deny (incoming), allow (outgoing), allow (routed)
To Action From
-- ------ ----
51820/udp ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
443/udp ALLOW IN Anywhere
22/tcp on wg0 ALLOW IN Anywhere ← SSH ผ่าน VPN เท่านั้น
192.168.100.0/24 on wg0 ALLOW IN Anywhere
Anywhere on wg0 ALLOW FWD Anywhere on eth0
สังเกต: ไม่มี
22 ALLOW Anywhere— SSH จาก Internet ตก Default Deny ทันที
# จาก Internet (ไม่ได้ต่อ VPN) — ต้อง FAIL
ssh -o ConnectTimeout=5 ubuntu@PUBLIC_IP
# → ssh: connect to host PUBLIC_IP port 22: Connection timed out ✓
# จาก Internet — ต้อง SUCCESS
curl -s -o /dev/null -w "%{http_code}" http://PUBLIC_IP
# → 200 หรือ 301 ✓
# หลังต่อ VPN — SSH ต้อง SUCCESS
ssh ubuntu@10.0.0.1
# → เชื่อมต่อได้ ✓
Caddy เปิดรับ Traffic จากทุกคน (Public) และ Forward ไปยัง Web Server ใน Private Network
sudo nano /etc/caddy/Caddyfile
# ========================================
# Caddy Reverse Proxy — Public Access
# ไม่ restrict IP: ผู้ใช้ทั่วไปเข้าได้เลย
# ========================================
# Option A: ใช้ Domain (Caddy จัดการ SSL อัตโนมัติ)
adminer.yourdomain.com {
reverse_proxy 192.168.100.10:8080
log {
output file /var/log/caddy/access.log
format json
}
header {
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
X-XSS-Protection "1; mode=block"
Referrer-Policy "strict-origin-when-cross-origin"
}
}
# Option B: ใช้ IP โดยตรง (สำหรับแลบที่ไม่มี Domain)
:80 {
reverse_proxy 192.168.100.10:8080
log {
output file /var/log/caddy/access.log
format json
}
}
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl enable caddy
sudo systemctl restart caddy
sudo systemctl status caddy
# ทำบนเครื่อง DB Server (192.168.100.20)
sudo apt update
sudo apt install -y mariadb-server mariadb-client
sudo systemctl enable mariadb
sudo systemctl start mariadb
sudo mysql_secure_installation
Enter current password for root: [กด Enter]
Switch to unix_socket authentication: n
Change the root password: Y → StrongP@ssw0rd!
Remove anonymous users: Y
Disallow root login remotely: Y
Remove test database: Y
Reload privilege tables: Y
sudo mysql -u root -p
CREATE DATABASE labdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- User สำหรับ Adminer (Web Server เชื่อมต่อผ่าน Private Network)
CREATE USER 'adminer_user'@'192.168.100.10' IDENTIFIED BY 'SecurePass123!';
GRANT ALL PRIVILEGES ON labdb.* TO 'adminer_user'@'192.168.100.10';
-- User สำหรับ Admin ที่เข้าผ่าน VPN โดยตรง
CREATE USER 'dbadmin'@'10.0.0.%' IDENTIFIED BY 'VpnAdminPass789!';
GRANT ALL PRIVILEGES ON labdb.* TO 'dbadmin'@'10.0.0.%';
FLUSH PRIVILEGES;
SELECT user, host FROM mysql.user;
EXIT;
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
# ฟัง Private IP เท่านั้น — ไม่รับ connection จาก Internet
bind-address = 192.168.100.20
sudo systemctl restart mariadb
ss -tlnp | grep 3306
# ต้องเห็น: 192.168.100.20:3306
sudo apt install ufw -y
sudo ufw default deny incoming
sudo ufw default allow outgoing
# SSH: อนุญาตเฉพาะจาก VPN Network (Admin ที่ต่อ WireGuard แล้ว)
sudo ufw allow from 10.0.0.0/24 to any port 22 proto tcp comment 'SSH from VPN only'
# MariaDB: อนุญาตจาก Web Server และ VPN Admin
sudo ufw allow from 192.168.100.10 to any port 3306 comment 'MariaDB from Web Server'
sudo ufw allow from 10.0.0.0/24 to any port 3306 comment 'MariaDB from VPN Admin'
sudo ufw enable
sudo ufw status
# ทำบนเครื่อง Web Server (192.168.100.10)
sudo apt update
sudo apt install -y php php-fpm php-mysql nginx curl
sudo systemctl enable nginx php8.1-fpm
sudo systemctl start nginx php8.1-fpm
# ดาวน์โหลด Adminer
sudo mkdir -p /var/www/adminer
sudo curl -L https://github.com/vrana/adminer/releases/download/v4.8.1/adminer-4.8.1-mysql.php \
-o /var/www/adminer/index.php
sudo chown -R www-data:www-data /var/www/adminer
sudo nano /etc/nginx/sites-available/adminer
server {
listen 8080;
server_name _;
root /var/www/adminer;
index index.php;
# รับ request เฉพาะจาก Caddy (Gateway) เท่านั้น
# ผู้ใช้ทั่วไปเข้าผ่าน Caddy → Caddy ส่ง request มาจาก 192.168.100.1
# Admin ที่ต่อ VPN ก็ Route ผ่าน Gateway (192.168.100.1) เช่นกัน
allow 192.168.100.1; # Gateway (Caddy Reverse Proxy)
allow 10.0.0.0/8; # VPN Network (Admin เข้าโดยตรง)
deny all;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
}
sudo ln -s /etc/nginx/sites-available/adminer /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl restart nginx
sudo apt install ufw -y
sudo ufw default deny incoming
sudo ufw default allow outgoing
# SSH: อนุญาตเฉพาะจาก VPN Network
sudo ufw allow from 10.0.0.0/24 to any port 22 proto tcp comment 'SSH from VPN only'
# HTTP (Adminer): รับจาก Gateway (Caddy) เท่านั้น
# ผู้ใช้ทั่วไปและ Admin ต่างผ่าน Caddy บน Gateway
sudo ufw allow from 192.168.100.1 to any port 8080 comment 'Adminer from Caddy/Gateway'
sudo ufw enable
sudo ufw status
sudo nano /etc/wireguard/wg0.conf
[Interface]
PrivateKey = <CLIENT1_PRIVATE_KEY>
Address = 10.0.0.2/24
DNS = 1.1.1.1, 8.8.8.8
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = <PUBLIC_IP>:51820
# Full Tunnel: Traffic ทั้งหมดรวม Internet ผ่าน VPN
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
sudo wg-quick up wg0
sudo wg show
# ทดสอบ Full Tunnel
curl ifconfig.me # ควรได้ PUBLIC_IP ของ Gateway
# ทดสอบ SSH ผ่าน VPN
ssh ubuntu@10.0.0.1 # SSH เข้า Gateway
ssh ubuntu@192.168.100.10 # SSH เข้า Web Server
ssh ubuntu@192.168.100.20 # SSH เข้า DB Server
ติดตั้ง WireGuard for Windows แล้วสร้าง config:
[Interface]
PrivateKey = <CLIENT1_PRIVATE_KEY>
Address = 10.0.0.2/24
DNS = 1.1.1.1
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = <PUBLIC_IP>:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
# จากเครื่องใด ๆ ใน Internet — ไม่ต้องต่อ VPN
curl -I http://PUBLIC_IP
# → HTTP/1.1 200 OK ✓
curl -I https://adminer.yourdomain.com
# → HTTP/2 200 พร้อม SSL cert อัตโนมัติจาก Caddy ✓
# จาก Internet โดยไม่ต่อ VPN — ต้อง FAIL ทั้งหมด
ssh -o ConnectTimeout=5 ubuntu@PUBLIC_IP
# → Connection timed out ✓ (UFW block)
ssh -o ConnectTimeout=5 ubuntu@192.168.100.10
# → ไม่สามารถ reach Private IP ได้เลย ✓
# เชื่อมต่อ VPN ก่อน
sudo wg-quick up wg0
# SSH เข้าแต่ละ Server — ทุกเครื่องต้อง SUCCESS
ssh ubuntu@10.0.0.1 # Gateway ✓
ssh ubuntu@192.168.100.10 # Web Server ✓
ssh ubuntu@192.168.100.20 # DB Server ✓
# ก่อนต่อ VPN
curl ifconfig.me # → IP ของ Client จริง
# หลังต่อ VPN
sudo wg-quick up wg0
curl ifconfig.me # → PUBLIC_IP ของ Gateway ✓ (Full Tunnel ทำงาน)
sudo nano /home/ubuntu/check_lab.sh
#!/bin/bash
GREEN='\033[0;32m'; RED='\033[0;31m'; NC='\033[0m'
ok() { echo -e "${GREEN}✓${NC} $1"; }
fail() { echo -e "${RED}✗${NC} $1"; }
echo "════════════════════════════════════"
echo " Network Lab Health Check"
echo "════════════════════════════════════"
echo -e "\n[1] Services:"
systemctl is-active wg-quick@wg0 &>/dev/null && ok "WireGuard" || fail "WireGuard"
systemctl is-active caddy &>/dev/null && ok "Caddy" || fail "Caddy"
systemctl is-active ufw &>/dev/null && ok "UFW" || fail "UFW"
echo -e "\n[2] UFW — SSH Rules (ต้องไม่มี 22 ALLOW จาก Anywhere):"
sudo ufw status | grep 22
echo -e "\n[3] WireGuard Peers:"
sudo wg show | grep -E "peer|endpoint|handshake|transfer"
echo -e "\n[4] Private Network:"
ping -c1 -W2 192.168.100.10 &>/dev/null && ok "Web Server (192.168.100.10)" || fail "Web Server"
ping -c1 -W2 192.168.100.20 &>/dev/null && ok "DB Server (192.168.100.20)" || fail "DB Server"
echo -e "\n[5] Caddy → Web Server:"
CODE=$(curl -s -o /dev/null -w "%{http_code}" http://192.168.100.10:8080)
[ "$CODE" = "200" ] && ok "Adminer OK (HTTP $CODE)" || fail "Adminer HTTP $CODE"
echo -e "\n[6] Outbound IP (Full Tunnel):"
echo " $(curl -s --max-time 5 ifconfig.me)"
echo -e "\n════════════════════════════════════"
chmod +x /home/ubuntu/check_lab.sh
sudo /home/ubuntu/check_lab.sh
| Port | Protocol | Service | จาก Internet | จาก VPN | หมายเหตุ |
|---|---|---|---|---|---|
| 22 | TCP | SSH — Gateway | ❌ Block | ✅ Allow | wg0 interface เท่านั้น |
| 51820 | UDP | WireGuard | ✅ Allow | — | ทุกคน connect VPN ได้ |
| 80 | TCP | HTTP — Caddy | ✅ Allow | ✅ Allow | Public Web Access |
| 443 | TCP/UDP | HTTPS — Caddy | ✅ Allow | ✅ Allow | Public Web Access |
| 22 | TCP | SSH — Web Server | ❌ Block | ✅ Allow | Private IP + VPN only |
| 8080 | TCP | Adminer — Nginx | ❌ (Private) | ✅ Allow | ผ่าน Caddy เท่านั้น |
| 22 | TCP | SSH — DB Server | ❌ Block | ✅ Allow | Private IP + VPN only |
| 3306 | TCP | MariaDB | ❌ Block | ✅ Allow | Private IP + VPN only |
# ตรวจสอบ rule บน Gateway — ต้องเห็น "on wg0"
sudo ufw status | grep 22
# Expected: 22/tcp on wg0 ALLOW IN Anywhere
# ตรวจสอบว่า VPN handshake สำเร็จ
sudo wg show
# latest handshake ต้องไม่นานเกิน 3 นาที
# ping ทดสอบ
ping 10.0.0.1 # จาก Client
# Caddy log
sudo journalctl -u caddy -n 50
# ทดสอบ Web Server ตอบสนองหรือไม่
curl -v http://192.168.100.10:8080
# UFW บน Web Server ต้องอนุญาต 192.168.100.1:8080
sudo ufw status # (บน Web Server)
# ตรวจสอบ IP Forwarding
cat /proc/sys/net/ipv4/ip_forward # ต้องเป็น 1
# ตรวจสอบ NAT rule
sudo iptables -t nat -L POSTROUTING -v -n
# ต้องเห็น MASQUERADE สำหรับ 10.0.0.0/24
# ตรวจสอบ Client config
# AllowedIPs ต้องเป็น 0.0.0.0/0, ::/0
ufw allow 22 กับ ufw allow in on wg0 to any port 22 ว่ามีผลต่างกันอย่างไร10.0.0.3) และทดสอบว่า SSH ได้ทุก Server หรือไม่เอกสารนี้จัดทำสำหรับการเรียนการสอนเท่านั้น | อรรถพล คงหวาน | มหาวิทยาลัยเทคโนโลยีราชมงคลศรีวิชัย