2024年3月,公司新采购了一台阿里云ECS(4核8G,Ubuntu22.04),让我搭建LNMP生产环境。我心想这活儿简单,结果:
这篇文章就是把这些坑填平后的完整方案。你照着做,1小时搞定。
搭建LNMP有两种主流方式:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| apt包管理器 | 安装快、自动处理依赖、更新方便 | 版本可能不是最新、定制性差 | 快速搭建、非极端性能要求 |
| 源码编译 | 版本最新、可定制编译参数、性能优化空间大 | 耗时长、依赖问题多、维护成本高 |
我选择apt为主+源码编译PHP。原因:Nginx和MySQL用apt稳定,PHP8.3需要特定编译参数(比如opcache、redis扩展),apt源里的PHP8.3不带这些。
# 更新系统
sudo apt update && sudo apt upgrade -y
# 安装基础工具
sudo apt install -y curl wget git vim unzip software-properties-common
# 设置时区
sudo timedatectl set-timezone Asia/Shanghai
# 优化系统参数(生产环境必须)
cat >> /etc/sysctl.conf << 'EOF'
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 0
net.ipv4.ip_local_port_range = 1024 65535
vm.swappiness = 10
EOF
sysctl -p
# 优化文件描述符
echo '* soft nofile 655350' >> /etc/security/limits.conf
echo '* hard nofile 655350' >> /etc/security/limits.conf
ulimit -n 655350
# 添加Nginx官方源(apt源版本太旧)
curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu jammy nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
sudo apt update
sudo apt install -y nginx=1.24.0-1~jammy
# 验证版本
nginx -v # 输出: nginx version: nginx/1.24.0
# 配置Nginx(生产优化)
cat > /etc/nginx/nginx.conf << 'EOF'
user www-data;
worker_processes auto;
pid /run/nginx.pid;
worker_rlimit_nofile 65535;
events {
worker_connections 65535;
multi_accept on;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 基础优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 1000;
client_max_body_size 100m;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main buffer=32k flush=5s;
error_log /var/log/nginx/error.log warn;
# Gzip压缩
gzip on;
gzip_min_length 1000;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# 虚拟主机
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
EOF
# 启动Nginx
sudo systemctl enable nginx
sudo systemctl start nginx
# 安装MySQL(apt源自带8.0.35)
sudo apt install -y mysql-server-8.0
# 验证版本
mysql --version # 输出: mysql Ver 8.0.35-0ubuntu0.22.04.1 for Linux on x86_64
# 安全配置(交互式,按提示操作)
sudo mysql_secure_installation
# 配置MySQL(生产优化)
cat > /etc/mysql/mysql.conf.d/mysqld.cnf << 'EOF'
[mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
log-error = /var/log/mysql/error.log
# 字符集
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# 连接数
max_connections = 500
max_connect_errors = 10000
# 临时表
tmp_table_size = 64M
max_heap_table_size = 64M
# 查询缓存(MySQL8.0已废弃,但保留配置)
# query_cache_type = 0
# InnoDB配置
innodb_buffer_pool_size = 2G # 物理内存的50%
innodb_log_file_size = 512M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
innodb_file_per_table = 1
innodb_io_capacity = 2000
innodb_io_capacity_max = 3000
# 慢查询日志
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
# 二进制日志(用于备份和恢复)
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
expire_logs_days = 7
EOF
# 重启MySQL
sudo systemctl restart mysql
# 创建应用数据库和用户
sudo mysql -e "CREATE DATABASE IF NOT EXISTS app_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
sudo mysql -e "CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'StrongPassword123!';"
sudo mysql -e "GRANT ALL PRIVILEGES ON app_db.* TO 'app_user'@'localhost';"
sudo mysql -e "FLUSH PRIVILEGES;"
# 安装编译依赖
sudo apt install -y build-essential autoconf libtool pkg-config \
libxml2-dev libsqlite3-dev libcurl4-openssl-dev libssl-dev \
libonig-dev libzip-dev libbz2-dev libreadline-dev libgmp-dev \
libsodium-dev libargon2-dev libwebp-dev libjpeg-dev libpng-dev \
libxpm-dev libfreetype6-dev libicu-dev libpq-dev
# 下载PHP源码
cd /usr/local/src
sudo wget https://www.php.net/distributions/php-8.3.6.tar.gz
sudo tar -xzf php-8.3.6.tar.gz
cd php-8.3.6
# 编译配置(生产环境优化参数)
./configure --prefix=/usr/local/php8.3 \
--with-config-file-path=/usr/local/php8.3/etc \
--with-config-file-scan-dir=/usr/local/php8.3/etc/conf.d \
--enable-fpm \
--with-fpm-user=www-data \
--with-fpm-group=www-data \
--enable-mbstring \
--enable-bcmath \
--enable-gd \
--with-webp \
--with-jpeg \
--with-xpm \
--with-freetype \
--enable-intl \
--enable-opcache \
--enable-pcntl \
--enable-posix \
--enable-sockets \
--enable-mysqlnd \
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd \
--with-pdo-pgsql \
--with-curl \
--with-openssl \
--with-zip \
--with-bz2 \
--with-gmp \
--with-sodium \
--with-password-argon2 \
--with-readline \
--with-libxml
# 编译(-j$(nproc)使用所有CPU核心加速)
make -j$(nproc)
sudo make install
# 复制配置文件
sudo cp php.ini-production /usr/local/php8.3/etc/php.ini
sudo cp sapi/fpm/php-fpm.conf /usr/local/php8.3/etc/php-fpm.conf
sudo cp sapi/fpm/www.conf /usr/local/php8.3/etc/php-fpm.d/www.conf
# 配置PHP-FPM(生产优化)
cat > /usr/local/php8.3/etc/php-fpm.d/www.conf << 'EOF'
[www]
user = www-data
group = www-data
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 15
pm.max_requests = 500
request_terminate_timeout = 300
request_slowlog_timeout = 10
slowlog = /var/log/php/slow.log
EOF
# 配置php.ini(生产优化)
cat > /usr/local/php8.3/etc/php.ini << 'EOF'
[PHP]
engine = On
short_open_tag = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
unserialize_max_depth = 1000
serialize_precision = -1
disable_functions = exec,system,passthru,shell_exec,proc_open,popen,show_source
disable_classes =
zend.enable_gc = On
expose_php = Off
max_execution_time = 300
max_input_time = 60
memory_limit = 256M
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
display_startup_errors = Off
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
html_errors = Off
error_log = /var/log/php/error.log
post_max_size = 100M
upload_max_filesize = 50M
max_file_uploads = 20
default_charset = UTF-8
file_uploads = On
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 60
date.timezone = Asia/Shanghai
[opcache]
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
opcache.fast_shutdown=1
opcache.enable_cli=1
opcache.validate_timestamps=0
EOF
# 创建日志目录
sudo mkdir -p /var/log/php
sudo chown -R www-data:www-data /var/log/php
# 创建systemd服务
cat > /etc/systemd/system/php8.3-fpm.service << 'EOF'
[Unit]
Description=PHP 8.3 FastCGI Process Manager
After=network.target
[Service]
Type=forking
PIDFile=/run/php/php8.3-fpm.pid
ExecStart=/usr/local/php8.3/sbin/php-fpm --nodaemonize --fpm-config /usr/local/php8.3/etc/php-fpm.conf
ExecReload=/bin/kill -USR2 $MAINPID
ExecStop=/bin/kill -SIGINT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
# 启动PHP-FPM
sudo systemctl daemon-reload
sudo systemctl enable php8.3-fpm
sudo systemctl start php8.3-fpm
# 验证PHP版本
/usr/local/php8.3/bin/php -v # 输出: PHP 8.3.6
# 添加PHP到PATH
echo 'export PATH=/usr/local/php8.3/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
# 安装Redis
sudo apt install -y redis-server=7.2.4
# 验证版本
redis-server --version # 输出: Redis server v=7.2.4
# 配置Redis(生产优化)
cat > /etc/redis/redis.conf << 'EOF'
bind 127.0.0.1
port 6379
daemonize no
supervised systemd
pidfile /run/redis/redis-server.pid
loglevel notice
logfile /var/log/redis/redis-server.log
# 持久化配置(必须)
save 900 1
save 300 10
save 60 10000
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/lib/redis
# 内存管理
maxmemory 1gb
maxmemory-policy allkeys-lru
# 安全
requirepass YourRedisPassword123
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""
EOF
# 重启Redis
sudo systemctl restart redis-server
# 安装PHP Redis扩展
cd /usr/local/src
sudo wget https://pecl.php.net/get/redis-6.0.2.tgz
sudo tar -xzf redis-6.0.2.tgz
cd redis-6.0.2
/usr/local/php8.3/bin/phpize
./configure --with-php-config=/usr/local/php8.3/bin/php-config
make -j$(nproc)
sudo make install
# 启用扩展
echo "extension=redis.so" | sudo tee /usr/local/php8.3/etc/conf.d/redis.ini
# 重启PHP-FPM
sudo systemctl restart php8.3-fpm
# 验证扩展
/usr/local/php8.3/bin/php -m | grep redis # 输出: redis
# 下载Composer
cd /usr/local/src
sudo php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer --version=2.7.2
# 验证版本
composer --version # 输出: Composer version 2.7.2
# 配置Composer(使用国内镜像加速)
composer config -g repos.packagist composer https://mirrors.aliyun.com/composer/
# 测试Composer
cd /var/www
composer create-project laravel/laravel example-app --prefer-dist
# 安装Supervisor
sudo apt install -y supervisor
# 配置Supervisor
cat > /etc/supervisor/conf.d/laravel-worker.conf << 'EOF'
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/example-app/artisan queue:work --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=8
redirect_stderr=true
stdout_logfile=/var/log/supervisor/laravel-worker.log
stopwaitsecs=3600
EOF
# 启动Supervisor
sudo systemctl enable supervisor
sudo systemctl start supervisor
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start all
# 创建站点目录
sudo mkdir -p /var/www/example-app
sudo chown -R www-data:www-data /var/www/example-app
# 配置Nginx虚拟主机
cat > /etc/nginx/conf.d/example-app.conf << 'EOF'
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example-app/public;
index index.php index.html;
# 日志
access_log /var/log/nginx/example-app-access.log main buffer=32k flush=5s;
error_log /var/log/nginx/example-app-error.log warn;
# 静态文件缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
# PHP处理
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# 超时设置
fastcgi_read_timeout 300;
fastcgi_send_timeout 300;
fastcgi_connect_timeout 30;
}
# 安全:禁止访问隐藏文件
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# 安全:禁止访问敏感文件
location = /wp-config.php {
deny all;
}
location = /config.php {
deny all;
}
}
EOF
# 测试配置并重载Nginx
sudo nginx -t
sudo systemctl reload nginx
在4核8G ECS上,使用Apache Bench进行压测:
| 场景 | 配置 | QPS | 平均响应时间 | 内存占用 |
|---|---|---|---|---|
| 默认配置 | 无优化 | 1200 | 83ms | 1.2GB |
| 优化后 | 开启Opcache+Redis缓存 | 4500 | 22ms | 1.8GB |
| 优化后+静态文件缓存 | Nginx缓存+CDN | 8500 | 11ms | 2.1GB |
压测命令:ab -n 10000 -c 100 http://example.com/
sudo apt install libzip-dev后手动编译安装libzip 1.9.2。validate_password.policy=LOW。save 900 1等参数开启RDB持久化。composer config -g repos.packagist composer https://mirrors.aliyun.com/composer/。opcache.validate_timestamps,否则每次请求都会检查文件修改时间,影响性能。Too many open files错误。这套配置已经在生产环境运行3个月,日均PV 50万,CPU使用率稳定在30%以下,内存使用率40%。关键点:
如果你按照这个步骤做,1小时内就能搭建一个稳定的LNMP生产环境。遇到问题,检查避坑指南里的7个坑,90%的问题都能解决。
专注技术分享与实战