• Posts tagged "nginx"

Blog Archives

在Ubuntu中安装PHP

Ubuntu实用工具系列文章,将介绍基于Linux ubuntu的各种工具软件的配置和使用。有些工具大家早已耳熟能详,有些工具经常用到但确依然陌生。我将记录我在使用操作系统时,安装及配置工具上面的一些方法,把使用心得记录下来也便于自己的以后查找和回忆。

关于作者:

  • 张丹(Conan), 程序员Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/linux-php-install/

linux-php

前言

PHP是一种高效的Web开发语言,可以嵌入在 HTML 并由服务器解释的脚本语言。PHP比CGI或者Perl更快速地执行动态网页,执行效率比完全生成HTML标记的CGI要高许多;PHP还可以执行编译后代码,编译可以达到加密和优化代码运行,使代码运行更快。

PHP已广泛地被使用在各种Web系统和应用中。

目录

  1. PHP在Windows中安装
  2. PHP在Linux Ubuntu中安装

1 PHP在Windows中安装

1.1 下载并解压PHP

在Windows中安装PHP环境非常简单,直接下载压缩文件(zip),解压即可。下载地址:http://windows.php.net/download/

解压目录:D:\toolkit\php-5.5.11

我们运行php.exe时,会弹出一个错误,计算机丢MSVCR110.ddl。

win-php

当遇到这个错误,我们需要安装VC11的相关组件,去微软官方去下载对应的组件。下载链接:http://www.microsoft.com/zh-CN/download/details.aspx?id=30679

下载对应的32位或64位的版本,双击安装下载的文件vcredist_x64.exe。我们再次双击php.exe,运行PHP正常。

安装后PHP环境后,我们还需要安装Web服务器,比如Apache, Nginx, ISS等。

1.2 下载并解压Nginx

我在这里介绍一下Nginx作为PHP的Web服务器的安装和配置。

下载Window版本的Nginx压缩文件(zip),下载地址:http://nginx.org/en/download.html

解压目录:D:\toolkit\nginx-1.5.11

+ Nginx服务器运行命令:Nginx安装目录/nginx.exe

1.3 让PHP在Nginx中运行

1.3.1 修改PHP配置文件

让我们先配置PHP环境

进入PHP目录D:\toolkit\php-5.5.11,复制php.ini-development文件并创建新文件php.ini

编辑php.ini


~ vi php.ini

;设置PHP工作目录
extension_dir = "D:/toolkit/php-5.5.11/ext"

;设置支持mysql
extension=php_mysql.dll
extension=php_mysqli.dll

;让Nginx找到PHP
cgi.fix_pathinfo=1

注: php.ini文件中,分号”;”为注释

启动PHP的CGI程序,监听9000端口:

在Window的命令行窗口输入


~ D:\toolkit\php-5.5.11>php-cgi.exe -b 127.0.0.1:9000 -c php.ini

1.3.2 修改Nginx配置文件

进入Nginx目录D:\toolkit\nginx-1.5.11,找到配置文件conf/nginx.conf

  • PHP文件运行目录,D:/workspace/php
  • 设置访问域名,php.me
  • 设置对.php文件,通过fastcgi转向127.0.0.1:9000解析

编辑文件conf/nginx.conf


~ vi conf/nginx.conf

http {

   # 忽略部分代码

   server {
       set $htdocs D:/workspace/php/;

       listen 80;
       server_name php.me;

       location / {
           root $htdocs;
           autoindex on;
           index index.php index.html;
       }

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

启动Nginx服务器


~ D:\toolkit\nginx-1.5.11>nginx.exe

1.3.3 设置host

在host中把域名php.me映射为本机IP 127.0.0.1

编辑文件C:\Windows\System32\drivers\etc\hosts


~ vi C:\Windows\System32\drivers\etc\hosts

127.0.0.1   php.me

在命令行窗口用ping命令


~ ping php.me

正在 Ping php.me [127.0.0.1] 具有 32 字节的数据:
来自 127.0.0.1 的回复: 字节=32 时间<1ms TTL=64
来自 127.0.0.1 的回复: 字节=32 时间<1ms TTL=64
来自 127.0.0.1 的回复: 字节=32 时间<1ms TTL=64
来自 127.0.0.1 的回复: 字节=32 时间<1ms TTL=64

127.0.0.1 的 Ping 统计信息:
    数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
    最短 = 0ms,最长 = 0ms,平均 = 0ms

1.3.4 PHP测试文件

在目录 D:/workspace/php/ 中,新建一个PHP的文件env.php


~ vi env.php

<?php phpinfo(); ?>

1.3.5 在浏览器中,查看PHP运行情况

在浏览器中打开HTTP地址:http://php.me/env.php

php-env

这样我们就完成了,PHP在Window中的配置。

2 PHP在Linux Ubuntu中安装

相比Windows中略显繁琐的配置,在Ubuntu中几行命令就可以完成。

我们将同样构建PHP与Nginx结合的Web服务器环境。

2.1 下载并安装PHP

默认情况,Ubuntu中会自带PHP。


# 查看PHP的版本
~ php -version
PHP 5.3.10-1ubuntu3.10 with Suhosin-Patch (cli) (built: Feb 28 2014 23:14:25)
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies

# 安装PHP依赖库
~ sudo apt-get install php5-cli php5-cgi

2.2 下载并安装Nginx

下载并安装nginx


~ sudo apt-get install nginx

# 启动nginx
~ sudo /etc/init.d/nginx start

# 查看Nginx运行状态
~ sudo /etc/init.d/nginx status
 * nginx is running

# 查看Nginx进程
~ ps -aux|grep nginx
root      2306  0.0  0.0  62860  1344 ?        Ss   15:31   0:00 nginx: master process /usr/sbin/nginx
www-data  2307  0.0  0.0  63216  1916 ?        S    15:31   0:00 nginx: worker process
www-data  2308  0.0  0.0  63216  1656 ?        S    15:31   0:00 nginx: worker process
www-data  2309  0.0  0.0  63216  1916 ?        S    15:31   0:00 nginx: worker process
www-data  2310  0.0  0.0  63216  1656 ?        S    15:31   0:00 nginx: worker process

2.3 下载并安装spawn

spawn是一个FastCGI的应用,可伸缩地、高速地在HTTP server和动态脚本语言间通信的接口。

安装spawn-fcgi


~ sudo apt-get install spawn-fcgi

启动spawn-fcgi


~ sudo /usr/bin/spawn-fcgi -a 127.0.0.1 -C 5 -p 9000 -f /usr/bin/php-cgi -P /var/run/fastcgi-php.pid
spawn-fcgi: child spawned successfully: PID: 2940

# 查看进程
~ ps -axu|grep cgi
root      2940  0.0  0.0  55196  6292 ?        Ss   15:40   0:00 /usr/bin/php-cgi
root      2941  0.0  0.0  55196  2840 ?        S    15:40   0:00 /usr/bin/php-cgi
root      2942  0.0  0.0  55196  2840 ?        S    15:40   0:00 /usr/bin/php-cgi
root      2943  0.0  0.0  55196  2840 ?        S    15:40   0:00 /usr/bin/php-cgi
root      2944  0.0  0.0  55196  2840 ?        S    15:40   0:00 /usr/bin/php-cgi
root      2945  0.0  0.0  55196  2840 ?        S    15:40   0:00 /usr/bin/php-cgi

2.4 修改Nginx配置文件

  • PHP文件运行目录,/home/conan/php
  • 设置访问域名,ubuntu.php.me
  • 设置对.php文件,通过fastcgi转向127.0.0.1:9000解析

编辑文件:nginx.conf


~ sudo vi /etc/nginx/nginx.conf

http {

   # 忽略部分代码

   server {
       set $htdocs /home/conan/php;

       listen 80;
       server_name ubuntu.php.me;

       location / {
           root $htdocs;
           autoindex on;
           index index.php index.html;
       }

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

重启nginx服务器


~ sudo /etc/init.d/nginx restart
Restarting nginx: nginx.

2.5 设置host

在host中把域名ubuntu.php.me映射为本机IP 127.0.0.1


~ sudo vi /etc/hosts

127.0.0.1       ubuntu.php.me

用ping测试ubuntu.php.me


~ ping ubuntu.php.me
PING ubuntu.php.me (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_req=1 ttl=64 time=0.040 ms
64 bytes from localhost (127.0.0.1): icmp_req=2 ttl=64 time=0.031 ms
64 bytes from localhost (127.0.0.1): icmp_req=3 ttl=64 time=0.067 ms

2.6 PHP测试文件

在目录 /home/conan/php 中,新建一个PHP的文件env.php


~ mkdir /home/conan/php

~ vi /home/conan/php/env.php

<?php phpinfo(); ?>

2.7 在浏览器中,查看PHP运行情况

在浏览器中打开HTTP地址:http://ubuntu.php.me/env.php

ubuntu-php

注:在浏览器端的host文件中,设置ubuntu.php.me域名对应到IP的映射。

这样我们完成了PHP在Ubuntu中的安装和配置了!

转载请注明出处:
http://blog.fens.me/linux-php-install/

打赏作者

Nginx反向代理Websocket

从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome浏览器就基于V8,同时打开20-30个网页都很流畅。Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低。非常适合小型网站,个性化网站,我们自己的Geek网站!!

关于作者

  • 张丹(Conan), 程序员Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/nodejs-websocket-nginx/

nodejs-nginx-ws

前言

用Nginx给网站做反向代理和负载均衡,是广泛使用的一种Web技术,不仅能够保证后端服务器的隐蔽性,还可以提高网站情况,部署灵活,而且以来源软件实现负载均衡性价比非常高。

不过今天要讲一下,如何用Nginx给Websocket服务器实现反向代理和负载均衡。我也是第一次做这样的尝试,所以仅把功能实现,优化以后再说。

目录

  1. 反向代理和负载均衡
  2. 创建基于Node的websocket服务器端
  3. 创建websocket客户端
  4. 用Nginx实现反向代理
  5. 用Nginx实现多websocket服务器的负载均衡

1. 反向代理和负载均衡

反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。

负载均衡 (Load Balancing) 负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。

2. 创建基于Node的websocket服务器端

系统环境:

  • win7 64bit
  • npm 1.2.19
  • node v0.10.5
  • bower 1.1.2
  • nginx 1.5.11
  • redis 2.4.6

创建基于Node的websocket服务器端

ws1

新建工程


D:\workspace\javascript>mkdir nginx-websocket && cd nginx-websocket
D:\workspace\javascript\nginx-websocket>npm install socket.io
socket.io@0.9.16 node_modules\socket.io
├── base64id@0.1.0
├── policyfile@0.0.4
├── redis@0.7.3
└── socket.io-client@0.9.16 (xmlhttprequest@1.4.2, uglify-js@1.2.5, active-x-obfuscator@0.0.1, ws@0.4.31)

服务器端启动文件app1.js


~ vi app1.js

var port = 3100;
var io = require('socket.io').listen(port);

io.sockets.on('connection', function (socket) {
    socket.emit('server', {
        server: 'Server1',
        port: port
    });
});

启动程序

node app1.js

3. 创建websocket客户端

通过bower安装socket.io-client库和jquery库


#下载socket.io-client
D:\workspace\javascript\nginx-websocket>bower install socket.io-client
bower socket.io-client#*        cached git://github.com/LearnBoost/socket.io-client.git#0.9.16
bower socket.io-client#*      validate 0.9.16 against git://github.com/LearnBoost/socket.io-client.git#*
bower socket.io-client#~0.9.16 install socket.io-client#0.9.16

socket.io-client#0.9.16 bower_components\socket.io-client

#下载jquery
D:\workspace\javascript\nginx-websocket>bower install jquery
bower jquery#*                  cached git://github.com/jquery/jquery.git#2.1.0
bower jquery#*                validate 2.1.0 against git://github.com/jquery/jquery.git#*
bower jquery#*                     new version for git://github.com/jquery/jquery.git#*
bower jquery#*                 resolve git://github.com/jquery/jquery.git#*
bower jquery#*                download https://github.com/jquery/jquery/archive/2.1.0.tar.gz
bower jquery#*                progress received 0.3MB of 0.7MB downloaded, 46%
bower jquery#*                progress received 0.3MB of 0.7MB downloaded, 50%
bower jquery#*                progress received 0.4MB of 0.7MB downloaded, 56%
bower jquery#*                progress received 0.4MB of 0.7MB downloaded, 61%
bower jquery#*                progress received 0.5MB of 0.7MB downloaded, 67%
bower jquery#*                progress received 0.5MB of 0.7MB downloaded, 72%
bower jquery#*                progress received 0.5MB of 0.7MB downloaded, 77%
bower jquery#*                progress received 0.6MB of 0.7MB downloaded, 81%
bower jquery#*                progress received 0.6MB of 0.7MB downloaded, 86%
bower jquery#*                progress received 0.6MB of 0.7MB downloaded, 91%
bower jquery#*                progress received 0.6MB of 0.7MB downloaded, 94%
bower jquery#*                progress received 0.7MB of 0.7MB downloaded, 99%
bower jquery#*                 extract archive.tar.gz
bower jquery#*                resolved git://github.com/jquery/jquery.git#2.1.0
bower jquery#~2.1.0            install jquery#2.1.0
jquery#2.1.0 bower_components\jquery

创建静态的html文件,作为websocket客户端:client.html


~ vi client.html

<!DOCTYPE html>
<html>
<head>
<title>Websocket Client</title>
<script src="bower_components/socket.io-client/dist/socket.io.min.js"></script>
<script src="bower_components/jquery/dist/jquery.min.js"></script>
</head>
<body>
<h1>Socket.IO Client</h1>
<div id="content">connecting....</div>

<script>
var socket = io.connect('http://localhost:3100');
socket.on('server', function (data) {
console.log(data);
$('#content').html(JSON.stringify(data));
});
</script>

</body>
</html>

用浏览器打开client.html,查看websocket通讯情况。

websocket1

服务器端和客户端通讯成功。

接下来,我们用Nginx实现Websocket服务器的反向代理。

4. 用Nginx实现反向代理

看文官说明Nginx在1.3以后的版本支持websocket反向代理,但我在Nginx1.4版本测试时失败,nginx1.5.11版本测试成功。

ws2

操作步骤:

  • 1). 下载安装Nginx
  • 2). 修改Nginx配置文件,配置反向代理
  • 3). 启动Nginx服务器
  • 4). 修改app1.js,增加超时的设置
  • 5). 修改client.html,修改nginx访问端口
  • 6). 启动Node的Websocket服务器
  • 7). 浏览器访问测试

1). 下载安装Nginx

下载地址:http://nginx.org/en/download.html

2). 修改Nginx配置文件,配置反向代理

修改nginx配置文件:nginx.conf


http {

    // ...省略

    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    server {

	    listen       3102;  #监听3102 
	    server_name localhost;

        location / {
            proxy_pass http://localhost:3100; #代理3100 

            proxy_set_header X-Real-IP $remote_addr;
	    proxy_set_header Host $host;
	    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

	    proxy_http_version 1.1;
	    proxy_set_header Upgrade $http_upgrade;
	    proxy_set_header Connection "upgrade";
        }
    }

    // ...省略
}
  • 设置nginx的访问端口:3102
  • 设置nginx的代理端口:3100

3). 启动Nginx服务器


D:\toolkit\nginx-1.5.11>nginx.exe

4). 修改app1.js,增加超时的设置

修改启动文件:app1.js


var port = 3100;
var io = require('socket.io').listen(port);

io.enable('browser client minification');  // send minified client
io.enable('browser client etag');          // apply etag caching logic based on version number
io.enable('browser client gzip');          // gzip the file
//io.set('log level', 1);                    // reduce logging

io.set('transports', [ 'websocket','flashsocket','htmlfile','xhr-polling','jsonp-polling']);

io.sockets.on('connection', function (socket) {

    socket.emit('server', {
        server: 'Server1',
        port: port
    });
});

5). 修改client.html,修改nginx访问端口


<!DOCTYPE html>
<html>
<head>
<title>Websocket Client</title>
<script src="bower_components/socket.io-client/dist/socket.io.min.js"></script>
<script src="bower_components/jquery/dist/jquery.min.js"></script>
</head>
<body>
<h1>Socket.IO Client</h1>
<div id="content">connecting....</div>

<script>
    var socket = io.connect('http://localhost:3102',{ // 访问3102端口
        'connect timeout': 500,
        'reconnect': true,
        'reconnection delay': 500,
        'reopen delay': 500,
        'max reconnection attempts': 10
    });//设置连接超时

    socket.on('server', function (data) {
        console.log(data);
        $('#content').html(JSON.stringify(data));
    });
</script>

</body>
</html>

6). 启动Node的Websocket服务器


D:\workspace\javascript\nginx-websocket>node app1.js

7). 浏览器访问测试

打开网页:

websocket2

这样就打通了nginx反向代理Websocket。不过遇到一个问题,就是tcp建立连接时特别慢,目前还没有好的解决办法。

5. 用Nginx实现多websocket服务器的负载均衡

接下来,我们在Nginx配置负载均衡。

ws3

由于基于Socket.io实现的Websocket服务器是单线程的,而访问实例被保存在MemoryStore中。如果我们想实现多个Websocket服务器或多进程调用,那么我们需要把访问实例单独存储,Socket.io集成了通过Redis的NoSQL数据库存储。

socket.io配置说明,可以参考:Configuring Socket.IO

操作步骤:

  • 1). 下载安装Redis服务器并启动
  • 2). 修改app1.js,增加Redis配置
  • 3). 新建app2.js,增加Redis配置
  • 4). 修改Nginx配置文件,配置app1,app2的负载均衡
  • 5). 启动Nginx服务器,启动app1.js, app2.js
  • 6). 浏览器访问测试

1). 下载安装Redis服务器并启动

Redis的window版本的下载地址:https://github.com/rgl/redis/downloads

启动redis


D:\toolkit\Redis>redis-server.exe

2). 修改app1.js,增加Redis配置

修改一个app1.js,绑定Redis存储实例


var port = 3100;
var io = require('socket.io').listen(port);

var RedisStore = require('socket.io/lib/stores/redis')
    , redis  = require('socket.io/node_modules/redis')
    , pub    = redis.createClient()
    , sub    = redis.createClient()
    , client = redis.createClient();

io.set('store', new RedisStore({
    redisPub : pub
    , redisSub : sub
    , redisClient : client
}));

io.enable('browser client minification');  // send minified client
io.enable('browser client etag');          // apply etag caching logic based on version number
io.enable('browser client gzip');          // gzip the file
//io.set('log level', 1);                    // reduce logging

io.set('transports', [ 'websocket','flashsocket','htmlfile','xhr-polling','jsonp-polling']);

io.sockets.on('connection', function (socket) {

    socket.emit('server', {
        server: 'Server1',
        port: port
    });
});

3). 新建app2.js,增加Redis配置

增加一个app2.js,做为第二个websocket服务器


var port = 3101;
var io = require('socket.io').listen(port);

var RedisStore = require('socket.io/lib/stores/redis')
    , redis  = require('socket.io/node_modules/redis')
    , pub    = redis.createClient()
    , sub    = redis.createClient()
    , client = redis.createClient();

io.set('store', new RedisStore({
    redisPub : pub
    , redisSub : sub
    , redisClient : client
}));

io.enable('browser client minification');  // send minified client
io.enable('browser client etag');          // apply etag caching logic based on version number
io.enable('browser client gzip');          // gzip the file
//io.set('log level', 1);                    // reduce logging

io.set('transports', [ 'websocket','flashsocket','htmlfile','xhr-polling','jsonp-polling']);

io.sockets.on('connection', function (socket) {

    socket.emit('server', {
        server: 'Server2',
        port: port
    });
});

4). 修改Nginx配置文件,配置3100,3101端口的负载均衡

修改Nginx配置文件:nginx.conf


http{
	map $http_upgrade $connection_upgrade {
		default upgrade;
		''      close;
	}

	upstream websocket {
		#ip_hash;
		server localhost:3100;  
		server localhost:3101;
	}

	server {
		listen       3102;
		server_name localhost;

		location / {
			proxy_pass http://websocket;
			
			#proxy_pass http://localhost:3100/;  
			
			proxy_set_header X-Real-IP $remote_addr;
			proxy_set_header Host $host;
			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

			proxy_http_version 1.1;
			proxy_set_header Upgrade $http_upgrade;
			proxy_set_header Connection "upgrade";
		}
	}
}

5). 启动Nginx服务器,启动app1.js, app2.js


D:\toolkit\nginx-1.5.11>nginx.exe
D:\workspace\javascript\nginx-websocket>node app1.js
D:\workspace\javascript\nginx-websocket>node app2.js

6). 浏览器访问测试

打开2个浏览器页面:

websocket3

这样就实现2个Websocket服务器轮训的负载均衡!!不过,建立连接非常慢的问题依然存在,我还没有什么好的办法。希望了解内情的同学,帮助解答!

转载请注明出处:
http://blog.fens.me/nodejs-websocket-nginx/

打赏作者

Nginx反向代理Nodejs – log4js日志IP显示错误

从零开始nodejs系列文章

从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome浏览器就基于V8,同时打开20-30个网页都很流畅。Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低。非常适合小型网站,个性化网站,我们自己的Geek网站!!

关于作者

张丹(Conan), 程序员Java,R,PHP,Javascript
weibo:@Conan_Z
blog: http://blog.fens.me
email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/nodejs-nginx-log4js/

前言

为提高web应用的吞吐量,我们一般都用nginx做负载均衡器,再反向代理到真正的web服务器。像JAVA服务可以做成Nginx+Tomcat, PHP用Nginx+Spawn-fcgi, 当然nodejs服务,我们也可以做相同的架构Ngnix+Node。

我使用nginx+nodejs+log4js时,发现log4js日志的remote_addr项,总是显示127.0.0.1。本文将重点解释如何通过修改log4js的代码,解决这个问题。

我已经提交这个问题到log4js-node的issue
https://github.com/nomiddlename/log4js-node/issues/139

log4js-bug

文章目录:

  1. 配置nginx反向代理
  2. log4js做为web日志输出
  3. log4js日志ip显示错误及修复

1. 配置nginx反向代理

本地启动nodejs : node app.js ,默认3000端口。

安装nginx

~ sudo apt-get install nginx

进入nginx配置目录

~ cd /etc/nginx/sites-enabled
/etc/nginx/sites-enabled

新建一个配置文件moive

~ vi moive

#moive.me
upstream nodejs__upstream {
        server 127.0.0.1:3000;
        #server 127.0.0.1:3001;
        keepalive 64;
}
server {
        listen 80;
        server_name www.moive.me moive.me;
        access_log /var/log/nginx/moiveme.log;
        location / {
                proxy_set_header   X-Real-IP            $remote_addr;
                proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
                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://nodejs__upstream;
        }
}

对配置项的解释:

  • listen,监听端口80
  • server_name , 监听域名 www.moive.me moive.me
  • access_log ,nginx日志输出 /var/log/nginx/moiveme.log
  • proxy_pass ,反向代理转发 http://nodejs__upstream;
  • 通过upstream nodejs__upstream 可以配置多台nodejs节点,做负载均衡。
  • keepalive ,设置存活时间。如果不设置可能会产生大量的timewait。

重新启动nginx

~ sudo /etc/init.d/nginx restart

通过浏览器访问web站点
http://moive.me

2. log4js做为web日志输出

log4js的配置与使用,请查看 玩转Nodejs日志管理log4js

查看控制台日志,发现一个问题,客户端IP记录值都是127.0.0.1。这个是我们不期待的。

GET / 304 24ms
[2013-06-20 06:55:39.405] [WARN] [default] - 127.0.0.1 - - "GET / HTTP/1.1" 304 - "" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36"
GET /css/my.css 304 5ms
[2013-06-20 06:55:39.646] [WARN] [default] - 127.0.0.1 - - "GET /css/my.css HTTP/1.1" 304 - "http://moive.me/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36"
GET /css/bootstrap.min.css 304 4ms
[2013-06-20 06:55:39.651] [WARN] [default] - 127.0.0.1 - - "GET /css/bootstrap.min.css HTTP/1.1" 304 - "http://moive.me/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36"
GET /js/holder.js 304 3ms
[2013-06-20 06:55:39.652] [WARN] [default] - 127.0.0.1 - - "GET /js/holder.js HTTP/1.1" 304 - "http://moive.me/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36"
GET /js/jquery-1.9.1.min.js 304 4ms
[2013-06-20 06:55:39.653] [WARN] [default] - 127.0.0.1 - - "GET /js/jquery-1.9.1.min.js HTTP/1.1" 304 - "http://moive.me/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36"

在浏览器通过IP直接访问,http://50.116.27.194:3000/, 所有的客户端IP显示正常。

GET / 304 12ms
[2013-06-20 06:57:49.492] [WARN] [default] - 114.252.83.33 - - "GET / HTTP/1.1" 304 - "" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36"
GET /js/holder.js 304 2ms
[2013-06-20 06:57:49.720] [WARN] [default] - 114.252.83.33 - - "GET /js/holder.js HTTP/1.1" 304 - "http://50.116.27.194:3000/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36"
GET /css/bootstrap.min.css 304 2ms
[2013-06-20 06:57:49.723] [WARN] [default] - 114.252.83.33 - - "GET /css/bootstrap.min.css HTTP/1.1" 304 - "http://50.116.27.194:3000/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36"
GET /css/my.css 304 2ms
[2013-06-20 06:57:49.724] [WARN] [default] - 114.252.83.33 - - "GET /css/my.css HTTP/1.1" 304 - "http://50.116.27.194:3000/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36"

我们把问题定位在nginx转发出现的。

在程序中打印客户端IP。

~ vi routes/index.js

        console.log("ip=>"+req.ip);
	console.log("REMOTE_ADDR=>"+req.get['REMOTE_ADDR']);
	console.log("HTTP_X_REAL_IP=>"+req.get['HTTP_X_REAL_IP']);
	console.log("x-real-ip=>"+req.get['x-real-ip']);
	console.log("x-forwarded-for=>"+req.get['x-forwarded-for']);

	var headers = req.headers;
	console.log("headers=>"+ (headers['x-real-ip'] || headers['x-forwarded-for']));
	console.log("headers x-real-ip=>"+headers['x-real-ip']);
	console.log("headers x-forwarded-for=>"+headers['x-forwarded-for']);

	console.log("====================================================");

	var proxy_ip=headers['x-real-ip'] || headers['x-forwarded-for']
	if(proxy_ip) return console.log("proxy"+proxy_ip);
	if(req.ip) return console.log(req.ip);

	console.log("====================================================");

http://moive.me, 通过nginx转发的输出结果:

[2013-06-20 07:01:48.731] [INFO] console - ip=>127.0.0.1
[2013-06-20 07:01:48.732] [INFO] console - REMOTE_ADDR=>undefined
[2013-06-20 07:01:48.732] [INFO] console - HTTP_X_REAL_IP=>undefined
[2013-06-20 07:01:48.732] [INFO] console - x-real-ip=>undefined
[2013-06-20 07:01:48.732] [INFO] console - x-forwarded-for=>undefined
[2013-06-20 07:01:48.732] [INFO] console - headers=>114.252.83.33
[2013-06-20 07:01:48.732] [INFO] console - headers x-real-ip=>114.252.83.33
[2013-06-20 07:01:48.732] [INFO] console - headers x-forwarded-for=>114.252.83.33
[2013-06-20 07:01:48.732] [INFO] console - ====================================================
[2013-06-20 07:01:48.733] [INFO] console - proxy114.252.83.33
[2013-06-20 07:01:48.733] [INFO] console - req.ip127.0.0.1

http://50.116.27.194:3000, 直接通过IP访问的输出结果

[2013-06-20 06:57:49.480] [INFO] console - ip=>114.252.83.33
[2013-06-20 06:57:49.480] [INFO] console - REMOTE_ADDR=>undefined
[2013-06-20 06:57:49.480] [INFO] console - HTTP_X_REAL_IP=>undefined
[2013-06-20 06:57:49.481] [INFO] console - x-real-ip=>undefined
[2013-06-20 06:57:49.481] [INFO] console - x-forwarded-for=>undefined
[2013-06-20 06:57:49.481] [INFO] console - headers=>undefined
[2013-06-20 06:57:49.481] [INFO] console - headers x-real-ip=>undefined
[2013-06-20 06:57:49.481] [INFO] console - headers x-forwarded-for=>undefined
[2013-06-20 06:57:49.481] [INFO] console - ====================================================
[2013-06-20 06:57:49.482] [INFO] console - req.ip114.252.83.33

我们已经发现,通过nginx转发的客户端IP是不能直接使用express3框架中req.ip获得的,而是需要通过req.headers[‘x-real-ip’]和req.headers[‘x-forwarded-for’]才能得到。

3. log4js日志ip显示错误及修复

下面我们要再查一下log4js代码,看看他是怎么实现的,为什么会出现IP的错误。

打开 log4js/lib/connect-logger.js 118行

~ vi connect-logger.js
 function format(str, req, res) {
        return str
        .replace(':url', req.originalUrl)
        .replace(':method', req.method)
        .replace(':status', res.__statusCode || res.statusCode)
        .replace(':response-time', res.responseTime)
        .replace(':date', new Date().toUTCString())
        .replace(':referrer', req.headers['referer'] || req.headers['referrer'] || '')
        .replace(':http-version', req.httpVersionMajor + '.' + req.httpVersionMinor)
        .replace(':remote-addr',req.socket && (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress)))
        .replace(':user-agent', req.headers['user-agent'] || '')
        .replace(':content-length', (res._headers && res._headers['content-length']) || (res.__headers && res.__headers['Content-Length']) || '-')
        .replace(/:req\[([^\]]+)\]/g, function(_, field){ return req.headers[field.toLowerCase()]; })
        .replace(/:res\[([^\]]+)\]/g, function(_, field){
                return res._headers
                ? (res._headers[field.toLowerCase()] || res.__headers[field])
                : (res.__headers && res.__headers[field]);
        });
 }

我们发现他的代码和express3的req.ip实现的代码是类似的,这样是不识别通过代理程序转发的客户端IP。

.replace(':remote-addr',req.socket && (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress)))

下面对这行代码进行修改。

.replace(':remote-addr', req.headers['x-forwarded-for'] || req.connection.remoteAddress)

先检查不是转发的IP,再取默认IP。

重起nodejs服务器

浏览器访问测试。

  • http://moive.me
  • http://50.116.27.194:3000
[2013-06-20 07:12:58.706] [WARN] [default] - 114.252.83.33 - - "GET / HTTP/1.1" 304 - "http://moive.me/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36"
GET /css/bootstrap.min.css 304 5ms
[2013-06-20 07:12:58.949] [WARN] [default] - 114.252.83.33 - - "GET /css/bootstrap.min.css HTTP/1.1" 304 - "http://moive.me/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36"
GET /css/my.css 304 3ms
[2013-06-20 07:12:59.153] [WARN] [default] - 114.252.83.33 - - "GET /css/my.css HTTP/1.1" 304 - "http://moive.me/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36"
GET /js/jquery-1.9.1.min.js 304 2ms
[2013-06-20 07:12:59.156] [WARN] [default] - 114.252.83.33 - - "GET /js/jquery-1.9.1.min.js HTTP/1.1" 304 - "http://moive.me/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36"

两种访问测试都正常,解决了log4js通过nginx反向代理,日志IP显示错误的问题。

转载请注明出处:
http://blog.fens.me/nodejs-nginx-log4js/

打赏作者