Cấu hình Apache Virtual Host: Chạy Nhiều Website trên Cùng Một Server

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

Khởi động nhanh — Cài Apache trong 5 phút

Chỉ cần cài Apache và serve một trang? Đây là con đường ngắn nhất. Mình giả sử bạn đang dùng Ubuntu 22.04 — cũng là setup mình chạy trên production.

# Cài đặt Apache
sudo apt update
sudo apt install apache2 -y

# Kiểm tra xem Apache có đang chạy không
sudo systemctl status apache2

# Mở firewall cho HTTP và HTTPS
sudo ufw allow 'Apache Full'

Mở trình duyệt và truy cập http://your-server-ip. Bạn sẽ thấy trang mặc định Apache2 Ubuntu Default Page — Apache đã chạy.

Thư mục web root mặc định là /var/www/html/. Đặt file index.html vào đó là hiển thị ngay. Vậy là xong phần cơ bản.

Giờ đến câu hỏi thực sự: nếu bạn muốn chạy hai hoặc nhiều website khác nhau trên cùng một server? Đó là lúc virtual host phát huy tác dụng.

Tìm hiểu sâu — Virtual Host là gì?

Virtual Host là gì?

Virtual host nói với Apache: “Khi có request đến cho domain A, serve file từ thư mục này. Khi là domain B, serve từ thư mục kia.”

Apache hỗ trợ hai loại:

  • Name-based virtual hosts — nhiều domain dùng chung một địa chỉ IP (phổ biến nhất)
  • IP-based virtual hosts — mỗi domain có IP riêng (hiếm gặp, chủ yếu cho các setup SSL cũ)

Trong hướng dẫn này mình dùng name-based virtual hosts xuyên suốt. Đây là kiểu mà 99% các setup đều sử dụng.

Cấu trúc file config của Apache

Trước khi chỉnh sửa gì, hãy hiểu cách Apache tổ chức các file config trên Ubuntu:

/etc/apache2/
├── apache2.conf          # Config chính
├── ports.conf            # Apache lắng nghe trên những port nào
├── sites-available/      # Tất cả config virtual host (đã bật hay chưa)
│   ├── 000-default.conf  # Config site mặc định
│   └── default-ssl.conf
├── sites-enabled/        # Symlink đến các site đang hoạt động
├── mods-available/       # Các module Apache có sẵn
└── mods-enabled/         # Symlink đến các module đang hoạt động

Ý tưởng cốt lõi là: viết config trong sites-available/, sau đó bật nó bằng a2ensite. Lệnh đó tạo symlink trong sites-enabled/. Apache chỉ đọc những gì được symlink vào đó — không đọc gì khác.

Thiết lập Virtual Host đầu tiên

Giả sử bạn đang host hai site: site1.comsite2.com.

Bước 1 — Tạo thư mục web root:

sudo mkdir -p /var/www/site1.com/public_html
sudo mkdir -p /var/www/site2.com/public_html

# Đặt quyền sở hữu đúng
sudo chown -R $USER:$USER /var/www/site1.com
sudo chown -R $USER:$USER /var/www/site2.com

# Đặt permissions
sudo chmod -R 755 /var/www/site1.com
sudo chmod -R 755 /var/www/site2.com

Bước 2 — Thêm trang test cho mỗi site:

echo '<h1>Chào mừng đến Site 1</h1>' | sudo tee /var/www/site1.com/public_html/index.html
echo '<h1>Chào mừng đến Site 2</h1>' | sudo tee /var/www/site2.com/public_html/index.html

Bước 3 — Tạo file config virtual host:

sudo nano /etc/apache2/sites-available/site1.com.conf

Dán nội dung sau vào:

<VirtualHost *:80>
    ServerName site1.com
    ServerAlias www.site1.com
    DocumentRoot /var/www/site1.com/public_html

    ErrorLog ${APACHE_LOG_DIR}/site1-error.log
    CustomLog ${APACHE_LOG_DIR}/site1-access.log combined

    <Directory /var/www/site1.com/public_html>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

Với site2, copy file đó rồi thay hàng loạt:

sudo cp /etc/apache2/sites-available/site1.com.conf /etc/apache2/sites-available/site2.com.conf
sudo sed -i 's/site1/site2/g' /etc/apache2/sites-available/site2.com.conf

Bước 4 — Bật các site và reload Apache:

sudo a2ensite site1.com.conf
sudo a2ensite site2.com.conf

# Tùy chọn: tắt site mặc định
sudo a2dissite 000-default.conf

# Kiểm tra config trước khi reload — luôn làm bước này
sudo apache2ctl configtest

# Reload Apache
sudo systemctl reload apache2

Nếu configtest in ra Syntax OK là ổn. Đừng bỏ qua bước này — nó đã cứu mình khỏi không ít cơn đau đầu lúc 3 giờ sáng.

Nâng cao — HTTPS, .htaccess và nhiều Port

Bật HTTPS với Let’s Encrypt (Certbot)

HTTP chạy tốt cho môi trường test local. Còn production thì bạn cần HTTPS — và Certbot là cách gọn nhất để làm điều đó:

sudo apt install certbot python3-certbot-apache -y
sudo certbot --apache -d site1.com -d www.site1.com

Certbot hỏi email, bạn đồng ý điều khoản, và nó tự động chỉnh sửa config Apache để thêm SSL. Tự động gia hạn chạy qua systemd timer. Chuyện certificate hết hạn trở thành việc của người khác lo.

Kiểm tra việc gia hạn hoạt động trước khi bạn quên mất:

sudo certbot renew --dry-run

Dùng .htaccess cho các rule theo từng thư mục

AllowOverride All trong config virtual host là thứ cho phép dùng file .htaccess. Với nó, bạn có thể đặt các rewrite rule, redirect và kiểm soát truy cập theo từng thư mục — mà không cần chạm vào config Apache chính.

Redirect HTTP sang HTTPS và bỏ tiền tố www là hai trường hợp phổ biến nhất:

# /var/www/site1.com/public_html/.htaccess
RewriteEngine On

# Redirect www về non-www
RewriteCond %{HTTP_HOST} ^www\.site1\.com [NC]
RewriteRule ^ https://site1.com%{REQUEST_URI} [L,R=301]

# Redirect HTTP sang HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Đảm bảo mod_rewrite đã được bật:

sudo a2enmod rewrite
sudo systemctl reload apache2

Chạy Virtual Host trên port không chuẩn

Port 80 đã bị service khác chiếm? Thêm port 8080 vào ports.conf trước:

echo 'Listen 8080' | sudo tee -a /etc/apache2/ports.conf

Sau đó đổi *:80 thành *:8080 trong config virtual host:

<VirtualHost *:8080>
    ServerName site1.com
    DocumentRoot /var/www/site1.com/public_html
    ...
</VirtualHost>

Mẹo thực chiến từ kinh nghiệm thực tế

File log riêng cho từng Virtual Host

Luôn khai báo ErrorLogCustomLog riêng cho mỗi virtual host. Khi site2 lỗi lúc 2 giờ sáng, bạn muốn xem thẳng log của nó — chứ không phải lục tìm trong một file chứa log lẫn lộn từ năm site khác nhau:

sudo tail -f /var/log/apache2/site2-error.log

Kiểm tra Apache đang dùng config nào

# Liệt kê tất cả site đang bật
ls -la /etc/apache2/sites-enabled/

# Hiển thị toàn bộ config đã biên dịch
sudo apache2ctl -S

Flag -S là thứ mình dùng đầu tiên khi có gì đó không ổn. Nó hiển thị mọi virtual host đang hoạt động, port nó bind vào, và document root của nó. Không cần đoán mò.

Ghi chú về hiệu năng từ setup của mình

Trên server Ubuntu 22.04 với 4GB RAM, mình đã chuyển từ prefork MPM sang event MPM sau khi bật PHP-FPM. Sự khác biệt rất rõ ràng: prefork cấp phát khoảng 35MB mỗi worker process, giới hạn ở tầm 60–70 request đồng thời trước khi hết RAM. Sau khi chuyển sang event MPM + PHP-FPM, cùng cái máy đó xử lý thoải mái 200+ kết nối đồng thời — Apache gần như stateless, còn PHP-FPM tự quản lý pool worker riêng của nó.

# Chuyển từ prefork sang event MPM
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
sudo systemctl restart apache2

Nếu bạn chạy PHP, kết hợp cái này với PHP-FPM và module proxy_fcgi. Nhiều visitor đồng thời hơn, cùng phần cứng.

Checklist debug nhanh

Khi virtual host không hoạt động, chạy qua danh sách này theo thứ tự:

  1. Chạy sudo apache2ctl configtest — lỗi cú pháp sẽ chặn mọi thứ
  2. Kiểm tra sudo systemctl status apache2 — Apache có đang chạy không?
  3. Xác nhận DNS trỏ đúng IP server (hoặc test local bằng cách sửa /etc/hosts)
  4. Kiểm tra permissions trên document root — Apache cần quyền đọc
  5. Đọc log lỗi của từng site cụ thể, không phải log chung
  6. Xác nhận module cần thiết đã được bật (ls /etc/apache2/mods-enabled/)

Apache virtual host trông có vẻ phức tạp trên giấy. Nhưng cài đặt một lần là toàn bộ hệ thống vào guồng ngay. Cách tổ chức symlink giữa sites-availablesites-enabled, các shortcut a2ensite/a2dissite — nó scale tốt dù bạn đang chạy 2 site hay 20 site trên cùng một máy.

Share: