在VPS Ubuntu上部署Laravel:Nginx + PHP + MySQL设置

Laravel是东南亚最流行的PHP框架。要在VPS上正确部署它,您需要设置完整堆栈:Nginx + PHP-FPM + MySQL + Composer、配置文件权限、.env和队列工作程序。本指南将您从空白的Ubuntu 22.04 VPS带到正在运行的生产应用 — 一步一步。

推荐的VPS规格:2 GB或更多RAM、30 GB+ SSD、Ubuntu 22.04 LTS,适用于中等规模的Laravel应用。

理解VPS上的Laravel堆栈

在深入了解安装命令之前,了解不同组件如何协同工作会很有帮助。每个用户请求都通过服务器上的多个层:

  1. Nginx — 接受来自互联网的HTTP/HTTPS连接,充当反向代理,将PHP请求转发到PHP-FPM。
  2. PHP-FPM(FastCGI流程管理器) — 处理PHP代码并运行Laravel应用逻辑。
  3. MySQL — 存储所有应用数据:用户、帖子、订单、设置。
  4. Laravel应用 — 通过public/index.php接收请求,通过控制器和模型路由它们,然后返回响应。
  5. 队列工作程序(可选) — 处理大量后台任务,如发送电子邮件、调整图像大小或导出报告,而不阻塞请求周期。

理解这个流程使调试变得容易得多。如果页面无法加载,首先检查Nginx日志。如果看到PHP错误,检查PHP-FPM日志。如果数据未保存,查看MySQL错误。

为什么VPS对Laravel比共享主机更好:共享主机限制PHP扩展,通过终端阻止Artisan命令,并防止运行像队列工作程序这样的持久后台进程。VPS为您提供完全的root访问权限、安装任何扩展的能力、自定义php.ini的能力,以及24小时运行工作程序的能力。

在部署Laravel之前加固VPS

在安装任何软件之前,先保护服务器。连接到互联网的新VPS将在几分钟内面临自动化端口扫描和暴力攻击。

配置UFW防火墙

# 只允许必要的端口
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status

创建非Root部署用户

sudo adduser deployer
sudo usermod -aG sudo deployer

# 将您的SSH密钥复制到新用户
sudo rsync --archive --chown=deployer:deployer ~/.ssh /home/deployer

禁用SSH上的密码登录

sudo nano /etc/ssh/sshd_config
# 设置这两行:
PasswordAuthentication no
PermitRootLogin no

sudo systemctl restart sshd

在禁用密码认证之前,请始终验证基于密钥的登录是否有效,以避免将自己锁定在外。

步骤1 — 更新系统并安装Nginx

# 更新软件包列表
sudo apt update && sudo apt upgrade -y

# 安装Nginx
sudo apt install nginx -y
sudo systemctl enable nginx
sudo systemctl start nginx

步骤2 — 安装PHP 8.2 + Laravel扩展

# 添加PHP PPA (Ubuntu 22.04)
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update

# 安装PHP 8.2和所有Laravel需要的扩展
sudo apt install php8.2 php8.2-fpm php8.2-mysql php8.2-xml \
  php8.2-curl php8.2-mbstring php8.2-zip php8.2-bcmath \
  php8.2-tokenizer php8.2-gd php8.2-intl -y

# 验证版本
php -v

步骤3 — 安装MySQL

sudo apt install mysql-server -y
sudo mysql_secure_installation

# 为Laravel创建数据库和用户
sudo mysql -u root -p
CREATE DATABASE laravel_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'laravel_user'@'localhost' IDENTIFIED BY 'StrongPassword123!';
GRANT ALL PRIVILEGES ON laravel_db.* TO 'laravel_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;

第四步 — 安装Composer

curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
composer --version

第五步 — 上传您的Laravel项目

使用Git或SCP将项目传输到VPS:

# 从Git克隆(推荐)
cd /var/www
sudo git clone https://github.com/yourusername/your-laravel-app.git myapp
sudo chown -R www-data:www-data /var/www/myapp

# 安装Composer依赖项(生产模式)
cd /var/www/myapp
sudo -u www-data composer install --no-dev --optimize-autoloader

第六步 — 配置.env和应用程序密钥

cp .env.example .env
nano .env
# 编辑以下值:
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourdomain.com
DB_DATABASE=laravel_db
DB_USERNAME=laravel_user
DB_PASSWORD=StrongPassword123!

# 生成应用程序密钥
php artisan key:generate

# 运行数据库迁移
php artisan migrate --force

第七步 — 设置存储权限

sudo chown -R www-data:www-data /var/www/myapp/storage
sudo chown -R www-data:www-data /var/www/myapp/bootstrap/cache
sudo chmod -R 775 /var/www/myapp/storage
sudo chmod -R 775 /var/www/myapp/bootstrap/cache

# 创建公共存储符号链接
php artisan storage:link

第八步 — 配置Nginx虚拟主机

sudo nano /etc/nginx/sites-available/myapp

# 粘贴此配置:
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    root /var/www/myapp/public;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.ht { deny all; }
}

# 启用站点
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

第九步 — 使用Certbot安装SSL

sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Certbot将自动配置HTTPS和自动续期

第十步 — 配置队列工作程序(如果使用队列)

# Create a Supervisor config for the queue worker
sudo apt install supervisor -y
sudo nano /etc/supervisor/conf.d/laravel-worker.conf

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/myapp/artisan queue:work --sleep=3 --tries=3
autostart=true
autorestart=true
user=www-data
numprocs=2
redirect_stderr=true
stdout_logfile=/var/www/myapp/storage/logs/worker.log

# Reload Supervisor
sudo supervisorctl reread
sudo supervisorctl 更新
sudo supervisorctl start laravel-worker:*

第十一步 — 针对生产环境进行优化

# 缓存配置、路由和视图
php artisan config:cache
php artisan route:cache
php artisan view:cache

# 优化Composer自动加载器
composer dump-autoload --optimize

使用Cron设置Laravel调度器

Laravel内置的任务调度器让您可以用PHP代码管理所有计划任务,而无需创建多个独立的Cron作业。服务器上只需要一条Cron条目:

# 编辑www-data用户的crontab
sudo crontab -u www-data -e

# 添加此单行以每分钟运行调度器
* * * * * cd /var/www/myapp && php artisan schedule:run >> /dev/null 2>&1

配置完成后,应用程序调度器中定义的每个任务(每日邮件、每周清理、每小时数据同步)都将在正确的时间自动触发。示例任务:

# routes/console.php (Laravel 10+)
use Illuminate\Support\Facades\Schedule;

Schedule::command('emails:send-digest')->dailyAt('08:00');
Schedule::command('logs:clean')->weekly();
Schedule::command('cache:prune-stale-tags')->hourly();

监控和调试Laravel部署

上线后,监控确保应用程序保持健康状态。Laravel的日志系统默认将所有错误写入storage/logs/laravel.log。

实时查看日志

tail -f /var/www/myapp/storage/logs/laravel.log

常见问题与解决方法

症状 可能原因 解决方法
500 服务器内部错误 权限错误或缺少.env值 检查storage/权限和.env是否完整
404 页面未找到 Nginx根目录或try_files配置错误 确认根路径指向public/
502 网关错误 PHP-FPM未运行 sudo systemctl restart php8.2-fpm
队列中任务卡住 Supervisor未运行 sudo supervisorctl start laravel-worker:*

在VPS上管理多个环境

生产环境的Laravel应用通常涵盖至少三个环境:本地(开发者机器)、预发布(QA测试)和生产(线上服务器)。保持环境隔离可防止测试数据污染真实数据,并让团队在更改到达用户之前安全验证。

环境文件结构

# 如何组织环境文件
.env              # 当前配置(永不提交 — 已列入.gitignore)
.env.example      # 开发者入职模板(提交此文件)
.env.staging      # 预发布值(仅服务器端,不提交)
.env.production   # 生产值(仅服务器端,不提交)

结构良好的生产环境.env

APP_NAME="MyApp"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourdomain.com
LOG_CHANNEL=daily
LOG_LEVEL=error

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_prod
DB_USERNAME=laravel_prod_user
DB_PASSWORD=VeryStrongProductionPassword!

CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis

黄金法则:每个.env文件必须列入.gitignore。只有.env.example(不含真实机密)才应提交。泄露的生产环境.env会立即暴露数据库凭据和加密密钥。

Laravel Horizon:VPS上的队列仪表板

Laravel Horizon是由Laravel团队构建的官方队列监控仪表板。它提供作业吞吐量、处理时间、失败率和工作程序负载均衡的实时可见性,使队列调试比阅读原始日志文件快得多。

安装Laravel Horizon

composer require laravel/horizon
php artisan horizon:install

在config/horizon.php中配置工作程序

'environments' => [
    'production' => [
        'supervisor-1' => [
            'maxProcesses' => 10,
            'balanceMaxShift' => 1,
            'balanceCooldown' => 3,
        ],
    ],
    'local' => [
        'supervisor-1' => [
            'maxProcesses' => 3,
        ],
    ],
],

Horizon的Supervisor配置

sudo nano /etc/supervisor/conf.d/laravel-horizon.conf

[program:laravel-horizon]
process_name=%(program_name)s
command=php /var/www/myapp/artisan horizon
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/myapp/storage/logs/horizon.log
stopwaitsecs=3600

sudo supervisorctl reread && sudo supervisorctl update
sudo supervisorctl start laravel-horizon

限制Horizon仪表板访问

// app/Providers/HorizonServiceProvider.php
protected function gate(): void
{
    Gate::define('viewHorizon', function ($user) {
        return in_array($user->email, [
            '[email protected]',
        ]);
    });
}

配置完成后,在https://yourdomain.com/horizon访问Horizon仪表板。您可以查看待处理、处理中和失败的作业,并直接从界面重试失败的作业,无需SSH访问。

速率限制与API滥用防护

生产应用需要防范机器人和过度请求API的客户端。Laravel通过throttle中间件内置速率限制,并以Redis为后端,实现跨多个队列工作程序或进程的分布式计数。

在RouteServiceProvider中定义速率限制

// In App\Providers\RouteServiceProvider
RateLimiter::for('api', function (Request $request) {
    return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
});

RateLimiter::for('login', function (Request $request) {
    return [
        Limit::perMinute(5)->by($request->input('email')),
        Limit::perMinute(20)->by($request->ip()),
    ];
});

添加Nginx级别速率限制作为第一道防线

# In /etc/nginx/nginx.conf, http block
limit_req_zone $binary_remote_addr zone=api:10m rate=60r/m;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

# In your Laravel server block
location /api/ {
    limit_req zone=api burst=20 nodelay;
    limit_req_status 429;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
    include fastcgi_params;
}

location /login {
    limit_req zone=login burst=3 nodelay;
    limit_req_status 429;
    try_files $uri $uri/ /index.php?$query_string;
}
层级 工具 优势
网络层 UFW 防火墙 在流量到达Nginx前阻断端口
Web服务器层 Nginx limit_req 在调用PHP前进行速率限制
应用层 Laravel throttle 基于Redis跟踪的每用户限制
进程层 Fail2ban 自动封禁触发过多429错误的IP

在Nginx和Laravel两层同时进行防护(纵深防御),意味着恶意客户端在PHP-FPM被调用之前就会被拒绝,从而在流量高峰期节省CPU和内存资源。

零停机代码更新

将新代码推送到生产环境时,请按照以下顺序操作,以避免在更新窗口期间用户遭遇错误:

# 1. 启用维护模式
php artisan down --retry=60

# 2. 拉取最新代码
git pull origin main

# 3. 安装或更新依赖项
composer install --no-dev --optimize-autoloader

# 4. 运行待处理的迁移
php artisan migrate --force

# 5. 清除并重建缓存
php artisan optimize:clear
php artisan optimize

# 6. 重启队列工作程序
sudo supervisorctl restart laravel-worker:*

# 7. 将站点恢复上线
php artisan up

在运行迁移前使用php artisan down,可防止用户在结构性变更(如添加或删除列)期间遭遇数据库错误。

上线前检查清单:APP_DEBUG=false ✓ → APP_ENV=production ✓ → SSL已激活 ✓ → 存储权限 ✓ → 队列工作程序运行中 ✓ → 配置缓存 ✓ → Cron作业已设置 ✓ — 已准备好投入生产。

⚠️ 安全提醒:永远不要将.env文件提交到Git。启用UFW关闭不必要的端口,并考虑更改默认SSH端口以减少暴力攻击风险。

Laravel就绪VPS,价格实惠

AsiaGB VPS配备Ubuntu 22.04 LTS、完整root访问权限、SSD和泰国IP地址,您只需几分钟即可部署Laravel。

查看VPS套餐

查看泰国VPS主机全部套餐 →