将博客应用自动部署到线上服务器完整流程详解
为了演示应用从开发到上线的完整生命周期,今天学院君来教你如何将刚刚开发好的博客应用上线。这里我使用的是阿里云服务器作为测试环境,操作系统默认是 Ubuntu 18.04。如果你使用的是其它云服务器(比如腾讯云等)或者自有服务器,操作步骤完全一样,都可以以此教程作为参考。
注:在开始之前,我们假设你已经购买了相应的服务器并且拥有 root 权限进行远程登录和操作。如果只是本着学习目的,新用户可以通过阿里云或腾讯云的云服务器免费试用功能进行测试。
本教程服务器环境是 Linux + Nginx + MySQL + PHP,通过 ssh 远程登录服务器,通过 Git 仓库管理代码,通过 Laravel 提供的 Envoy 工具实现代码自动化发布。
1、设置 ssh 免密码登录远程服务器
由于在上线和运维过程中,可能需要到多次登录到远程服务器,每次都要输入密码很麻烦,我们可以设置以加密的方式免密码通过 ssh 登录远程 Linux 主机,这样可以节省很多时间,也能解决你忘记密码的烦恼。
生成私钥公钥文件
如果你的本地主机不包含 ~/.ssh/id_rsa
文件,可以通过运行如下命令生成:
ssh-keygen -t rsa
每次执行上述命令后产生的私钥文件都不同,如果 ~/.ssh/id_rsa
文件已经存在,会提示是否覆盖,选择 n
不覆盖,如果该文件不存在则会生成该文件(提示需要输入的地方都可以留空)。
运行该命令会生成 ~/.ssh/id_rsa
和 ~/.ssh/id_rsa.pub
两个文件,分别存储私钥和公钥,接下来我们通过 scp
命令将公钥文件拷贝到远程服务器的 .ssh
目录下(如果服务器上没有该目录,先创建这个目录):
scp ~/.ssh/id_rsa.pub root@your-server-ip:~/.ssh
记得将命令中的 your-server-ip
换成你的服务器公网 IP。
将公钥添加到授权KEY
登录到远程服务器,运行如下命令将公钥文件内容追加到 ~/.ssh/authorized_keys
文件:
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
如果服务器上没有 ~/.ssh/authorized_keys
这个文件,可以运行如下命令将 ~/.ssh/id_rsa.pub
文件拷贝过来:
cp id_rsa.pub authorized_keys
接下来,我们在本地主机测试通过 ssh 登录远程服务器:
注意将上述命令中的 IP 地址替换成自己的服务器公网 IP,这样一来,就可以无需输入密码即可登录远程服务器了,非常方便。
2、在服务器安装 LNMP 环境
接下来,我们在服务器上安装 Nginx、MySQL、PHP及其扩展、Composer、NPM 以及 Git 工具。
升级到 Ubuntu 18.04
由于 Ubuntu 18.04 自带的 PHP 安装源就是 PHP 7.2,为了避免后续安装后升级,如果你的系统还不是 18.04 的话,这里我们一步将操作系统升级到 Ubuntu 18.04,在服务器运行如下命令即可:
do-release-upgrade
然后按照提示一路输入 y
回车即可,在弹出框选择编码时选择 UTF-8
。重启后再次登录,就可以在登录成功提示中看到系统已经升级到 Ubuntu 18.04 了。
安装 Nginx
首先是 Nginx,我们通过如下命令快速安装:
apt-get install nginx
安装 MySQL
其次是 MySQL:
apt-get install mysql-server
安装成功后,就可以在命令行测试登录了:
默认密码为空,安装的 MySQL 是 5.7 版本。
安装 PHP 及其扩展
最后是安装 PHP:
apt-get install php-fpm
默认安装的 PHP 版本是 PHP 7.2.10:
符合 Laravel 5.7 框架的最低版本要求,接下来我们运行 php -m
比对下还有哪些扩展需要安装:
对比 Laravel 5.7 安装配置 文档中对 PHP 扩展的要求,还需要安装以下扩展:
apt-get install php-mysql php-xml php-mbstring php-ctype php-zip php-curl
注:
zip
扩展会在运行 Composer 安装/更新的时候用到。
安装 Composer
此外,为了管理 PHP 依赖,还需要安装 Composer:
wget https://getcomposer.org/download/1.8.0/composer.phar
mv composer.phar /usr/local/bin/composer
chmod u+x /usr/local/bin/composer
我们可以通过 composer -V
查看是否安装成功:
注:最好为 Composer 配置一个中国镜像。网上资源很多,自行搜索实现。
安装 NPM
对应的,我们还需要安装 NPM 对前端资源进行管理:
apt-get install npm
安装该工具也会顺便安装 Node.js,默认的 NPM 版本比较低,我们可以通过这个命令对其进行升级:
npm install -g npm
更新完成后,通过 npm -v
查看其版本信息(需要退出或打开新的窗口登录服务器才能看到最新版本):
安装 Git
我们通过 Git 仓库对代码进行管理,所以还需要安装 Git 客户端工具:
apt-get install git
至此,环境和工具都已经准备好了,下面我们将博客代码上传到 Github,通过 Git 仓库来管理代码。
3、将项目代码上传到 Github
Git 仓库有很多种,可以是 Github 上的公共仓库,也可以是基于 Gitlab 自己搭建的私有仓库,我们以 Github 为例,将代码上传到 Github,以公共 Git 仓库的方式对博客项目代码进行管理。
首先在 Github 上创建一个新的仓库,比如我将其命名为 laravel-blog-code
,类型选择为 public
,创建完成后,就有了一个地址为 https://github.com/nonfu/laravel-blog-code
的远程 Git 仓库。
然后在本地项目根目录下通过运行如下命令将项目与上面新建的远程 Github 仓库关联起来:
rm -rf .git // 如果原来有 .git 目录将其删除
git init
git remote add origin https://github.com/nonfu/laravel-blog-code
接下来就可以提交项目代码到远程 Github 仓库了:
git add .
git commit -m '博客项目代码'
git pull --allow-unrelated-histories
git push --set-upstream origin master
这样,就会将项目代码都提交到对应的 Github 仓库。
4、在服务器首次部署项目
初始化项目资源
代码既然已经上传到 Git 仓库,接下来,我们就可以在服务器拉取最新代码了。我们准备将 /var/www
目录作为 Web 应用根目录,在该目录下通过 Git 命令从 Github 克隆项目:
git clone https://github.com/nonfu/laravel-blog-code
进入博客项目根目录,运行如下命令初始化后端依赖和前端依赖,并且编译前端资源:
cd laravel-blog-code/
composer install
npm install
npm run prod
如果在运行 npm run prod
的过程中报错,可以尝试通过在 package.json
中指定 cross-env
的路径来解决:
"scripts": {
...
"prod": "npm run production",
"production": "node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
更新目录权限
由于 Nginx 默认用户名和用户组都是 www-data
,所以我们将 laravel-blog-code
整个项目目录的所属用户和用户组也设置为 www-data
:
cd /var/www
chown -R www-data:www-data laravel-blog-code/
这样一来,就一劳永逸的解决了 Laravel 项目目录权限的问题。另外,在 public
目录下创建一个指向 storage/app/public
目录的软链 storage
:
php artisan storage:link
创建线上数据库
通过 mysql -u root -p
登录到数据库,如果连接报错:
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'
尝试运行 service mysql start
启动 MySQL 服务。
默认数据库密码为空,下面我们来设置 root
用户密码提高安全性,MySQL 5.7 设置密码的方式和之前版本有些不同,因为 mysql.user
表中没有 password
字段了:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your-password';
将 your-password
替换成你自己的数据库密码,运行 quit
退出,然后重新连接数据库,此时就要输入密码才能连接了。进入交互式命令行后运行如下命令在数据库中新创建一个数据库 blog57
:
create database blog57 default charset utf8 collate utf8_general_ci;
更新线上 .env
配置
接下来,回到 laravel-blog-code
博客项目根目录,创建线上 .env
环境配置文件,初始化应用配置:
cp .env.example .env
php artisan key:generate
然后修改应用其它配置信息如下:
APP_NAME=Laravel学院
APP_ENV=production
APP_DEBUG=false
APP_URL=http://blog.laravelacademy.org
注:请将
APP_NAME
和APP_URL
配置为你自己的应用名称和 URL。
接下来修改数据库配置信息和邮箱配置信息。
运行数据库迁移和填充命令初始化数据
准备好数据库和环境配置后,就可以运行迁移命令创建数据表了:
php artisan migrate
然后运行填充命令初始化应用测试数据:
php artisan db:seed
这样我们就已经准备好数据库和测试数据了。接下来我们配置 Nginx 指向这个 Web 应用。
配置 Nginx 指向博客应用
Nginx 相关配置位于 /etc/nginx
目录下,我们进入 sites-available
目录创建一个新的应用配置文件:
cd /etc/nginx/sites-available
touch laravel-blog.conf
通过 vi laravel-blog.conf
命令打开该文件,输入 i
进入编辑模式,编辑文件内容如下:
server {
listen 80;
server_name blog.laravelacademy.org;
root /var/www/laravel-blog-code/public;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri /index.php =404;
fastcgi_index index.php;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
#fixes timeouts
fastcgi_read_timeout 600;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
location /.well-known/acme-challenge/ {
root /var/www/letsencrypt/;
log_not_found off;
}
error_log /var/log/nginx/blog57_error.log;
access_log /var/log/nginx/blog57_access.log;
}
注:请将
server_name
配置域名修改为自己的域名。如果你的应用目录和 PHP 版本与本教程默认值不符,也需要做相应调整。
编辑完成后,输入 :wq
保存并退出,然后进入上一级目录下的 site-enabled
目录创建一个指向该文件的软链:
cd ../sites-enabled/
ln -s ../sites-available/laravel-blog.conf laravel-blog
然后运行如下命令检测配置是否有误:
service nginx configtest
启动 Nginx、PHP-FPM
至此,我们已经完成了第一次部署项目上线的所有初始化配置,最后,我们来启动 Nginx 和 PHP-FPM(已经启动的话需要重启):
service nginx start
service php7.2-fpm start
如果 MySQL 没有启动的话,也要启动:
service mysql start
5、访问线上博客应用
通过本地虚拟域名访问
至此,我们已经成功将项目部署到线上,现在可以在本地访问线上应用了,本教程中,学院君配置的域名是 blog.laravelacademy.org
,如果你没有购买过域名,或者域名还没有备案,可以通过在本地配置虚拟域名的方式访问,即在 /etc/hosts
中配置域名与线上服务器的映射:
47.99.47.169 blog.laravelacademy.org
将 47.99.47.169
替换成你自己的远程服务器公网 IP 即可。这样,就可以在本地浏览器中访问 http://blog.laravelacademy.org
了:
第一次访问弹出这样的页面,意思是让我们到服务器删除 /var/www/html
演示项目,我们登录到服务器删除这个目录:
cd /var/www/
rm -rf html/
再次访问 http://blog.laravelacademy.org
,如果页面显示空白,则还需要到服务器修改 Nginx 配置,打开 /etc/nginx/fastcgi_params
,在文件末尾加上如下两行代码:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_script_name;
保存退出后,重启启动 Nginx,这样,就可以访问博客首页了:
此时,还没有上传背景图片,我们可以登录到服务器通过 Tinker 手动创建后台用户,然后上传对应的背景图片(这些在前面的教程中都已经演示过,这里不再赘述),如果上传过程中报错:
413 Request Entity Too Large
需要修改 PHP 上传文件最大尺寸限制,在服务器上打开 /etc/php/7.2/fpm/php.ini
,找到 upload_max_filesize = 2M
这一行,将其值调整为 8M
:
upload_max_filesize = 8M
保存退出,重启 PHP-FPM:
service php7.2-fpm reload
此外,还要在 /etc/nginx/nginx.conf
新增配置,在 http {}
配置中新增如下这行配置:
client_max_body_size 10m; // 这里的配置值稍大于或等于 PHP 中的配置
修改完成后保存退出,然后重启 Nginx,这样,就可以上传成功了。再次访问首页,即可看到背景图片了:
通过 DNS 域名解析访问
如果你有一个已经备案的域名,还可以通过在域名服务商那里通过域名解析的方式将域名指向服务器公网 IP,这样,所有人都可以通过指定的域名访问你的应用了,还是以阿里云为例,你可以通过在控制台域名列表选择解析进入域名解析页面,点击「新增解析」按钮,在弹出框填写表单:
主机记录处填写你的域名前缀,比如 www
、blog
等,如果不想有前缀,可以填写 @
,就像Laravel学院那样。填写完成后,点击确定,等待几分钟,就可以解析成功了。
在本地 /etc/hosts
文件中删除之前绑定的虚拟域名:
47.99.47.169 blog.laravelacademy.org
再次访问 http://blog.laravelacademy.org/blog
,依然是 OK 的,说明我们的域名解析已经生效了,接下来,就可以把网址分享给你的小伙伴,让他们来访问你的博客了。
这样,我们就完成了应用从首次部署上线到支持公开访问的完整流程。
6、后续代码迭代更新上线
一般来说,项目都是需要迭代开发上线的,这里,我们使用 Git 管理代码的优势就体现出来,以后每次修改代码,测试完成合并到指定上线分支(比如 master
分支)后,就可以直接到服务器上通过 git pull
拉取最新代码了,如果最新代码有问题,也可以快速回滚到上一个稳定版本,将事故影响降到最低。关于 Git 开发工作流是另外一个话题,这里就不展开了,针对个人博客这种小项目,也不需要搞那么复杂。
基于 Envoy + Git 实现自动化部署
我们知道,Laravel 还提供了一个远程执行服务器命令的扩展包 Envoy,我们可以借助这个扩展包结合 Git 工具实现简单的自动化部署代码到服务器。
实现起来非常简单,首先需要在本地全局安装 Envoy 扩展包:
composer global require laravel/envoy
安装完成后,到本地项目根目录下创建一个 Envoy.blade.php
文件,并编写自动化部署脚本如下:
@servers(['web' => 'root@47.99.47.169'])
@task('deploy', ['on' => ['web'], 'confirm' => true])
cd /var/www/laravel-blog-code
git pull
@endtask
我们将需要部署的服务器配置到 @servers
指令中(支持多台机器部署,将对应IP换成你自己的服务器IP),然后在 @task
指令中,通过第一个参数指定命令名称,第二个参数指定部署机器和配置(比如多台机器并行发布,部署前是否确认),具体的操作步骤位于 @task
和 @endtask
之间。当然,这里你还可以进一步进行优化,比如如果需要安装 PHP 扩展包需要运行 composer update
命令,如果更新了前端资源需要运行 npm
相关命令,有数据库迁移还需要运行 php artisan migrate
等。学院君这里只是给你一个方向,具体细节可以自己去优化,更多 Envoy 使用细节可以参考官方文档。
定义好自动化发布脚本后,接下来,我们就可以在本地项目根目录下运行如下命令,发布迭代更新的代码到服务器:
envoy run deploy
这样,我们就完成了一个简单的自动化部署代码到线上的解决方案,对于小型项目来说,还是很方便的,无需登录服务器即可快速完成代码上线,尤其是你有多台服务器的话,更有必要这么做。
注:需要将
Envoy.blade.php
文件添加到.gitignore
文件,避免泄露敏感信息。
以更新 Disqus 评论框为例演示自动化部署
下面,我们以更新 Disqus 评论框域名配置为例,演示下自动化部署代码上线,并测试效果。我们之前在实现 Disqus 评论框的时候,域名是写死的:
var disqus_config = function () {
this.page.url = 'http://blog.app/blog/{{ $post->slug }}';
this.page.identifier = 'blog-{{ $post->slug }}';
};
这就导致上线之后需要修改域名信息,造成本地与线上代码的不一致,维护起来非常麻烦,所以我们将其改写为通过配置文件读取 .env
中 APP_URL
环境字段的方式来获取应用域名:
var disqus_config = function () {
this.page.url = '{{ config('app.url') }}/blog/{{ $post->slug }}';
this.page.identifier = 'blog-{{ $post->slug }}';
};
改写完成后,将其提交到 Github 仓库:
git add .
git commit -m '修改disqus评论框域名获取方式'
git push
然后,我们无需登录到线上服务器,只需在本地项目根目录下运行 envoy run deploy
即可完成代码部署:
这样,就成功将修改后的文件上传到服务器了,打开博客详情页,就可以看到 Disqus 评论框了:
你也可以将博客的站点地图提交给搜索引擎,让它们来抓取你的网站了。
写到这里,就算是完成了博客应用的完整生命周期,同时,也希望对那些不太熟悉部署应用上线流程的同学有所启发。
35 Comments
真的很详细,辛苦了,谢谢!
ErrorException : Undefined offset: 0
at /usr/local/nginx/html/blog57/database/seeds/PostsTableSeeder.php:33 29| return; 30| } 31| 32| shuffle($tags);
这是什么原因啊 求解
本地免密登录服务器什么的都做了 但是 本地执行envoy 还是会报错 下面是我的代码 不知道哪里出的问题啊 @servers(['web' => 'root@IP'])
@task('deploy', ['on' => ['web'], 'confirm' => true]) cd /usr/local/nginx/html/blog57 git pull @endtask
报错信息 This task did not complete successfully on one of your servers.
你先登录到服务器手动执行下这两个命令看是否报错
没有报错啊 提示的是
[root@iz2zecarj1v1oh39etx4p0z blog57]# cd /usr/local/nginx/html/blog57 [root@iz2zecarj1v1oh39etx4p0z blog57]# git pull Already up-to-date.
那为啥 envoy 报错了 神奇
买的VPS已经安装好了Ubuntu 18.04,我想查看还安装好了哪些东西应该用什么命令啊?
Nginx配置有问题吗?已经改了域名、目录,PHP版本也是一致的,配置检测是OK,但是通过本地虚拟域名去访问,页面是404 not fund.
server {
}
打开 acess_log 和 error_log 看下明细 应该可以定位出来
只能一个个去看 或者通过安装的方式去测试是否已安装 nginx mysql php 都要自己装的 不会自带的