Bash script block 04: Cài PHP & MariaDB (database)

Khối này dùng để cài PHP và MariaDB, làm nền cho các ứng dụng như WordPress.

# Phần 3: Cài PHP & MariaDB
# --- CẤU HÌNH BIẾN NGẪU NHIÊN (CHUẨN PIPEFAIL) ---
# Logic: Lấy trước 1 lượng data raw (head -c 500) -> Lọc -> Cắt chuỗi bằng Bash

# 1. Tạo Database Name: wp_ + 8 ký tự
# Lấy 100 byte rác, lọc lấy chữ thường/số, gán vào biến tạm
_TMP_DB=$(head -c 500 /dev/urandom | LC_ALL=C tr -dc 'a-z0-9')
# Cắt lấy 8 ký tự đầu tiên
GEN_DB_NAME="wp_${_TMP_DB:0:8}"

# 2. Tạo User Name: user_ + 8 ký tự
_TMP_USER=$(head -c 500 /dev/urandom | LC_ALL=C tr -dc 'a-z0-9')
GEN_DB_USER="user_${_TMP_USER:0:8}"

# 3. Tạo Password: 20 ký tự (Hoa + Thường + Số)
_TMP_PASS=$(head -c 500 /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9')
GEN_DB_PASS="${_TMP_PASS:0:20}"

# Xóa biến tạm cho gọn
unset _TMP_DB _TMP_USER _TMP_PASS

# --- BẮT ĐẦU CÀI ĐẶT ---
# Cài PHP & MariaDB
echo -e "${GREEN}[1/4] Dang cai dat PHP 8.3 va cac module can thiet...${NC}"

# Thêm repository và cài đặt PHP
sudo apt update
sudo apt install -y lsb-release ca-certificates apt-transport-https software-properties-common
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update

# Cài đặt PHP 8.3 và các extensions
sudo apt install -y php8.3-fpm php8.3-mysql php8.3-curl php8.3-gd php8.3-mbstring php8.3-xml php8.3-zip php8.3-imagick php8.3-intl php8.3-bcmath

echo -e "${GREEN}[2/4] Dang cai dat MariaDB Server...${NC}"
sudo apt install -y mariadb-server

# --- BẢO MẬT MARIADB (HARDENING) ---
echo -e "${GREEN}[3/4] Dang thuc hien bao mat MariaDB (Secure Installation)...${NC}"

# Chạy một khối lệnh SQL để thực hiện các yêu cầu bảo mật:
# 1. Xóa anonymous users
# 2. Chỉ cho phép root login từ localhost (tắt remote root)
# 3. Xóa database 'test' và quyền truy cập vào nó
# 4. Reload privileges
sudo mariadb <<EOF
DELETE FROM mysql.user WHERE User='';
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
FLUSH PRIVILEGES;
EOF

echo -e "${GREEN}[4/4] Dang tao Database va User cho WordPress...${NC}"

# Sử dụng biến đã tạo ở trên vào câu lệnh SQL
# Lưu ý: Vì biến chỉ chứa [a-zA-Z0-9] nên không cần escape phức tạp, rất an toàn.

sudo mariadb -e "CREATE DATABASE IF NOT EXISTS ${GEN_DB_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
sudo mariadb -e "CREATE USER IF NOT EXISTS '${GEN_DB_USER}'@'localhost' IDENTIFIED BY '${GEN_DB_PASS}';"
sudo mariadb -e "GRANT ALL PRIVILEGES ON ${GEN_DB_NAME}.* TO '${GEN_DB_USER}'@'localhost';"
sudo mariadb -e "FLUSH PRIVILEGES;"

# --- KẾT THÚC VÀ XUẤT THÔNG TIN ---

# Lưu thông tin vào file để tra cứu sau này (Quan trọng vì mật khẩu là ngẫu nhiên)
CRED_FILE="$HOME/wpp.txt"
cat > "$CRED_FILE" <<EOF
----------------------------------------
WORDPRESS DATABASE CREDENTIALS
Date: $(date)
----------------------------------------
Database Name : ${GEN_DB_NAME}
Database User : ${GEN_DB_USER}
Database Pass : ${GEN_DB_PASS}
----------------------------------------
EOF
chmod 600 "$CRED_FILE" # Chỉ user hiện tại mới đọc được file này

# Để xem lại nội dung dùng lệnh sau trên terminal: cat ~/wpp.txt
# Copy bằng cách bôi đen ở terminal, sau đó paste (ctrl + V) như bình thường ở giao diện cài đặt
# Sau khi cài xong WordPress cần xóa file này đi bằng lệnh: rm ~/wpp.txt

echo -e "${GREEN}>>> Cai dat hoan tat!${NC}"
echo -e "${YELLOW}Thong tin Database (Da duoc luu tai $CRED_FILE):${NC}"
echo -e "  - Database: ${GEN_DB_NAME}"
echo -e "  - User:     ${GEN_DB_USER}"
echo -e "  - Pass:     ${GEN_DB_PASS}"
echo -e "${YELLOW}Kiem tra PHP version:${NC}"
php -v
echo -e "${GREEN}>>> Buoc tiep theo: Cai dat WordPress.${NC}"
sleep 2

a. Tạo trước tên cho database, user & pass cho user

# 1. Tạo Database Name: wp_ + 8 ký tự
# Lấy 100 byte rác, lọc lấy chữ thường/số, gán vào biến tạm
_TMP_DB=$(head -c 500 /dev/urandom | LC_ALL=C tr -dc 'a-z0-9')
# Cắt lấy 8 ký tự đầu tiên
GEN_DB_NAME="wp_${_TMP_DB:0:8}"

# 2. Tạo User Name: user_ + 8 ký tự
_TMP_USER=$(head -c 500 /dev/urandom | LC_ALL=C tr -dc 'a-z0-9')
GEN_DB_USER="user_${_TMP_USER:0:8}"

# 3. Tạo Password: 20 ký tự (Hoa + Thường + Số)
_TMP_PASS=$(head -c 500 /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9')
GEN_DB_PASS="${_TMP_PASS:0:20}"

# Xóa biến tạm cho gọn
unset _TMP_DB _TMP_USER _TMP_PASS

GEN_DB_NAME, GEN_DB_USER, GEN_DB_PASS lần lượt là các biến dành cho tên database, user, pass.

_TMP_DB, _TMP_USER, _TMP_PASS lần lượt là các biến tạm đầu vào để lấy các ký tự ngẫu nhiên.

Các tên bảng, user, pass cần có các giá trị ngẫu nhiên thay vì cố định để gia tăng bảo mật.

Giải thích đoạn mã:

_TMP_DB=$(head -c 500 /dev/urandom | LC_ALL=C tr -dc 'a-z0-9')
  • $(...): chạy các lệnh bên trong dấu ngoặc đơn rồi gán cho biến tạm _TMP_DB
  • /dev/urandom: một file đặc biệt trong Linux chứa các dữ liệu ngẫu nhiên.
  • head -c 500: lấy ra đúng 500 byte dữ liệu đầu tiên từ nguồn ngẫu nhiên đó.
  • | (Pipe): chuyển kết quả làm đầu vào cho lệnh tiếp theo.
  • LC_ALL=C: dữ liệu đầu vào là nhị phân (500 byte), lệnh này ép dữ liệu về dạng mà lệnh xử lý văn bản phía sau xử lý được, nếu không dễ lỗi.
  • tr -dc 'a-z0-9: cả cụm này có nghĩa là xóa tất cả các ký tự mà không phải chữ thường (a-z) và số (0-9). Lệnh này quan trọng để tránh dữ liệu ngẫu nhiên có các ký tự đặc biệt như /, #,… mà có thể gây lỗi khi thao tác với các câu lệnh liên quan đến database.

Tiếp:

GEN_DB_NAME="wp_${_TMP_DB:0:8}"

Nghĩa là chuỗi _TMP_DB được lấy 8 ký tự đầu tiên, sau đó gắn vào sau wp_ để làm tên chính thức cho database, ví dụ wp_ak89dlz7

Riêng với password thì cần phức tạp hơn nên nó có cả chữ thường, chữ hoa và số. Đồng thời độ dài cũng lớn hơn khi nó lấy 20 ký tự.

Tuy nhiên về sau cách dưới đây được cho là tốt hơn:

_TMP_DB=$(openssl rand -hex 16)

Nó sẽ tạo chuỗi hex ngẫu nhiên dài 32 ký tự. Nó tốt hơn vì nhanh & ổn định hơn cách cũ, cách cũ có độ dài ký tự không ổn định và có thể rủi ro (dù hiếm). Vì vậy tôi sửa lại mã thành như sau:

# 1. DB Name (Thoải mái độ dài, MySQL cho phép 64 ký tự)
# Kết quả ví dụ: wp_a1b2c3d4e5f67890
GEN_DB_NAME="wp_$(openssl rand -hex 8)"

# 2. User Name (Nên giữ <= 16 ký tự để tương thích mọi phiên bản MySQL)
# Giảm xuống hex 5 (10 ký tự) + "user_" (5 ký tự) = 15 ký tự
# Kết quả ví dụ: user_a1b2c3d4e5
GEN_DB_USER="user_$(openssl rand -hex 5)"

# 3. Password (32 ký tự là rất mạnh rồi)
# Kết quả ví dụ: 890123456789abcdef0123456789abcd
GEN_DB_PASS=$(openssl rand -hex 16)

b. Cài đặt PHP

# Thêm repository và cài đặt PHP
sudo apt update
sudo apt install -y lsb-release ca-certificates apt-transport-https software-properties-common
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update

# Cài đặt PHP 8.3 và các extensions
sudo apt install -y php8.3-fpm php8.3-mysql php8.3-curl php8.3-gd php8.3-mbstring php8.3-xml php8.3-zip php8.3-imagick php8.3-intl php8.3-bcmath

Phần đầu tiên:

sudo apt update
sudo apt install -y lsb-release ca-certificates apt-transport-https software-properties-common
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update

Ubuntu cũng có các kho PHP, tuy nhiên các phiên bản cũ hơn sẽ chứa các bản PHP cũng cũ. Phần này sẽ chỉ định kho ngoài uy tín (của Ondřej Surý, một trong các nhà phát triển chính của Debian, còn Ubuntu thì dựa trên Debian) rồi chọn phiên bản PHP mong muốn (nhưng vẫn tương thích với OS hiện tại) thay vì dựa vào mặc định của phiên bản Ubuntu.

PS: Tuy vậy để tốt nhất, người dùng vẫn chỉ nên cài Ubuntu LTS bản gần nhất, hoặc kế cận sau đó, không nên cài bản quá cũ. Bản quá cũ sẽ vẫn có khả năng gặp vấn đề với những phiên bản PHP mới nhất.

Phần thứ hai:

sudo apt install -y php8.3-fpm php8.3-mysql php8.3-curl php8.3-gd php8.3-mbstring php8.3-xml php8.3-zip php8.3-imagick php8.3-intl php8.3-bcmath

Nó sẽ cài đặt bộ lõi của phiên bản PHP 8.3 cùng các thư viện mở rộng thiết yếu.

Giải thích nhanh:

  • php8.3-fpm: trình quản lý tiến trình php chuyên dụng, cái này Caddy và Nginx dùng. Apache sẽ dùng thư viện khác. FPM chịu trách nhiệm nhận yêu cầu từ web server, xử lý code và trả về kết quả.
  • php8.3-mysql: để PHP giao tiếp được với database (MySQL hoặc MariaDB), bắt buộc phải có trong các ứng dụng cần database như WordPress.
  • php8.3-curl: giúp PHP thực hiện yêu cầu HTTP tới server khác.
  • php8.3-gd: thư viện xử lý ảnh cơ bản.
  • php8.3-imagick: thư viện xử lý ảnh nâng cao.
  • php8.3-mbstring, php8.3-intl, php8.3-xml là các thư viện liên quan đến xử lý ngôn ngữ và văn bản.
  • php8.3-zip: cho phép PHP nén và giải nén file zip, cần thiết khi update WordPress, cài theme/plugin từ file zip.
  • php8.3-bcmath: thư viện toán.

c. Cài MariaDB & xóa các thiết lập mặc định không an toàn

echo -e "${GREEN}[2/4] Dang cai dat MariaDB Server...${NC}"
sudo apt install -y mariadb-server

# --- BẢO MẬT MARIADB (HARDENING) ---
echo -e "${GREEN}[3/4] Dang thuc hien bao mat MariaDB (Secure Installation)...${NC}"

# Chạy một khối lệnh SQL để thực hiện các yêu cầu bảo mật:
# 1. Xóa anonymous users
# 2. Chỉ cho phép root login từ localhost (tắt remote root)
# 3. Xóa database 'test' và quyền truy cập vào nó
# 4. Reload privileges
sudo mariadb <<EOF
DELETE FROM mysql.user WHERE User='';
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
FLUSH PRIVILEGES;
EOF

Phần thứ nhất:

sudo apt install -y mariadb-server

Cái này là lệnh cài database MariaDB. MariaDB rất tương thích với MySQL, câu lệnh chạy được trên MySQL đều chạy được trên MariaDB.

Phần thứ hai:

sudo mariadb <<EOF
DELETE FROM mysql.user WHERE User='';
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
FLUSH PRIVILEGES;
EOF

Tập hợp lệnh trên gia tăng bảo mật cho MariaDB bằng cách loại bỏ các mặc định như xóa bảng mẫu test, cấm root đăng nhập từ xa, xóa user ẩn danh. Cuối cùng nó nạp lại bảng phân quyền để yêu cầu MariaDB cập nhật các thông tin mới ở trên ngay lập tức. MariaDB lúc này sẽ sạch sẽ và an toàn hơn.

d. Tạo database chờ sẵn cho WordPress

echo -e "${GREEN}[4/4] Dang tao Database va User cho WordPress...${NC}"

# Sử dụng biến đã tạo ở trên vào câu lệnh SQL
# Lưu ý: Vì biến chỉ chứa các chữ cái thường và số nên không cần escape phức tạp, rất an toàn.

sudo mariadb -e "CREATE DATABASE IF NOT EXISTS ${GEN_DB_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
sudo mariadb -e "CREATE USER IF NOT EXISTS '${GEN_DB_USER}'@'localhost' IDENTIFIED BY '${GEN_DB_PASS}';"
sudo mariadb -e "GRANT ALL PRIVILEGES ON ${GEN_DB_NAME}.* TO '${GEN_DB_USER}'@'localhost';"
sudo mariadb -e "FLUSH PRIVILEGES;"

Phần đầu: sudo mariadb -e

  • sudo mariadb: vào MariaDB bằng quyền root do vậy không cần mật khẩu đăng nhập, điều này tiện lợi để thao tác tự động luôn.
  • -e: yêu cầu MariaDB thực thi câu lệnh SQL nằm trong dấu nháy kép rồi thoát ra ngay thay vì mở giao diện dòng lệnh.

Phần hai:

  • CREATE DATABASE: lệnh SQL để tạo cơ sở dữ liệu mới.
  • IF NOT EXISTS: chỉ tạo nếu database chưa tồn tại.
  • ${GEN_DB_NAME}: biến tên database mà chúng ta tạo ban nãy.
  • DEFAULT CHARACTER SET utf8mb4: quan trọng để hỗ trợ đầy đủ các loại ngôn ngữ trong đó có tiếng Việt, ngoài ra là nhiều ký tự khác như Emoji.
  • COLLATE utf8mb4_unicode_ci: quy định cách so sánh và sắp xếp ký tự.

Phần ba:

  • CREATE USER: tạo người dùng mới để quản lý database trên.
  • '${GEN_DB_USER}'@'localhost': tên người dùng được lấy từ biến mà chúng ta tạo ban nãy, localhost ám chỉ rằng nó chỉ được kết nối từ chính máy chủ này, không được phép kết nối từ xa (remote).
  • IDENTIFIED BY '${GEN_DB_PASS}': thiết lập mật khẩu cho user, sử dụng biến ${GEN_DB_PASS} tạo ở mục a trước đó.

Phần bốn:

  • GRANT ALL PRIVILEGES: trao toàn quyền cho user thao tác với bảng database.
  • ON ${GEN_DB_NAME}.*: tuy nhiên chỉ được thao tác với bảng database chỉ định cụ thể. Tức là nó không được quá quyền, thừa quyền. Cái này còn gọi là nguyên tắc quyền tối thiểu (chỉ có quyền cần thiết tối thiểu cho nhiệm vụ, không được hơn, một nguyên tắc quan trọng trong bảo mật, chúng ta sẽ gặp lại khái niệm này khi phân quyền cho www-data hoặc tài khoản SFTP đăng nhập vào thư mục web).
  • TO '${GEN_DB_USER}'@'localhost': chỉ định cho user cụ thể.
  • sudo mariadb -e "FLUSH PRIVILEGES;": nạp lại để các thay đổi có hiệu lực ngay lập tức.

e. Xuất thông tin để dùng lại

# Lưu thông tin vào file để tra cứu sau này (Quan trọng vì mật khẩu là ngẫu nhiên)
CRED_FILE="$HOME/wpp.txt"
cat > "$CRED_FILE" <<EOF
----------------------------------------
WORDPRESS DATABASE CREDENTIALS
Date: $(date)
----------------------------------------
Database Name : ${GEN_DB_NAME}
Database User : ${GEN_DB_USER}
Database Pass : ${GEN_DB_PASS}
----------------------------------------
EOF
chmod 600 "$CRED_FILE" # Chỉ user hiện tại mới đọc được file này

Người cài đặt sẽ cần dùng thông tin này để nhập vào khi cài đặt WordPress, vì vậy xuất ra dưới file txt có tên wpp.txt (lưu trong server/VPS), đồng thời siết quyền để chỉ root đọc được nó. Lưu ý file này cần xóa sau khi hoàn thành nhiệm vụ cài WordPress (cho dù đã bảo mật bằng cách chỉ cho root đọc, an toàn nhất vẫn là sau khi cài xong thì xóa).

Sử dụng lệnh:

cat ~/wpp.txt

Để xem lại các thông tin.

f. Xuất thông báo ra màn hình

echo -e "${GREEN}>>> Cai dat hoan tat!${NC}"
echo -e "${YELLOW}Thong tin Database (Da duoc luu tai $CRED_FILE):${NC}"
echo -e "  - Database: ${GEN_DB_NAME}"
echo -e "  - User:     ${GEN_DB_USER}"
echo -e "  - Pass:     ${GEN_DB_PASS}"
echo -e "${YELLOW}Kiem tra PHP version:${NC}"
php -v
echo -e "${GREEN}>>> Buoc tiep theo: Cai dat WordPress.${NC}"
sleep 2

Xuất các thông báo ra màn hình về kết quả cài đặt cũng như thông tin về tên bảng, user và pass (mặc dù có file lưu, việc thông báo ra màn hình vẫn rất có ích). Kèm thông báo về bước tiếp theo, đồng thời cho màn hình nghỉ 2s để người dùng đọc nội dung (luôn có màn hình nghỉ ở các bước chuyển).

Viết một bình luận