mac系统版本为OS X EI Capitan 10.11.4
(其实系统已经安装好了管理员权限的apache,在/etc/apache2下,但是我们还是要安装用户权限的apache,方便更改文件不需要权限)

默认已经在mac上面安装好了用户权限的apache。(如果没有安装好的话,传送门:Apache Installing

apache安装的一些小问题

我简单说说在安装apache过程中遇到的问题:

  • 如果遇到OSError或者写入错误的话,一般是没有root目录下的写入权限,使用sudo命令获得权限就好。
  • configure: error: C compiler cannot create executables 解决方法传送门
  • 通常在安装的过程中会遇到各种各样的工具缺失,比如apr,pcre等,去官网下载源码下来解压,然后运行configure文件后编译就好了。命令如下:
./configure --prefix=安装地址
make
make install
#如果想清除之前的.o文件可以使用make distclean

安装好apache之后命令行进入bin目录下运行./apachectl start启动apache服务。

  • 启动过程中最常见的就是80端口被占用,体现为套接字无法绑定地址,为了省事,我直接将apache中conf目录下的httpd.conf文件中监听的端口改成了8000。
Listen 127.0.0.1:8000
  • 以及还遇到了这个错误:httpd: Could not reliably determine the server’s fully qualified domain name, using 127.0.0.1 for ServerName
    这里需要改一下/etc/hosts文件以及ServerName属性,详细解决方法看以上链接。

开启浏览器输入localhost后返回it works之后apache则安装成功。

apache安装扩展模块mod_wsgi

安装方法传送门:mod_wsgi installation
第一种方法是传统的apache安装扩展模块的方法,先下载mod_wsgi源码,configure然后再编译安装,然而因为在make intall的时候出现了root权限问题(用sudo也无法解决,详细的情况讨论请参见这里),所以我选择了用第二种方法安装mod_wsgi模块。

第二种方法就是直接用pip安装mod_wsgi,安装好之后将mod_wsgi-py27.so的路径配置在httpd.conf文件中。命令如下:

[sudo] pip install mod_wsgi
mod_wsgi-express module-location
#将输出的路径复制到httpd.conf中,假设输出的路径为/user/local/mod_wsgi-py27.so
#在http.conf中写入以下命令:
LoadModule wsgi_module /user/local/mod_wsgi-py27.so

重新启动apache服务器,mod_wsgi模块就应该安装好了。

hello world example 与 mod_wsgi模块交互

接下来可以试一下用一个简单的hello world application来测试一下mod_wsgi模块的正常工作。
定义一个符合WSGI标准的application并保存该文件为hello.wsgi。(如果不太清楚WSGI标准的可以参看我的一篇博客: WSGI初探及wsgiref简单实现)

#hello.wsgi
def application(environ, start_response):status = "200 OK"response_headers = [('Content-type', 'text/plain')]output = "hello world!"start_response(status, response_headers)return [output]

我尝试用了两种方法来配置apache使其调用hello.wsgi返回hello world。

  1. 第一种方法就是直接将hello.wsgi放在apache的根目录下访问,比较简单。
  2. 第二种方法就是在apache上配置一个虚拟主机,通过自己设置的域名来访问hello.wsgi。

我们先来看第一种方法:

  1. 首先打开conf目录下的httpd.conf文件(就是apache的主服务器的配置文件),找到DocumentRoot变量,它的值就是apache服务器的根目录,把你的hello.wsgi文件拖到该目录下。(注意,在mac下应该已经确认在Finder中打开所有的文件后缀名,hello.wsgi的后缀名为.wsgi,当然,不一定要使用后缀名.wsgi,也可以使用.py后缀)
  2. 然后在DocumentRoot变量(假设为/Users/Apache/WWW)下设定WSGI脚本的别名:
WSGIScriptAlias /hello.wsgi /Users/Apache/WWW/hello.wsgi

在打开apache服务后,我们在浏览器中输入localhost :8000/hello.wsgi (监听的端口为8000),即可看到“hello world!”。

值得注意的是,如果WSGIScriptAlias设置成了:

WSGIScriptAlias / /Users/Apache/WWW/hello.wsgi

那么在WWW目录下的所有静态文件都会被屏蔽,对localhost:8000/*(*表示任意字符)的任意访问都会转换成对hello.wsgi的访问。如果我们还想要访问在WWW目录下的静态文件,则需要用到Alias指令。

第二种方法:

1.首先 在http.conf文件中设置可以引入包含虚拟主机的文件:

# Virtual hosts
# Include conf/extra/httpd-vhosts.conf
将上面的#去掉就可以引入虚拟主机的配置文件了

2.在extra目录下找到http-ghosts.conf配置virtual host,基本跟配置主服务器一样:
(假设虚拟主机的根目录为/Users/Apache/VirtualHost,监听的端口为8001)

<VirtualHost *:8001>DocumentRoot "/Users/Apache/VirtualHost"ServerName www.virtualhost.comServerAlias virtualhost.comWSGIScriptAlias /hello.wsgi /Users/Apache/VirtualHost/hello.wsgiDirectoryIndex index.html<Directory "/Users/Apache/VirtualHost">Options Indexes FollowSymLinksAllowOverride NoneRequire all granted</Directory>
</VirtualHost>

3.在设置完虚拟主机的配置文件之后,我们还不能在浏览器中立即测试我们的新域名,我们还要将新域名和127.0.0.1绑定起来。因此打开/etc/hosts文件,绑定域名和地址(修改文件需要权限):

127.0.0.1      virtualhost.com

那么/etc/hosts为什么要这样设定呢?
一般来说,当浏览器得到域名的时候,浏览器首先通过/etc/hosts文件查询它的ip地址,得不到ip的时候再向DNS服务器查询。因此,如果我们在mac上设置了shadowsocks的全局代理,所有的请求直接走代理,那么我们就获取不到这个我们自己创立的域名的ip地址了。(所以记得关闭你的翻墙工具)
此时,我们打开浏览器就可以输入virtualhost.com:8000/hello.wsgi就能看到“hello world!”了。

关于mod_wsgi模块的embedded mode(嵌入模式)与Daemon Process(守护进程)

mod_wsgi模块在加载WSGI应用程序的时候有两种不同的模式,默认使用的是嵌入模式,而另一种模式是守护进程,等会我们会讲述如何开启守护进程。
这两种模式有什么不同呢?嵌入模式将会直接在apache的子进程中加载WSGI Application,而守护进程则会在与apache进程的不同进程中加载,需要进行进程间的通信机制。因此,如果对WSGI Application的代码进行了修改,那么在嵌入模式下需要重启apache服务器,而在守护进程下则不需要重启服务器(这对于如果没有重启服务器的权限却又需要修改应用程序的情况下是很有用的)。
以及,如果多个django的项目布置在同一台apache服务器上,也是推荐用守护进程,否则进程中的django_settings_module会相互错乱,具体参考这里:How to use Django with Apache and mod_wsgi。

接下来是Daemon process的virtual host配置代码(在第二种方法的代码基础上加上以下代码):

#在VirtualHost标签内加上以下代码
WSGIDaemonProcess virtualhost.com processes=2 threads=15 display-name=%{GROUP}
WSGIProcessGroup virtualhost.com#在VirtualHost标签以外加上以下代码
WSGISocketPrefix /Users/Apache/run/wsgi

关于前两行代码的详细作用请参考官方文档。
重点说一下最后一行的作用,首先假设我们没有在VirtualHost标签以外加上WSGISocketPrefix,或者,WSGISocketPrefix指定的目录没有读写权限,我们访问hello.wsgi都会返回:

503 Service UnavailableThe server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.

为什么会这样呢?首先我们知道Daemon模式下是不同进程间的通信,而其中使用了本地的socket,因此,服务器端需要对一个文件目录拥有写的权限来保存socket文件,客户端需要知道这养的一个文件目录并且具有读的权限来获取socket文件。所以,WSGISocketPrefix变量值只要设置一个具有读写权限的任意目录就可以了。

详细的英文解释:mod_wsgi ConfigurationIssues

mod_wsgi模块部署django应用

官方文档说的非常清楚,别忘了WSGIPythonPath变量即可(嵌入模式与守护进程配置不一样)。
官方文档传送门