小编说:Web服务器是连接用户浏览器与Python服务器端程序的中间节点,在网站建立的过程中起着重要的作用。目前最主流的Web服务器包括Nginx、Apache、lighthttpd、IIS等。Python服务器端程序在Linux平台下使用最广泛的是Nginx。
本文将带您学习Python程序与Web服务器连接的WSGI接口、Nginx的安装和配置方法,以及搭建SSL网站的技术。本文选自《Python高效开发实战——Django、Tornado、Flask、Twisted》一书
- 实战演练1:WSGI接口
WSGI是将Python服务器端程序连接到Web服务器的通用协议。由于WSGI的通用性,出现了独立的WSGI程序,例如uWSGI和Apache的mod_wsgi。
WSGI的全称为Web Server Gateway Interface,也可称作Python Web Server Gateway Interface,开始于2003年,为Python语言定义Web服务器和服务器端程序的通用接口规范。因为WSGI在Python中的成功,所以其他语言诸如Perl和Ruby也定义了类似WSGI作用的接口规范。WSGI的作用如图。
从上图中可见WSGI的接口分为两个:一个是与Web服务器的接口,另一个是与服务器端程序的接口。WSGI Server与Web服务器的接口包括uwsgi、fast cgi等,服务器端程序的开发者无须学习这部分的详细内容。服务器端的开发者需要关注的是WSGI与服务器程序的接口。
WSGI的服务器程序的接口非常简单,以下是一个服务器端程序的例子,将该文件保存为webapp.py:
代码语言:javascript复制def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return '<b>Hello, world!</b>'
该代码只定义了一个函数app,所有来自Web服务器的HTTP请求都会由WSGI服务转换为对该函数的调用。该示例的app函数中没有复杂的处理,只是通过start_response返回了状态码,并通过return返回了一个固定的HTTP消息体。与该服务器端程序相对应的是下面的WSGI Server程序:
代码语言:javascript复制#引入Python的WSGI包
from wsgiref.simple_server import make_server
#引入服务器端程序的代码
from webapp import application#实例化一个监听8080端口的服务器
server = make_server('', 8080, application)
# 开始监听HTTP请求:
server.serve_forever()
将该WSGI Server的程序保存为wsgi_server.py,通过下面的命令即可启动一个Web服务器,该服务器对所有的请求都返回Hello World页面:
代码语言:javascript复制#python wsgi_server.py
注意:虽然WSGI的设计目标是连接标准的Web服务器(Nginx、Apache等)与服务器端程序,但WSGI Server本身也可以作为Web服务器运行。由于性能方面的原因,该服务器一般只做测试使用,不能用于正式运行。
- 实战演练2:Linux Nginx uWSGI配置
Nginx 是由俄罗斯工程师开发的一个高性能HTT和反向代理服务器,其第1个公开版本0.1.0于2004年以开源形式发布。自发布后,它以运行稳定、配置简单、资源消耗低而闻名。许多知名网站(百度、新浪、腾讯等)均采用Nginx作为Web服务器。
因为Nginx是Python在Linux环境下的首选Web服务器之一,所以本节以Ubuntu Linux为例演示Nginx的安装及配置方法。
1.安装Nginx
在Ubuntu Linux中可以通过如下命令安装Nginx:
代码语言:javascript复制#sudo apt-get install nginx
安装结果如下。
安装程序把Nginx以服务的形式安装在系统中,相关的程序及文件路径如下。
-程序文件:放在/usr/sbin/nginx目录中。
-全局配置文件:/etc/nginx/nginx.conf。
-访问日志文件:/var/log/nginx/access.log。
-错误日志文件:/var/log/nginx/error.log。
-站点配置文件:/etc/nginx/sites-enabled/default。
安装好后,可以通过如下命令启动Nginx服务器:
代码语言:javascript复制.#sudo service nginx start
停止Nginx服务器:
代码语言:javascript复制#sudo service nginx stop
查看Nginx服务的状态:
代码语言:javascript复制#sudo service nginx status
重启Nginx服务器:
代码语言:javascript复制#sudo service nginx restart
2.Nginx配置文件
Nginx安装后以默认方式启动,在开发调试的过程中可能需要调整Nginx的运行参数,这些运行参数通过全局配置文件(nginx.conf)和站点配置文件(sites-enabled/*)进行设置。对全局配置文件(/etc/nginx/nginx.conf)中的关键可设置参数解析如下:
代码语言:javascript复制user www-data; ##定义运行Nginx的用户worker_processes 4; ##Nginx进程数,应设置与系统CPU数量相等的数值worker_rlimit_nofile 65535; ##每个Nginx进程可以打开的最大文件数events {
worker_connections 768; ##每个Nginx进程允许的最大客户端连接数 #在Nginx接到一个新连接通知后调用accept()来接受尽量多的连接
multi_accept off;
}http { ##
# Basic Settings
## sendfile on; ##是否允许文件上传
client_header_buffer_size 32k; ##上传文件大小限制
tcp_nopush on; ##防止网络阻塞
tcp_nodelay on; ##防止网络阻塞
keepalive_timeout 65; ##允许的客户端长连接最大秒数 ##Nginx散列表大小。本值越大,占用的内存空间越大,但路由速度越快
types_hash_max_size 2048; access_log /var/log/nginx/access.log; ##访问日志文件路径名
error_log /var/log/nginx/error.log; ##错误日志文件路径名 ## 如下两条用include命令加载站点配置文件
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
在每个Nginx服务器中可以运行多个Web站点,每个站点的配置通过站点配置文件设置。每个站点应该以一个单独的配置文件存放在/etc/nginx/sites-enabled目录中,默认站点的配置文件名为/etc/nginx/sites-enabled/default,对其中关键内容的解析如下:
代码语言:javascript复制server { ##配置站点监听的端口
listen 80; root /usr/share/nginx/html; ##配置HTTP根页面目录
index index.html index.htm; ##配置HTTP根目录中的默认页面 #站点监听的IP地址,默认的localhost只可用于本机访问,一般需要将其更改为真实IP
server_name localhost; ##location用于配置URL的转发接口
location /user/ {
##此处配置http://server_name/user/的转发地址
proxy_pass http://127.0.0.1:8080;
} ##错误页面配置,如下配置定义HTTP 404错误的显示页面为/404.html
error_page 404 /404.html;
}
3.安装uWSGI及配置
uWSGI是WSGI在Linux中的一种实现,这样开发者就无须自己编写WSGI Server了。
使用pip命令可以直接安装uWSGI:
代码语言:javascript复制#pip install uwsgi
安装完成后即可运行uwsgi命令启动WSGI服务器,uwsgi命令通过启动参数的方式配置可选的运行方式。比如,如下命令可以运行uWSGI,用于加载之前编写的服务器端程序webapp.py:
代码语言:javascript复制#uwsgi --http:9090 --wsgi-file webapp.py
*** Starting uWSGI 2.0.12 (64bit) on [Wed Feb 17 15:27:21 2016] ***
compiled with version: 4.8.2 on 17 February 2016 15:21:40
os: Linux-3.13.0-32-generic #57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014
nodename: iZ28e3m2w7rZ
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 1
current working directory: /home/lynn/project/my_project
detected binary path: /home/lynn/project/my_project/venv/bin/uwsgi
*** WARNING: you are running uWSGI without its master process manager ***
your processes number limit is 3746
your memory page size is 4096 bytes
detected max file descriptor number: 65535
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uWSGI http bound on 9090 fd 4
spawned uWSGI http 1 (pid: 18669)
uwsgi socket 0 bound to TCP address 127.0.0.1:34755 (port auto-assigned) fd 3
Python version: 2.7.6 (default, Jun 22 2015, 18:01:27) [GCC 4.8.2]
*** Python threads support is disabled. You can enable it with --enable-threads ***
Python main interpreter initialized at 0x1ff3b20
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 72768 bytes (71 KB) for 1 cores
*** Operational MODE: single process ***
WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x1ff3b20 pid: 18668 (default app)
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI worker 1 (and the only) (pid: 18668, cores: 1)
启动时用--http参数指定了监听端口,用--wsgi-file指定了服务器端的程序名。如上所示,uWSGI在启动的过程中会输出系统的一些环境信息:服务器名、进程数限制、服务器硬件配置、最大文件句柄数等。
除了在uWSGI启动命令行中提供配置参数,uWSGI还允许通过一个配置文件设置这些配置参数,比如可以编写如下配置文件,保存在文件名uwsgi.ini中:
代码语言:javascript复制uwsgi]
http = 9090
wsgi-file = webapp.py
启动uWSGI时直接指定配置文件即可:
代码语言:javascript复制#uwsgi uwsgi.ini
此时用浏览器访问服务器的9090端口,效果下。
除了http和wsgi-file参数,uWSGI还有很多其他参数,常用的如下。
- socket:以WSGI的Socket方式运行,并指定连接地址和端口。该Socket接口是uWSGI与其他Web服务器(Nginx/Apache)等进行对接的方式。
- chdir:指定uWSGI启动后的当前目录。
- processes:指定启动服务器端程序的进程数。
- threads:指定每个服务器端程序的线程数。即服务器端的总线程数为precessesthreads。
- uid:指定运行uWSGI的Linux用户id。
比如,如下配置文件用于用Socket方式启动一个uWSGI服务器,并配置了进程和线程数:
代码语言:javascript复制uwsgi]
socket = 127.0.0.1: 3011
wsgi-file = webapp.py
processes = 4
threads = 3
4.集成Nginx与uWSGI
直接通过在站点配置文件中为location配置uwsgi_pass,即可将Nginx与uWSGI集成,建立一个基于Nginx Python的正式站点。针对如下uWSGI接口有:
代码语言:javascript复制uwsgi]
socket = 127.0.0.1: 3011
wsgi-file = webapp.py
Nginx的站点配置文件为:
代码语言:javascript复制server {
listen 80; ##此处改为服务器的真实IP
server_name 121.12.134.11; location /{
##此处IP与Port配置必须与uwsgi接口中参数相同
uwsgi_pass http://127.0.0.1:3011;
}
}
技巧:可以为一个uWSGI配置多个Nginx Server和location,这样就轻松实现了以多域名访问同一个Python程序。
- 实战演练3:建立安全的HTTPS网站
普通HTTP站点的协议与数据以明文方式在网络上传输,而HTTPS(Hypertext Transfer Protocol over Secure Socket Layer)是以安全为目标的HTTP通道,即在HTTP下加入SSL层,通过SSL达到数据加密及身份认证的功能。目前几乎所有的银行、证券、公共交通的网站均以HTTPS方式搭建。
OpenSSL是一个强大的免费Socket层密码库,蕴含了主要的密码算法、常用的密钥和证书封装管理功能及SSL协议。目前大多数网站通过OpenSSL工具包搭建HTTPS站点,其步骤如下。
- 在服务器中安装OpenSSL工具包。
- 生成SSL密钥和证书。
- 将证书配置到Web服务器。
- 在客户端安装CA证书。
本节演示在Linux Ubuntu下OpenSSL的使用方法,以及Nginx在Linux下的证书配置方式。Windows中OpenSSL的使用方式与Linux中的完全一致,读者可以自行尝试。
1.在服务器中安装OpenSSL工具包
通过如下两条命令安装OpenSSL:
代码语言:javascript复制#sudo apt-get install openssl
#sudo apt-get install libssl-dev
命令运行成功后,OpenSSL命令和配置文件将被安装到Linux系统目录中。
- OpenSSL命令:/usr/bin/openssl。
- 配置文件:/usr/lib/ssl/*。
2.生成SSL密钥和证书
通过如下步骤生成CA证书ca.crt、服务器密钥文件server.key和服务器证书server.crt:
代码语言:javascript复制#生成CA 密钥
openssl genrsa -out ca.key 2048#生成CA证书,days参数以天为单位设置证书的有效期。在本过程中会要求输入证书的所在地、公司名、站点名等
openssl req -x509 -new -nodes -key ca.key -days 365 -out ca.crt#生成服务器证书RSA的密钥对
openssl genrsa -out server.key 2048#生成服务器端证书CSR,本过程中会要求输入证书所在地、公司名、站点名等。
openssl req -new -key server.key -out server.csr#生成服务器端证书 ca.crt
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365
上述命令生成服务器端证书时,必须在Common Nanme (CN) 字段中如实输入站点的访问地址。即如果站点通过www.mysite.com访问,则必须定义CN=www.mysite.com;如果通过IP地址访问,则需设置CN为具体的IP地址。
3.配置Nginx HTTPS服务器
在站点配置文件/etc/nginx/sites-enabled/default中添加如下server段,可以定义一个基于HTTPS的接口,该接口的服务器端程序仍旧为uWSGI接口127.0.0.1:3011。
代码语言:javascript复制#server {
listen 443; #HTTPS服务端口
server_name 0.0.0.0; #本机上的所有IP地址
ssl on;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;location {
uwsgi_pass http://127.0.0.1:3011;
}}
其中需要注意的是参数ssl_certificate和ssl_certificate_key需要分别指定生成的服务器证书和服务器密钥的全路径文件名。
至此,我们已经可以使用浏览器访问服务器的443端口进行HTTPS加密通信了。