LAMP Stack là gì và khi nào bạn cần nó?
Nếu bạn mới bắt đầu học lập trình web backend hoặc vừa nhận task deploy một ứng dụng PHP lên server, khả năng cao bạn sẽ cần LAMP Stack. Đây là bộ tứ gồm Linux + Apache + MySQL + PHP — nền tảng chạy WordPress, Laravel, Drupal và hàng trăm ứng dụng PHP khác. Apache một mình chiếm khoảng 30% thị phần web server toàn cầu, nên biết cách dựng LAMP là kỹ năng khá thiết thực.
Mình đã dùng LAMP trên môi trường staging của công ty (Ubuntu 22.04) để test config trước khi đẩy lên production. Bài học nhớ đời: cài đúng thứ tự, cấu hình đúng ngay từ đầu. Làm ngược lại thì mất cả buổi chiều debug những thứ lẽ ra không đáng mất thời gian.
Bài này chọn Apache thay vì Nginx vì nhiều dự án legacy PHP vẫn cần module mod_rewrite và .htaccess. Nếu bạn đang tìm cách cài Nginx, blog đã có bài riêng.
Cài đặt từng thành phần
1. Cập nhật hệ thống
Trước khi cài bất cứ thứ gì, luôn cập nhật package list — bỏ qua bước này thì hay gặp conflict phiên bản về sau:
sudo apt update && sudo apt upgrade -y
2. Cài Apache
sudo apt install apache2 -y
Xong rồi, khởi động và bật auto-start:
sudo systemctl start apache2
sudo systemctl enable apache2
Nếu đang dùng UFW, mở port 80:
sudo ufw allow 'Apache'
sudo ufw reload
Truy cập http://<IP-server> trên trình duyệt. Thấy trang “Apache2 Ubuntu Default Page” là ổn.
3. Cài MySQL
sudo apt install mysql-server -y
Chạy script bảo mật — cái này quan trọng, đừng bỏ qua:
sudo mysql_secure_installation
Script hỏi bạn một loạt câu hỏi. Với môi trường production, mình luôn chọn như sau:
- VALIDATE PASSWORD component: Y (bật kiểm tra độ mạnh mật khẩu)
- Remove anonymous users: Y
- Disallow root login remotely: Y
- Remove test database: Y
- Reload privilege tables: Y
Đăng nhập MySQL để xác nhận mọi thứ ổn:
sudo mysql -u root -p
4. Cài PHP
Ubuntu 22.04 ship PHP 8.1 trong repo mặc định. Cài luôn các extension hay dùng:
sudo apt install php libapache2-mod-php php-mysql php-cli php-curl php-gd php-mbstring php-xml php-zip -y
Vì sao cần những extension này? Tóm tắt nhanh:
php-mysql— kết nối PHP với MySQL/MariaDBphp-mbstring— xử lý chuỗi đa byte (cần cho tiếng Việt, tiếng Nhật…)php-xml— xử lý XML, nhiều framework PHP không chạy được nếu thiếu cái nàyphp-zip— WordPress dùng khi cài hoặc update plugin
Kiểm tra phiên bản:
php -v
Cấu hình chi tiết
Tạo Virtual Host cho ứng dụng của bạn
Để code trong /var/www/html mặc định chỉ ổn khi test nhanh. Mình luôn tạo Virtual Host riêng cho mỗi dự án — cách này giúp chạy song song nhiều website trên cùng một server mà không đụng nhau.
Tạo thư mục dự án và phân quyền:
sudo mkdir -p /var/www/myapp/public
sudo chown -R $USER:$USER /var/www/myapp/public
sudo chmod -R 755 /var/www/myapp
Mở file config Virtual Host mới:
sudo nano /etc/apache2/sites-available/myapp.conf
Điền nội dung sau vào:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
ServerName myapp.local
DocumentRoot /var/www/myapp/public
<Directory /var/www/myapp/public>
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/myapp-error.log
CustomLog ${APACHE_LOG_DIR}/myapp-access.log combined
</VirtualHost>
Bật site và module mod_rewrite — Laravel và WordPress đều cần cái này:
sudo a2ensite myapp.conf
sudo a2enmod rewrite
sudo systemctl restart apache2
Tạo database và user MySQL cho ứng dụng
Không bao giờ dùng root để kết nối từ ứng dụng — tạo user riêng với quyền hạn tối thiểu:
sudo mysql -u root -p
CREATE DATABASE myapp_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'myapp_user'@'localhost' IDENTIFIED BY 'StrongPassword123!';
GRANT ALL PRIVILEGES ON myapp_db.* TO 'myapp_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Lưu ý: Dùng utf8mb4 thay vì utf8 để hỗ trợ đầy đủ Unicode, kể cả emoji. WordPress từng có bug lưu emoji bị lỗi chính vì charset utf8 chỉ hỗ trợ 3 byte, trong khi emoji cần 4 byte.
Điều chỉnh cấu hình PHP cho production
File config PHP cho Apache ở /etc/php/8.1/apache2/php.ini. Mình hay chỉnh ngay mấy tham số này sau khi cài xong:
sudo nano /etc/php/8.1/apache2/php.ini
Dùng Ctrl+W trong nano để tìm nhanh từng dòng, rồi sửa theo:
; Giới hạn upload file (tùy nhu cầu)
upload_max_filesize = 64M
post_max_size = 64M
; Tăng memory limit nếu ứng dụng nặng
memory_limit = 256M
; Thời gian chạy tối đa (giây)
max_execution_time = 60
; Tắt hiển thị lỗi trên production (bật khi dev)
display_errors = Off
log_errors = On
error_log = /var/log/php_errors.log
Lưu lại, sau đó restart Apache để áp dụng:
sudo systemctl restart apache2
Kiểm tra và Monitoring
Test PHP hoạt động đúng
Tạo file phpinfo.php để kiểm tra:
sudo nano /var/www/myapp/public/phpinfo.php
<?php
phpinfo();
?>
Truy cập http://<IP-server>/phpinfo.php — bạn sẽ thấy trang thông tin PHP đầy đủ. Kiểm tra xem các extension đã cài (mysql, mbstring, xml…) có xuất hiện không.
Xóa ngay sau khi xem xong — để file này public là lỗ hổng bảo mật nghiêm trọng. Hacker nhìn vào đây là biết toàn bộ cấu hình server của bạn:
sudo rm /var/www/myapp/public/phpinfo.php
Kiểm tra kết nối PHP → MySQL
Tạo file test kết nối database:
<?php
$conn = new mysqli('localhost', 'myapp_user', 'StrongPassword123!', 'myapp_db');
if ($conn->connect_error) {
die('Lỗi kết nối: ' . $conn->connect_error);
}
echo 'Kết nối MySQL thành công! Server version: ' . $conn->server_info;
$conn->close();
?>
Thấy “Kết nối MySQL thành công” là LAMP Stack đã hoạt động end-to-end. Nhớ xóa file test này sau khi confirm.
Ba lệnh kiểm tra service cần bookmark
Trước khi thông báo “deploy xong” với team, mình thường chạy nhanh mấy cái này:
# Kiểm tra Apache
sudo systemctl status apache2
# Kiểm tra MySQL
sudo systemctl status mysql
# Xem log Apache realtime
sudo tail -f /var/log/apache2/error.log
# Xem log MySQL
sudo tail -f /var/log/mysql/error.log
Hoặc dùng one-liner gọn hơn:
for svc in apache2 mysql; do
echo -n "$svc: "
systemctl is-active $svc
done
Cả hai in ra active là ổn.
Kiểm tra port đang lắng nghe
sudo ss -tlnp | grep -E '(:80|:443|:3306)'
Apache trên port 80, MySQL trên 3306. Lưu ý MySQL chỉ bind 127.0.0.1 — đây là cấu hình an toàn mặc định, không expose ra ngoài internet.
Các lỗi thường gặp
- Apache không start: Chạy
sudo apachectl configtesttrước. Nguyên nhân số một thường là lỗi syntax config — thiếu dấu ngoặc, hoặc port 80 bị process khác chiếm mất. - PHP không load được extension: Nhìn vào
/etc/php/8.1/apache2/conf.d/— mỗi extension có file.iniriêng. Xác nhận nhanh bằngphp -m | grep mysql. - MySQL từ chối kết nối: Hay bị nhầm ở đây —
'user'@'localhost'và'user'@'127.0.0.1'là hai user khác nhau trong MySQL. Kiểm tra lại host khi tạo user.
