Vấn đề mình gặp khi deploy web lần đầu
Hồi mới bắt đầu với Linux server, mình từng deploy một project PHP lên VPS Ubuntu rồi ngồi thắc mắc tại sao truy cập IP lại ra trang mặc định của Apache, còn project của mình thì không thấy đâu. Mất gần nửa ngày mới vỡ ra: cài Apache xong là chưa đủ — còn phải cấu hình virtual host, phân quyền thư mục, và mở đúng port trên firewall.
Khoảng 6 tháng chạy Apache2 trên production — gồm một web app của team 5 developer — mình đã qua đủ kiểu lỗi “ngớ ngẩn” mà docs chính thức không đề cập. Bài này là quy trình mình đang thực sự dùng, không phải copy-paste từ manual.
Tại sao Apache2 lại gây rắc rối ngay từ đầu?
Vấn đề không phải Apache phức tạp. Ubuntu 22.04 có một vài thay đổi so với các bản cũ mà nhiều tutorial chưa kịp cập nhật:
- UFW mặc định chặn port 80/443 — cài xong Apache nhưng firewall vẫn block traffic.
- Cấu trúc thư mục
/etc/apache2/dùng hệ thốngsites-available/sites-enabled— khác hoàn toàn với cách ghi trong nhiều tài liệu cũ. - PHP-FPM vs mod_php — từ PHP 7.4 trở đi, Ubuntu khuyến khích PHP-FPM nhưng cần cấu hình thêm, không tự động như trước.
Hiểu được 3 điểm này là hiểu được 80% lý do tại sao Apache “hoạt động mà không hoạt động” trên máy bạn.
Cài đặt Apache2
Update package list rồi cài:
sudo apt update
sudo apt install apache2 -y
Kiểm tra Apache đã chạy chưa:
sudo systemctl status apache2
Thấy active (running) là ổn. Nếu ra failed, chạy sudo journalctl -xe để xem lý do cụ thể. Enable auto-start khi reboot:
sudo systemctl enable apache2
Mở firewall đúng cách với UFW
Đây là bước hay bị bỏ qua nhất. Apache cài sẵn profile cho UFW:
# Xem các profile có sẵn
sudo ufw app list
# Cho phép HTTP và HTTPS
sudo ufw allow 'Apache Full'
# Nếu chỉ cần HTTP trước
sudo ufw allow 'Apache'
# Bật UFW nếu chưa bật
sudo ufw enable
sudo ufw status
Sau bước này, gõ IP server vào trình duyệt sẽ thấy trang “Apache2 Ubuntu Default Page” — xác nhận mọi thứ đang chạy đúng.
Cấu hình Virtual Host — theo chuẩn Ubuntu
Mình thấy nhiều người hay chỉnh thẳng vào /etc/apache2/apache2.conf, đây là cách làm sai. Trên Ubuntu, mỗi website nên có một file cấu hình riêng trong /etc/apache2/sites-available/.
Tạo thư mục cho website
sudo mkdir -p /var/www/mywebsite.com/public
sudo chown -R $USER:$USER /var/www/mywebsite.com
sudo chmod -R 755 /var/www/mywebsite.com
Tạo file cấu hình virtual host
sudo nano /etc/apache2/sites-available/mywebsite.com.conf
Nội dung file:
<VirtualHost *:80>
ServerName mywebsite.com
ServerAlias www.mywebsite.com
ServerAdmin [email protected]
DocumentRoot /var/www/mywebsite.com/public
<Directory /var/www/mywebsite.com/public>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/mywebsite.com-error.log
CustomLog ${APACHE_LOG_DIR}/mywebsite.com-access.log combined
</VirtualHost>
Kích hoạt site và reload Apache
# Enable site mới
sudo a2ensite mywebsite.com.conf
# Disable site mặc định nếu không cần
sudo a2dissite 000-default.conf
# Kiểm tra cú pháp config
sudo apache2ctl configtest
# Reload Apache
sudo systemctl reload apache2
Lệnh apache2ctl configtest là bước mình luôn chạy trước khi reload — tránh tình huống Apache crash vì config sai cú pháp.
Bật module cần thiết
Apache2 trên Ubuntu dùng lệnh a2enmod để bật module. Một số module hay dùng:
# Bắt buộc nếu dùng .htaccess với WordPress/Laravel
sudo a2enmod rewrite
# SSL
sudo a2enmod ssl
# Nén gzip cho tĩnh
sudo a2enmod deflate
# Header security
sudo a2enmod headers
sudo systemctl restart apache2
Với dự án team 5 developer, mình gộp 4 lệnh này vào script bootstrap server. Chạy một lần là xong — không còn cảnh dev và production lệch module rồi ngồi debug cả buổi.
Cài đặt SSL với Let’s Encrypt
Domain đã trỏ về server rồi thì Certbot là nhanh nhất:
sudo apt install certbot python3-certbot-apache -y
sudo certbot --apache -d mywebsite.com -d www.mywebsite.com
Certbot tự sửa file .conf của bạn, thêm cấu hình SSL port 443, và tạo redirect từ HTTP sang HTTPS. Chứng chỉ có hạn 90 ngày nhưng auto-renew đã được set sẵn qua systemd timer:
# Kiểm tra timer auto-renew
sudo systemctl status certbot.timer
# Test thử renewal
sudo certbot renew --dry-run
Tổ chức nhiều website trên 1 VPS
Sau khi chạy nhiều project trên cùng VPS, mình đúc kết ra cấu trúc này:
/var/www/
├── site1.com/
│ └── public/ # DocumentRoot
├── site2.com/
│ └── public/
└── site3.com/
└── public/
/etc/apache2/
├── sites-available/
│ ├── site1.com.conf
│ ├── site2.com.conf
│ └── site3.com.conf
└── sites-enabled/ # Chỉ chứa symlink, đừng tạo file ở đây
Nguyên tắc: mỗi domain một file conf riêng, dùng a2ensite/a2dissite để bật tắt — không bao giờ sửa thẳng sites-enabled.
Đọc log khi có lỗi
9/10 lần gặp lỗi Apache, câu trả lời nằm ngay trong error log:
# Xem lỗi real-time
sudo tail -f /var/log/apache2/error.log
# Xem log theo domain (nếu đã cấu hình custom log)
sudo tail -f /var/log/apache2/mywebsite.com-error.log
# Xem access log
sudo tail -f /var/log/apache2/mywebsite.com-access.log
Lỗi 403 Forbidden? Thường là phân quyền thư mục sai hoặc thiếu AllowOverride All trong config. Lỗi 500? Error log sẽ chỉ ra ngay dòng lỗi cụ thể — không cần đoán mò.
Tóm tắt quy trình chuẩn
- Cài Apache2 → enable service
- Mở firewall với UFW (
Apache Full) - Tạo thư mục website với đúng permission
- Tạo file
.conftrongsites-available - Enable site bằng
a2ensite, test config, reload - Bật các module cần thiết (
rewrite,ssl, …) - Cài SSL với Certbot
Thực ra Apache2 không đáng sợ như nhiều người nghĩ. Phần lớn trường hợp server “không vào được”, nguyên nhân chỉ là UFW chưa mở port hoặc virtual host chưa enable. Kiểm tra 2 thứ đó trước — rồi mới bắt đầu tìm nguyên nhân phức tạp hơn.

