Hướng dẫn cài đặt WordPress với FrankenPHP và MariaDB

FrankenPHP là một giải pháp rất hay ho để vận hành một website WordPress. Vừa đơn giản hóa web server với php, vừa tận dụng được những điểm mạnh của Caddy như Auto HTTPS, HTTP/3… Trong bài này mình sẽ hướng dẫn cách cài đặt FrankenPHP lên một server Ubuntu/Debian.

Hướng dẫn cài đặt FrankenPHP chạy WordPress

Ưu nhược điểm của FrankenPHP khi chạy WordPress

Là một ứng dụng PHP, WordPress chạy tốt trên FrankenPHP. Tuy nhiên không giống như Laravel, cấu trúc của WordPress không thể khai thác hết sức mạnh của FrankenPHP cũng như sẽ gặp phải những trở ngại nhất định. Trước khi cài đặt bạn hãy cân nhắc kỹ ưu nhược điểm nhé.

Bài trước: Giới thiệu FrankenPHP: Web server & PHP hợp thể.

Ưu điểm:

  • Tích hợp sẵn Web Server (là Caddy) và PHP vào chung một file duy nhất. Không cần cài đặt riêng và cấu hình liên kết như các stack truyền thống.
  • Tận dụng ưu điểm của Caddy
    • Tự động lấy SSL cho domain, tự động gia hạn luôn. Bạn không cần làm gì liên quan đến SSL cả.
    • Support HTTP/3 mặc định, bạn cũng không cần cấu hình gì.
    • Việc cấu hình host cho từng web thực sự đơn giản, dưới 10 dòng là đủ chạy cả hệ thống. Thay vì các file vhost hoặc .htaccess dài ngoằng hàng trăm dòng như bên Apache hay Nginx.
  • Dù chỉ hoạt động ở Classic Mode, tương tự PHP-FPM hay mod_php của Apache, nó cũng chạy WordPress nhanh hơn đáng kể.

Nhược điểm:

  • Điểm mạnh nhất của FrankenPHP chính là Worker Mode. Nôm na nó như OPcache version nâng cao, Worker Mode sẽ load PHP app vào bộ nhớ, sau đó xử lý trực tiếp. Bằng cách này tốc độ xử lý nâng tầm tối đa, đáng tiếc nó chỉ hoạt động với Laravel hoặc các app PHP phù hợp. WordPress thì không chạy được vì cấu trúc khác.
  • Caddy instance trong FrankenPHP có thể chạy nhiều website đồng thời, nhưng chỉ có duy nhất 1 “pool”. Nghĩa là các site sẽ không được cách ly (isolate).
  • PHP được build sẵn là phiên bản PHP8.4 (FrankenPHP 1.7 – 1.9.1 hiện tại). Rất nhiều extension được build đầy đủ, tác giả chắc áp dụng phương châm thừa còn hơn thiếu. Tuy nhiên khi bạn cần 1 extension đặc thù, như ioncube loader chẳng hạn, thì chịu thua.

Vậy trường hợp nào bạn nên dùng FrankenPHP?

Đầu tiên, bạn phải có một ít kiến thức về quản trị server, Linux… Cơ bản, hiểu nguyên lý là được, có gì khó thì lại nhờ ChatGPT.

Tiếp theo, bạn phải đang cần 1 phương án nhanh, gọn, hiệu quả để triển khai WordPress. Bạn chỉ cần host 1 website, hoặc vài website nhưng đã phương án bảo mật chặt chẽ.

Cuối cùng, bạn phải đam mê vọc vạch một chút. FrankenPHP không kém ổn định hay kém hiệu quả; nó nhanh, tốt, và thậm chí là ổn định với mình. Nhưng để tin tưởng chạy 1 dự án trên một giải pháp mới thì chắc cũng ít có ai làm. Nếu bạn đã cân nhắc đủ kỹ, hoặc sẵn sàng thử nghiệm, thì hãy bắt đầu các bước tiếp theo.

Chuẩn bị môi trường server

Hãy chuẩn bị 1 VPS mới tinh tươm. Reinstall VPS lại từ đầu để sạch sẽ, ít lỗi và nhẹ nhàng hơn.

Debian 13 Trixie

FrankenPHP hỗ trợ đa dạng hệ điều hành, hỗ trợ nhiều cách chạy. Bạn có thể chạy qua Docker, chạy bằng file binary, hoặc cài qua gói package .deb/.rpm. Trong bài này mình sẽ hướng dẫn cài qua gói package .deb dành cho Ubuntu/Debian.

Về OS, mình ưu tiên chọn Debian, cụ thể là Debian 13 mới ra mắt được vài bữa. Nó nhanh, nhẹ, ít tốn tài nguyên, được support trong 5 năm tới, mình luôn ưu tiên chọn Debian thay vì Ubuntu. Nhưng trong bài thì Ubuntu hay Debian đều thao tác như nhau.

Cập nhật & cài đặt các thành phần cơ bản:

apt update && apt -y upgrade && apt -y install curl wget sudo

Cài đặt htop & btop (không bắt buộc):

apt -y htop btop

Cài đặt FrankenPHP

Github respository của

Xem phiên bản mới nhất của FrankenPHP tại Github. Truy cập một phiên bản, ví dụ v1.9.1, mình copy link frankenphp_1.9.1-1_amd64.deb, thay vào link tải. Chạy lệnh dưới sẽ tải gói cài đặt, lưu trong thư mục /tmp/

wget https://github.com/php/frankenphp/releases/download/v1.9.1/frankenphp_1.9.1-1_amd64.deb -O /tmp/frankenphp.deb

Tiếp theo, cài gói thông qua dpkg bằng câu lệnh dưới:

sudo dpkg -i /tmp/frankenphp.deb

Trong quá trình cài đặt có thể sẽ yêu cầu thêm dependencies, chạy tiếp lệnh dưới để tự động cài các dependencies còn thiếu & tiếp tục cài đặt FrankenPHP.

sudo apt-get install -f

Sau khi cài đặt xong, bạn có thể kiểm tra version của FrankenPHP.

frankenphp version

Thường sau khi cài, FrankenPHP còn thiếu vài thư mục, trong đó có thư mục lưu trữ SSL mặc định, bạn chạy lệnh sau để tạo và phân quyền:

mkdir /var/lib/frankenphp/.local/
chown -R frankenphp:frankenphp /var/lib/frankenphp/.local/

Lúc này, bạn có thể truy cập vào IP của VPS, sẽ hiển thị thông báo FrankenPHP đã cài & chạy thành công.

Cài đặt MariaDB

FrankenPHP đã bao gồm web server và php rồi, để chạy được WordPress còn cần thêm CSDL. MariaDB là một lựa chọn tốt thay cho MySQL.

MariaDB 11.8 LTS

Lưu ý: mỗi version OS sẽ có một phiên bản MariaDB mặc định, ví dụ Debian 11 – MariaDB 10.5, Debian 12 – MariaDB 10.11, Debian 13 – MariaDB 11.8.

Mình dùng Debian 13 nên mặc định cài luôn MariaDB 11.8 LTS bằng câu lệnh ở dưới, nếu bạn muốn cài phiên bản MariaDB khác với bản mặc định thì phải thêm repostory riêng theo hướng dẫn nhé.

apt install mariadb-server

Chạy mariadb-secure-installation

Sau khi cài đặt, bạn nên chạy lệnh mariadb-secure-installation để cài đặt bảo mật ban đầu cho MariaDB.

sudo /usr/bin/mariadb-secure-installation
  • Enter current password for root (enter for none): Vì bạn mới cài MariaDB nên sẽ không có pass đăng nhập, nên cứ để trống, nhấn Enter để tiếp tục. 
  • Switch to unix_socket authentication [Y/n]: Chỉ cho phép đăng nhập root bằng local qua phương thức unix_socket. Nên bật, nhấn Y rồi Enter. 
  • Change the root password? [Y/n]: Có muốn đặt mật khẩu cho root không? Nếu cần thì bạn có thể đặt, còn mình thì bấn “n” bỏ qua. Vẫn an toàn nhé, yên tâm.
  • Remove anonymous users? [Y/n]: Nhấn Y để xóa user mặc định. 
  • Disallow root login remotely? [Y/n]: Nhấn Y để tắt đăng nhập root từ bên ngoài. 
  • Remove test database and access to it? [Y/n]: Nhấn Y để xóa database test. 
  • Reload privilege tables now? [Y/n]: Nhấn Y để áp dụng các thay đổi vừa rồi. 

Vậy là xong!

Hướng dẫn tạo database

Sẵn tiện đang làm việc với database, chúng ta sẽ tạo luôn database và user trong MariaDB.

Giả sử bạn đang có kế hoạch sẽ triển khai website có domain example.com. Để cho dễ nhớ, bạn dự định tạo:

  • Database có tên là: examplecom_database
  • Database user tên là: examplecom_admin
  • Database user có password là: MAT-KHAU-DAY-NE

Đầu tiên, đăng nhập vào MariaDB: chạy lệnh mariadb

Nếu ở bước trên bạn có đặt password cho tài khoản root MaraiDB, bạn phải dùng lệnh này thay thế: mariadb -u root -p, sau đó nhập password. Thành công hiện ra MariaDB [(none)]> là được.

Chạy lệnh dưới để: tạo database, tạo user với password, phân quyền user vào database, áp dụng thay đổi, thoát.

CREATE DATABASE examplecom_database CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'examplecom_admin'@'localhost' IDENTIFIED BY 'MAT-KHAU-DAY-NE';
GRANT ALL PRIVILEGES ON examplecom_database.* TO 'examplecom_admin'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Import database từ file backup

Trong trường hợp bạn muốn restore web từ một bản backup cũ thay vì tạo web WordPress mới, bạn có thể dùng lệnh dưới để import.

  • Chuẩn bị bản backup database cũ, đặt tên là examplecom_database.sql.gz và đặt vào thư mục /root
  • Chạy lệnh bên dưới để import vào database mới tạo lúc nãy. Nhập password của user examplecom_admin khi được hỏi là xong.
gunzip -c /root/examplecom_database.sql.gz | mysql -u examplecom_admin -p examplecom_database

Mẹo dùng UNIX Socket thay cho TCP để tăng tốc database

Bình thường dùng WordPress chúng ta hay nhập 2 thông số: Database Host là localhost (hoặc 127.0.0.1) và Database Port là 3306 (mặc định). Trong wp-config.php sẽ có dòng define( 'DB_HOST', "localhost" );

Đó là phương pháp kết nối truyền thống qua giao thức TCP. Về bản chất tuy là cùng localhost nhưng nó sẽ phải đi qua lớp mạng nội bộ, phân giải tên miền… tốn thêm thời gian. Trong môi trường VPS, bạn tự cài và quản lý MariaDB, thường sẽ mở sẵn UNIX socket tại /run/mysqld/mysqld.sock. WordPress giao tiếp với MariaDB qua socket sẽ nhanh hơn, bảo mật hơn.

Như mình nói, socket mặc định được mở tại /run/mysqld/mysqld.sock, bạn có thể recheck bằng cách xem có file đó tồn tại không, hoặc xem cấu hình config để biết chính xác vị trí socket. Sau đó thay vì điền localhost hay 127.0.0.1, bạn điền giá trị :/run/mysqld/mysqld.sock là được.

define( 'DB_HOST', ":/run/mysqld/mysqld.sock" );

*Lưu ý có dấu : ở trước nhé! Quy chuẩn của WordPress để hiểu đây là socket.

Cấu hình Caddyfile & WordPress

Tạo thư mục chứa mã nguồn WordPress

Tùy thuộc vào thói quen, bạn có thể quy hoạch thư mục WordPress ở bất cứ đâu bạn muốn. Mình thì hay đặt tại /var/www. Sau đó đặt thư mục các website bên trong thư mục www này, ví dụ như /var/www/wpsieutoc.com

Các thư mục này chưa có sẵn, nên bước đầu phải tạo. Bạn thay thên thư mục wpsieutoc.com bằng tên thư mục bạn muốn tạo nhé.

sudo mkdir /var/www & sudo mkdir /var/www/wpsieutoc.com

Sau khi đã tạo xong, nếu bạn đã có sẵn source code rồi thì up vào thư mục này thôi. Còn nếu bạn muốn tải source code WordPress mới thì chạy lệnh dưới để tải bản WordPress mới nhất (nhớ thay wpsieutoc.com bằng tên thư mục bạn đã tạo ở trên).

cd /var/www && sudo wget https://wordpress.org/latest.tar.gz && sudo tar -xzvf latest.tar.gz && sudo mv wordpress/* wpsieutoc.com/ && sudo rmdir wordpress && sudo rm latest.tar.gz

QUAN TRỌNG: Sau khi upload source code cũ, hoặc tải bộ code WordPress mới về xong, bạn phải phân quyền lại thư mục cho FrankenPHP, cũng như set lại quyền file/thư mục cho hợp lý:

sudo chown -R frankenphp:frankenphp /var/www/ && sudo find /var/www/ -type d -exec chmod 755 {} \; && sudo find /var/www/ -type f -exec chmod 644 {} \;

Trỏ domain về địa chỉ VPS

Caddyfile là file cấu hình web server của Caddy (FrankenPHP). Nó giống các file vhost nginx.conf hoặc .htaccess.

2509 tro domain ve dia chi ip 2

Trước khi cấu hình Caddyfile, bạn phải trỏ domain về địa chỉ IP của VPS trước. Đây là bước quan trọng để khi FrankenPHP chạy với cấu hình mới, việc lấy SSL tự động sẽ diễn ra suôn sẻ, tránh các lỗi cũng như Rate Limiting của Let’s Encrypt.

Nếu bạn dùng Cloudflare, nhớ tắt chế độ proxy (tắt đám mây vàng) thì mới lấy SSL được nhé. Sau này web chạy thì bật proxy lại sau.

Cấu hình Caddyfile

Bạn có thể dùng sFTP để sửa Caddyfile tại /etc/frankenphp/Caddyfile

Hoặc dùng nano của Linux (chạy bằng Terminal):

nano /etc/frankenphp/Caddyfile

Dưới đây là nội dung Caddyfile mặc định:

                                                             
# The Caddyfile is an easy way to configure FrankenPHP and the Caddy web server.
#
# https://frankenphp.dev/docs/config
# https://caddyserver.com/docs/caddyfile

{
        frankenphp
}

http:// {
        root /usr/share/frankenphp/
        encode zstd br gzip

        php_server
}

# As an alternative to editing the above site block, you can add your own site
# block files in the Caddyfile.d directory, and they will be included as long
# as they use the .caddyfile extension.

import Caddyfile.d/*.caddyfile
  • Đoạn đầu là cấu hình frankenphp, không cấu hình gì thì các thông số mặc định.
  • Đoạn sau là các directive theo chuẩn Caddy.
  • Phần cuối là biểu thức để tìm & áp dụng các caddyfile phụ trong thư mục /Caddyfile.d

Chúng ta sẽ chỉnh sửa lại, bạn có thể xóa hết nội dung mặc định và thay thế bằng:

{
	frankenphp {
		max_threads auto
		max_wait_time 5s
	}
}

www.wpsieutoc.com {
	redir https://wpsieutoc.com{uri} permanent
}

wpsieutoc.com {
	root * /var/www/wpsieutoc.com
	encode zstd gzip
	php_server
}

Các thay đổi chính:

  • Cấu hình thêm cho frankenphp
    • max_thread = auto, mặc định max_thread sẽ bằng số core CPU mà VPS bạn có. Để auto để khi có nhiều việc phải làm, frankenphp tự tăng số thread lên.
    • max_wait_time đặt thành 5s.
  • Xóa directive http:// mặc định. Phần này thừa, chỉ để test khi mới cài, cũng ngăn chặn truy cập trực tiếp vào địa chỉ IP.
  • Thêm directive để redirect từ www sang non-www (nên có, để khi Caddy tự động tạo SSL sẽ tạo cho cả www, tốt cho SEO).
  • Thêm directive website chính:
    • Khai báo thư mục root chứa source code
    • Định dạng mã hóa nội dung zstd ưu tiên, fallback về gzip
    • Khai báo php_server cho directive này

Việc cấu hình Caddyfile thực sự đơn giản, để chạy những cái tối thiểu nhất, bạn chỉ cần 8 dòng là đủ. Mà mỗi dòng cũng chỉ vài ký tự, rất logic và dễ hiểu với dân ngoại đạo.

Nhưng đó là những mục tối thiểu để chạy, bạn có thể cấu hình thêm nhiều chức năng khác như Log truy cập, Header bảo mật… Mấy cái này mình tạm thời chưa đề cập, mục tiêu để ban đầu là chạy được đã.

Sau khi thay đổi và lưu, chạy lệnh sau để kiểm tra Caddyfile có lỗi gì không:

frankenphp validate --config /etc/frankenphp/Caddyfile

Nếu ổn, bạn có thể chạy thêm 1 lệnh nữa để Caddy tự format lại file theo chuẩn:

frankenphp fmt --overwrite --config /etc/frankenphp/Caddyfile

Cuối cùng, restart lại service frankenphp để áp dụng thay đổi:

systemctl restart frankenphp

Nếu không có gì sai hoặc phát sinh, bây giờ bạn đã có thể truy cập vào website của mình được rồi. Thử nhé!

2509 wordpress installation success

Cấu hình php.ini

Cấu hình php.ini mặc định của FrankenPHP có giới hạn ở 1 số chỗ như upload_max_filesize = 2M. Cần chỉnh sửa một vài thông số để tối ưu hơn.

File php.ini chính nằm tại: /etc/frankenphp/php.ini
FrankenPHP cũng tự động load các file .ini phụ trong thư mục /etc/frankenphp/php.d/

Vậy nên mình tạo riêng một file custom (nano /etc/frankenphp/php.d/custom.ini) với nội dung bên dưới:

[PHP]
; Basic Settings
engine = On
short_open_tag = Off
precision = 14

; Memory Limits
memory_limit = 128M
max_execution_time = 30
max_input_time = 60
post_max_size = 64M
upload_max_filesize = 64M
max_file_uploads = 10

; Output Buffering
output_buffering = 4096
implicit_flush = Off

; Error Handling (Production)
error_reporting = E_ALL & ~E_DEPRECATED & ~E_NOTICE
display_errors = Off
display_startup_errors = Off
log_errors = On
ignore_repeated_errors = On
html_errors = Off

; Session Settings
session.save_handler = files
session.use_strict_mode = 1
session.use_cookies = 1
session.use_only_cookies = 1
session.cookie_httponly = 1
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.cache_limiter = nocache

; Security (Minimal)
expose_php = Off
allow_url_fopen = On
allow_url_include = Off
register_argc_argv = Off
auto_globals_jit = On

; Variables
variables_order = "GPCS"
request_order = "GP"

; File Uploads
file_uploads = On

; Database
pdo_mysql.default_socket = /run/mysqld/mysqld.sock
mysqli.default_socket = /run/mysqld/mysqld.sock
mysqli.max_persistent = 5
mysqli.allow_persistent = On

; OPcache (Critical for Performance)
opcache.enable = 1
opcache.enable_cli = 0
opcache.memory_consumption = 64
opcache.interned_strings_buffer = 4
opcache.max_accelerated_files = 5000
opcache.max_wasted_percentage = 5
opcache.use_cwd = 1
opcache.validate_timestamps = 1
opcache.revalidate_freq = 2
opcache.save_comments = 0
opcache.optimization_level = 0x7FFFBFFF
opcache.force_restart_timeout = 180
opcache.log_verbosity_level = 1

; Date/Time
date.timezone = Asia/Ho_Chi_Minh

; Character Encoding
default_charset = "UTF-8"

; Resource Limits
realpath_cache_size = 4096K
realpath_cache_ttl = 120

; Socket
default_socket_timeout = 60

; PCRE
pcre.backtrack_limit = 100000
pcre.recursion_limit = 100000

; MySQL
mysqlnd.collect_statistics = Off
mysqlnd.collect_memory_statistics = Off

; GD
gd.jpeg_ignore_warning = 1

; mbstring
mbstring.language = neutral
mbstring.internal_encoding = UTF-8
mbstring.http_input = UTF-8
mbstring.http_output = UTF-8
mbstring.encoding_translation = Off

; BCMath
bcmath.scale = 2

; FastCGI
cgi.fix_pathinfo = 1
cgi.force_redirect = 0

; Performance
zend.enable_gc = On
zend.exception_ignore_args = On
zend.exception_string_param_max_len = 0

Lưu ý: đây là cấu hình phù hợp cho server (1CPU-1GB) cũng như mục đích của mình. Bạn nên chỉnh sửa các chỉ số theo sức mạnh của VPS & mục đích sử dụng. Nếu không chắc chắn, chỉ cần giữ các dòng bạn cần, đừng copy hết. Tham khảo ChatGPT để tìm giá trị tối ưu cho mình nhé!

Sau khi làm xong, restart lại frankenphp để áp dụng thay đổi: systemctl restart frankenphp

Cấu trúc sau cùng

Mình vẽ lại cấu trúc để bạn hiểu hơn về cách chạy WordPress trên FrankenPHP & MariaDB.

Phần tổ chức thực sự rất đơn giản, dễ hiểu & dễ xử lý. Dĩ nhiên đây là những phần cơ bản nhất, còn rất nhiều thứ có thể phát sinh như: Redis để Object Cache, phpAdmin để quản lý database trực quan, ProFTPD để quản lý FTP…

# Cấu trúc thư mục FrankenPHP với WordPress
├── etc/
│   ├── frankenphp/
│   │   ├── Caddyfile                 # File cấu hình chính cho Caddy
│   │   ├── php.ini                   # File cấu hình chính cho PHP
│   │   └── php.d/                    # Thư mục cấu hình PHP bổ sung
│   │       ├── custom1.ini
│   │       ├── custom2.ini
│   │       └── ...                   # Các file cấu hình PHP khác
│   │
│   └── mysql/                        # Thư mục cấu hình MariaDB
│       ├── mariadb.cnf               # File cấu hình MariaDB chính
│       ├── mariadb.conf.d/           # Thư mục chứa các file cấu hình khác                
│
├── var/
│   ├── lib/
│   │   └── frankenphp/
│   │       └── .local/               # Thư mục chứa SSL certificates
│   │
│   └── www/                          # Thư mục gốc chứa source code
│       ├── example.com/              # Website 1
│       │   ├── index.php
│       │   ├── wp-admin/
│       │   ├── wp-content/
│       │   └── wp-includes/
│       │
│       └── wpsieutoc.com/            # Website 2 (WordPress của bạn)
│           ├── index.php
│           ├── wp-config.php
│           ├── wp-admin/
│           ├── wp-content/
│           └── wp-includes/
│
└── ...                               # Các thư mục hệ thống khác

Quản lý FrankenPHP trên server

Bài này mình tập trung vào FrankenPHP nên tạm thời phần quản trị database không tính. Trong quá trình sử dụng & quản trị FrankenPHP sẽ có những phát sinh, mình list sẵn:

Kiểm tra trạng thái service

Để xem trạng thái FrankenPHP, bạn dùng câu lệnh: systemctl status frankenphp
Để xem chi tiết hơn nữa, bạn dùng lệnh: journalctl -xeu frankenphp.service

Các câu lệnh hữu ích khác:

  • Khởi động lại FrankenPHP:
    systemctl status frankenphp
  • Kiểm tra Caddyfile có hợp lệ không trước khi restart:
    frankenphp validate --config /etc/frankenphp/Caddyfile
  • Format lại Caddyfile theo chuẩn của Caddy:
    frankenphp fmt --overwrite --config /etc/frankenphp/Caddyfile
  • Chạy CLI trong Terminial:
    frankenphp php-cli /đường-dẫn-lệnh-php-cần-chạy
  • Và các lệnh khác, gõ frankenphp để ra danh sách…
  • Phân quyền lại cho FrankenPHP, lệnh này hữu dụng khi bạn upload/edit file trong /var/www/ bằng sFTP (root user):
sudo chown -R frankenphp:frankenphp /var/www/ && sudo find /var/www/ -type d -exec chmod 755 {} \; && sudo find /var/www/ -type f -exec chmod 644 {} \;

One Comment

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *