ubuntu

Linux 部署服务器手札(IV)

这次由于先换了个 Linode 的 vps,为了极大程度应用的效率,而且暂时不涉及 Django 的部署,我打算将其部署成 LNMP(Linux+Nginx+MySQL+PHP)。

如往常一样,distribution 选用了 Ubuntu 13.10,下面开始全新安装。

1. 系统初始化以及基本包的安装

apt-get update
apt-get upgrade
apt-get install mysql-server nginx phpmyadmin

上面的不多作解释了,只是在安装 phpmyadmin 的时候,包管理器很“友好”地把 apache2 给装上而且自己启动了!不急,我们可以将其干掉(但是卸载的包不是 apache2 而是 apache2.2-common):

apt-get remove apache2.2-common
apt-get autoremove

2. 安装 php-cgi 并配置 spawn 守护进程

nginx 与 php 通信是通过 fast-cgi 进行的,但是以前的经验,在 win 下面 php-cgi 是会不定期死掉的,因此需要一个进程管理器。

稍微啰嗦一下 nginx 和 php-cgi 的执行原理,以前是摸索很久才得到的经验,不过没有记录好:

  • nginx 要配置到能够解析 php 页面,必须在 nginx 之外另开一个 fast-cgi 服务,叫做 php-cgi(其他语言也有用 fast-cgi 的,但 php 的版本就是 php-cgi),启动这个服务侦听 9000 端口;
  • nginx 接收到以 .php 结尾的请求的时候,就将 http 路径解析成服务器 php 脚本的路径,然后通过 9000 转发给 php-cgi 服务;
  • 然后就会有一个 php-cgi 进程接收到具体的程序请求,然后从 nginx 发过来的请求中解析到脚本地址,然后执行指定的脚本(当然,http 请求的信息也会一并传给 php-cgi);
  • php-cgi 处理完毕之后,将脚本的输出响应返回给 nginx;
  • nginx 接收到 php-cgi 的响应结果直接响应回去给客户端;

然后这里有什么问题呢?由于 php-cgi 其实并不是很稳定(好像请求多少次就会自动关掉之类的),因此一般的处理办法是同时打开多个 php-cgi 进程侦听 9000 端口,然后用进程管理器保持进程的数量(如果有旧的进程结束掉,就再启动多一些新的进程,保持进程数量多于指定的下限);

当时在 win 下面做过这样的活,是用批处理直接执行这些工作,但毕竟批处理脚本也是不很稳定的,因此在 linux 里面有更好的工具来干这个活,叫做 spawn,那么我们下面来安装。

首先,如果是安装 phpmyadmin,包管理器就自动把 php5 给装上了(直接敲 php 是可以运行的),但是 php-cgi 没有,要手动安装,那么下面我们来安装 php5-cgi 和 spawn。

apt-get install php5-cgi spawn-fcgi

好,这一段先这样,后面是配置。

3. 在 nginx 为 phpmyadmin 配置虚拟主机

首先说明一下版本:

PHP 5.4.9-4ubuntu2.4 (cli) (built: Dec 12 2013 04:29:20) nginx version: nginx/1.2.6 (Ubuntu) mysql Ver 14.14 Distrib 5.5.34, for debian-linux-gnu (x86_64) using readline 6.2

现在我们启动 nginx(如果没有启动的话),然后访问服务器的 ip 应该已经可以看到欢迎页面了。

service nginx start
3.1. 默认站点配置

配置文件在 /etc/nginx/sites-available default,vim 进去。

我们假设默认的情况下就让 nginx 显示欢迎页面,然后我们绑定相应的域名到虚拟主机上再解析到我们的应用。

然后我们需要这个默认配置能够 mask 其他的虚拟主机(我开始没有这样设置,结果输 ip 就打开的是 phpmyadmin 的界面,这样不行。)于是我们作一丁点修改:

将 server 块下面的 listen 80; 改为 listen 80 default;

这样就指定了这个配置是默认配置,其他虚拟主机都匹配不到的时候采用这个配置。

3.2. phpmyadmin 虚拟站点配置

这里我打算分配一个二级域名绑定给 phpmyadmin,下面直接写配置,也比较简短:

/etc/nginx/sites-available 下面创建一个 phpmyadmin 文件,内容如下:

server {
    listen 80;

    root /usr/share/phpmyadmin;
    index index.php index.html index.htm;

    server_name my.domain.com;

    location / {
    }

    location ~ .*\.(js|css|jpg|gif|png|ico)$ {
        expires 30d;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

如上,解释一下内容:

  • server_name 指定了绑定的域名,后面加空格还可以多加任意个别名,通过这个 server_name 过来的请求会定位到这个 server 块解析;
  • listen, root 和 index 很直白,就不说了;
  • location ~ .*\.(js|css|jpg|gif|png|ico)$ 这一块指定了一些文件名后缀,为期设置了 30 天的缓存(30 天之内请求文件的话会返回 304 not modified);之后我用 chrome 打开调试工具 Network 那一块看到文件的请求就可以看到静态资源会显示 304 跳过下载的,就是这里的功劳;
  • location ~ \.php$ 这一块就是 fastcgi 解析 php 的设置了,可以看到只要是 php 结尾的文件都会被这个 location 块捕获,反正这样写就可以按照第2节的流程来与 php-cgi 通信了。

:wq 保存配置文件,但是要启用还差一点,我们要将这个文件创建一个链接到 sites-enabled,这里我暂时没找到像 apache2 那样的 a2ensite 和 a2dissite 命令,我们手动来搞:

# 创建一个软连接到 sites-enabled
ln -s /etc/nginx/sites-available/phpmyadmin /etc/nginx/sites-enabled/
# 重启一下 nginx
service nginx restart

然后访问我们的 my.domain.com(化名 :D),返回 502。那是因为我们的 spawn-fcgi(php-cgi) 还没有开起来呢,下面我们要将其启动,并且注册到系统初始化脚本里面去。

P.S. 我们可以去看看 /etc/nginx/nginx.conf,nginx 实际的配置文件是在这里,我们可以看到里面 http 块末尾有一段:

        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;

可以看到,其实只要我们在 /etc/nginx/conf.d/ 目录里面创建以 .conf 结尾的配置文件,又或者是在 /etc/nginx/sites-enabled/ 里面创建任何配置文件(扩展名不限),都会并入 nginx 的配置里面这就是我们上面这样部署虚拟站点的原因。同样,在百度里面有些其他创建虚拟站点实在 conf.d 目录里面放的,习惯不同而已,实际上是一样的。

4. spawn-fcgi 启动配置

首先,我们手工启动一下 spawn:

/usr/bin/spawn-fcgi -a 127.0.0.1 -p 9000 -C 5 -u www-data -g www-data -f /usr/bin/php5-cgi -P /var/run/fastcgi-php.pid

然后会输出之这一行:

spawn-fcgi: child spawned successfully: PID: 27188

说明启动成功,重启下 nginx,访问网址应该就可以看到 phpmyadmin 登录页面了。

PS: 开始我一直起 spawn-fcgi 起不来,后来发现缺少了 /usr/bin/php5-cgi 才知道原来 php5-cgi 没装,装上就 ok 了。

然后,我们还要这个操作开机启动,只需要将这一行添加到 /etc/rc.local 文件底部 exit 0 之前即可。

5. wordpress 迁移

然后接下来的一步工作就是实际的网站迁移过来。

暂时我所有的网站都是 wordpress 做的,我当时只迁移了本博客。

拷目录,拷数据库这些搬砖活就不写了,我在这里只粘贴一下 nginx 的配置,关键在于 php 伪静态的处理。

再科普一下以前研究了很久但是没有记录的内容,关于 wordpress 的伪静态 rewrite 规则。

  1. 一般情况下,php 的解析目录结构与请求地址的目录结构是一致的,也就是说 http url 上面指定 php 文件的位置,nginx 就找到 对应的服务器路径脚本再交给 php;
  2. 但有些时候不是,例如 wordpress 的固定链接,如果我们不设置固定链接,文章的 url 大概会是这样:http://myblog.com/index.php?p=123
  3. 配置了静态链接之后我们想是这样:http://myblog.com/2014/4/27/postname/
  4. 也就是说我们要配置一个重写规则,让 3 这种 url 的请求能够解析成 2 那样的效果;
  5. 实际上 wordpress 设置->固定链接里面会做一个工作,当我们用 3 那样的链接访问,而实际上转向访问 index.php 的时候,他会根据 3 的 url 根据格式找到相应的 post id;
  6. 所以,我们要做的就是,让 nginx 对于找不到目录的请求,全部转交给 wordpress 的 index.php 处理即可。
  7. 我们可以在 nginx 的配置里面做这个查找文件,检测文件是否存在,重定向请求的工作;
  8. 使用 nginx 的 rewrite 语句,可以产生一个 301 或者 302 重定向(两者区别请自行百度),默认情况下是 302 临时重定向(缺省 redirect),这种情况在浏览器地址栏看到的地址,以及 php 接收到请求头的地址都是原地址(即 3 的格式);如果在 rewrite 后面加上 permanent 关键字,产生的就是一个 301 重定向(浏览器的地址改变);以前实验过,也是补录一下。

好拗口,但总比没有解释要好。

下面是具体的配置文件,不再另行解释:

server {
    listen 80;

    root /var/www/myblog;
    index index.php index.html index.htm;

    server_name www.huangwenchao.com.cn huangwenchao.com.cn;

    location / {
        index index.html index.php;
        if (-f $request_filename/index.html){
            rewrite (.*) $1/index.html break;
        }
        if (-f $request_filename/index.php){
            rewrite (.*) $1/index.php;
        }
        if (!-f $request_filename){
            rewrite (.*) /index.php;
        }
    }

    location ~ .*\.(js|css|jpg|gif|png|ico)$ {
        expires 30d;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

6. 备份任务

这个跟以前的一样,写一个 bash 脚本然后 crontab -e 就搞定了;

7. 留条尾巴,关于 django

nginx+django 还没试过,其实我个人情感喜欢 nginx 多于 apache2,以后再行研究这个;

但是在搜罗资料的时候已经发现了这个http://wiki.ubuntu.org.cn/Nginx,以后再慢慢实践。


【转载请附】愿以此功德,回向 >>

原文链接:https://www.huangwenchao.com.cn/2014/04/linux-deploy-4.html【Linux 部署服务器手札(IV)】

发表评论

电子邮件地址不会被公开。 必填项已用*标注