Ubuntu+Nginx搭建全功能服务器
最终效果:nginx作为统一的前端服务器,处理所有的站点的静态页面,同时,将不同站点的脚本发送到不同的后端引擎,包括Django(Python),PHP,NodeJs,当然,同理可以继续增加Mono+.Net的站点,和ROR的站点配置。
以前一直在使用lighttpd,不过这服务器貌似不怎么更新了,传说中的2.0已经说了好几年了也不出来,只是过几个月偶尔放一个补丁版本出来修改一两个重要Bug,远不像nginx这么活跃。而且原来的lighttpd的PHP采用了fastcgi模式配置以后,进程里面5个PHP站点启动了十几个PHP的fastcgi进程,相当浪费内存。于是决定统一换到nginx。不过过程还是挺痛苦的。
安装nginx,直接apt-get install nginx搞定。配置文件也自动安装好了,自己编译安装的话当配置文件就得累个半死。/etc/nginx/目录下好多配置文件,其中的nginx.conf里面的连接数、压缩、缓存之类的参数自己可以改一改,其它的不用动。
在site-available目录下已经有一个默认的default站点配置,在site-enabled目录下是指向它的一个软链接。同样,把所有的可用的站点配置文件放在site-available目录下,把需要生效的站点链接到site-enabled下即可。可以删掉default。
第一步,先是PHP。mysql和PHP我比较喜欢自己编译安装。mysql现在安装的是MariaDB 5.5.34,编译参数都跟mysql完全一样。下载tar.gz的源代码文件,tar zxvf mariadb-5.5.34.tar.gz解压,然后进入这个目录,使用这个配置:
cmake . \
-DCMAKE_BUILD_TYPE:STRING=Release \
-DCMAKE_INSTALL_PREFIX:PATH=/opt/mysql \
-DINSTALL_DATADIR=/docs/mysqldb \
-DCOMMUNITY_BUILD:BOOL=ON \
-DENABLED_PROFILING:BOOL=ON \
-DENABLE_DEBUG_SYNC:BOOL=OFF \
-DINSTALL_LAYOUT:STRING=STANDALONE \
-DMYSQL_MAINTAINER_MODE:BOOL=OFF \
-DWITH_EMBEDDED_SERVER:BOOL=ON \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DWITH_EXTRA_CHARSETS:STRING=all \
-DWITH_SSL:STRING=bundled \
-DWITH_UNIT_TESTS:BOOL=OFF \
-DWITH_ZLIB:STRING=bundled \
-LH
然后make && make install就安装好了。安装后把my.cnf放到/opt/mysql目录下,用这个目录下的mysql.server start就可以启动。
然后下载PHP的5.5.6版本,同样解压后进入目录,执行
./configure –prefix=/opt/php –disable-debug –with-config-file-path=/opt/php/etc/php.ini –enable-shmop –with-gd –with-jpeg-dir=/usr/lib64 –with-png-dir –with-libxml-dir –with-zlib-dir –with-mysqli=mysqlnd –with-mysql=mysqlnd –with-pdo-mysql=mysqlnd –enable-sockets –with-iconv –enable-mbstring –enable-mbregex –enable-ftp –enable-gd-native-ttf –with-freetype-dir –enable-fpm –with-fpm-user=nobody –with-fpm-group=nogroup –enable-opcache
中间提示缺什么组件就搜一下,然后用apt-get install安装对应的包就可以。注意-enable-fpm,这是fastcgi模式下的PHP的进程管理工具,在高版本的PHP里已经是内嵌的功能,启用后会生成一个独立的php-fpm的可执行文件。另外最后的-enable-opcache,就是以前版本中的zend optimizer,加速器,5.5里面也变成了内置的部分。但是这个东西编译安装后并不会自动生效,需要自己加到php.ini里去。
配置完成后make && make install,就安装好了。然后把php.ini-production复制到/opt/php/etc/php.ini,里面需要修改的东西不多,可以在最后面加上这么一段:
zend_extension=opcache.so
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.enable_cli=1
opcache.enable=1
用来启用加速功能。另外/opt/php/conf/目录下有个php-fpm.conf.default,改名成php-fpm.conf,然后修改里面listen参数为listen = /tmp/php-fpm.socket,下面的pm相关的几个值可以自己根据情况调一下。编译后的php源码目录里,sapi/fpm目录下有个init.d.php-fpm,可以把它复制为/etc/init.d/php-fpm文件,并添加可执行属性,这样就可以通过它来启动fpm了,/etc/init.d/php-fpm start。不过这个脚本启动以后不会加载php.ini,不知道为什么,可以打开这个文件修改一下,在第四行的参数定义的地方加上-c /opt/php/etc/php.ini。
启动以后应该就有了/tmp/php-fpm.socket文件。这时候在nginx里添加一个站点,转发给PHP进程就可以了。在/etc/nginx/site-available目录下添加一个自己站点名字的配置文件,内容是:
server { listen 80; server_name www.unfish.net; location / { root /docs/htdocs/public/unfish/wordpress/; index index.php index.html index.htm; if (-f $request_filename) { expires 30d; break; } if (!-e $request_filename) { rewrite ^(.+)$ /index.php?q=$1 last; } } location ~ .php$ { fastcgi_pass unix:/tmp/php-fpm.socket; # port where FastCGI processes were spawned include fastcgi_params; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /docs/htdocs/public/unfish/wordpress/$fastcgi_script_name; # same path as above fastcgi_param PATH_INFO $fastcgi_script_name; } }
可以看的出来这是一个wordpress程序的配置文件,这个配置即包含了静态文件的托管,也包含了URL静态化以后的处理逻辑。fastcgi_pass unix:/tmp/php-fpm.socket;这个配置就是转发请求到php的socket接口。网上很多教程会讲ip:port的方式,其实在本地来说,socket方式效率更高,也不占用端口。对于其它的PHP站点,内容基本完全一样,只需要改server_name和root的路径参数。试试看PHP站点是不是可以打开了?
然后我们添加一个Django站点的配置文件。Django 1.4以前的版本是推荐fastcgi方式启动的,需要flup组件。后面的版本推荐的方式改成了wsgi方式,而且在项目生成模板的时候,就会自动生成一个wsgi.py文件,用来启动wsgi模式的服务。我现有的站点生成的版本比较老,没有这个文件,这也没关系,我们使用ini文件的方式来启动。在生产环境中运行django项目,就不能靠这个wsgi.py和manage.py了,需要更完整的wsgi服务器,uwsgi。下载最新版本的源代码,解压后在它的目录里执行python uwsgiconfig.py –build,就会执行编译命令,然后得到一个独立的可执行文件,uwsgi,简单起见,把这个文件复制到/usr/sbin/目录里就可以用了。
然后在Django项目的目录下,在settings.py的同级目录里,建一个wsgi.ini,内容是:
[uwsgi] socket = /docs/htdocs/licaie/web.sock chdir = /docs/htdocs/licaie/web/ pythonpath = .. env = DJANGO_SETTINGS_MODULE=web.settings_fastcgi module = django.core.handlers.wsgi:WSGIHandler() processes = 4 master = true threads = 5 daemonize = /var/log/uwsgi-licaie.log
第一行同样是生成后的socket文件用于连接nginx,后面的chdir是项目目录(我的项目名是web),settings_fastcgi.py是在这个项目目录下的用于生产环境的配置文件的名字,其它的都可以自己调。然后执行uwsgi wsgi.ini,这个站点就算启动了。然后在nginx下面增加一个站点的配置文件,内容是:
upstream django-licaie { server unix:/docs/htdocs/licaie/web.sock; } server { listen 80; server_name www.licaie.com; location ~ ^/site_media/(.*) { # STATIC_URL alias /docs/htdocs/licaie/web/templates/$1; autoindex off; expires 30d; } location /uploads { # STATIC_URL alias /docs/htdocs/licaie/web/uploads; expires 30d; } location ~ /(.*) { uwsgi_pass django-licaie; include uwsgi_params; } }
site_media和uploads是两个静态目录,alias可以指向不同文件名的目录。最下面的代码指定转发方式。重启nginx,应该就可以看到这个站点的成功运行了。
最后是nodejs,这个不能直接apt-get install nodejs,因为主源里面的nodejs版本太老了,新的组件都不支持这个版本,需要添加一个服务器。
sudo apt-get install -y python-software-properties python g++ make sudo add-apt-repository -y ppa:chris-lea/node.js sudo apt-get update sudo apt-get install nodejs
这样就可以安装上最新版本的nodejs了。然后用npm install express -g安装express,然后就可以创建基于express的站点了。对于express生成的站点模板,理论上只要在这个站点目录下执行node app.js,这个服务器就启动了。但是,同样的,这个方式也不适合生产环境。因为它启动的只是个单任务单线程的站点。我们需要用到PM2这个项目。只要运行
npm install -g pm2
就可以了。然后在这个站点目录下执行pm2 start app.js -i max就可以执行起这个站点。然后需要到nginx里添加一个对应的站点配置文件,内容是:
root@li315-123:/opt/php# ls var/ upstream nodejsapp1_upstream { server 127.0.0.1:9000; keepalive 8; } server { listen 80; server_name nodeapp1.unfish.net; location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) { root /docs/htdocs/nodejsApp/nodeapp1/; access_log off; expires max; } location / { proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_set_header Connection ""; proxy_http_version 1.1; proxy_pass http://nodejsapp1_upstream; } }
内容跟上面的差不多,只是这里目前我还没有找到用socket方式连接的方法,只有用IP+端口的方式。这个站点的端口号就在站点的app.js文件里,打开就看到了。重启nginx以后远程访问这个站点的域名,应该就可以看到这个站点输出的信息了。(默认是welcome to Express)
至此,一个支持PHP+Django+Nodejs的服务器就搭建好了。基本同样的代理方式,还可以再为nginx添加对Mono和ROR的支持。