这么多年过去了,当年文章中所描述的一些问题还有小部分仍然存在,不过自从
django有了骚浪贱的gunicorn加WhiteNoise组合,这些问题都不叫事儿了。时代的发展速度真的很快……
最近忙着把项目从Windows+XAMPP移植到Ubuntu,经历和解决了若干问题,由于大多数问题多数时间我们都会碰到,于是整理了这篇文章,希望能帮到遇到此类问题的朋友。
安装PostgreSQL
这里需要注意的是,用apt-get安装之后,需要做一系列设置:
设定postgres用户密码
1 | sudo -u postgres psql |
PostgreSQL会默认在系统中创建一个postgres用户作为数据库管理员,上面命令就是用postgres用户身份执行psql
进入之后,输入ALTER USER postgres WITH PASSWORD 'postgres';为数据库postgres用户设定密码,结束后输入\q退出psql
然后用下面命令清除系统中postgres用户的默认随机密码并重新指定密码
1 | sudo passwd -d postgres |
这里容易弄混的地方是,数据库和系统中都各存在一个postgres用户,这两个用户不是一回事。
修改 PostgreSQL 默认配置
编辑/etc/postgresql/9.1/main/postgresql.conf,这是配置的主文件,如果你的数据库和应用在不同的服务器,那么要设定数据库服务器对外可以被访问:
将listen_addresses = 'localhost'修改为listen_addresses = '*'
编辑/etc/postgresql/9.1/main/pg_hba.conf,这个文件用来定义可以访问的用户网络地址段,一般做如下修改:
将第一行local all postgres peer修改为local all postgres trust,不然你无法用postgres登录
然后将host all all 127.0.0.1/32 md5修改为host all all 127.0.0.1/32 trust
创建工作用户work
1 | psql -U postgres -h 127.0.0.1 |
1 | create user "work" with password "123456" nocreatedb; |
注意这里用的都是双引号,以区分大小写。
以后就可以为这个用户创建数据库进行工作了:
1 | create database "testdb" with owner="work"; |
安装pgadmin3
1 | sudo apt-get install pgadmin3 |
使用psql恢复从前pg_dump备份的数据库
先用pagadmin创建一个新的数据库,所有者选择刚才创建的用户work,模板使用template0,然后用下面命令进行恢复:
1 | psql -h localhost -U work -d restored < db.backup |
这里要注意,日后django设定中的user必须是这里-U参数指定的用来恢复数据的用户(也就是之前的work),同时该用户也必须是数据库的所有者,不然django运行起来会没有权限访问数据表。这里用postgres用户也行,不过日后需要手动修改所有数据表的所有者,比较麻烦。
apache及mod_wsgi相关设定
同样,使用apt-get安装apache和mod_wsgi后同样需要做一系列设置:
配置apache主设置文件
在ubuntu中,apache 2.4.6的配置文件结构有所变化,并不以httpd.conf来进行设置,其全局设置保存在/etc/apache2/apache2.conf中,此文件按照说明进行修改即可。
需要注意一点,根目录的权限需要进行设置:
1 | Options Indexes FollowSymLinks |
修改为
1 | Options FollowSymLinks |
使根目录具有访问权限,否则之后django将无法被访问,即使单独定义了VirtualHost的DocumentRoot权限也不行。
紧接着,把下面关于/srv/目录的注释去掉,启用/srv/目录配置,在正式部署的时候django project会放到这个目录中。
修改envvars
因为默认编码设置的问题,很有可能在apache/django的文件上传功能被执行时,无法转换non-ascii编码的文件名,导致上传失败,所以要在/etc/apache2/envvars中进行如下修改,将
1 | ## The locale used by some modules like mod_dav |
中的LANG定义注释掉,添加新的定义,上面几行修改为下面的样子
1 | ## The locale used by some modules like mod_dav |
或者在控制台中使用echo $LANG查看当前语言编码,并将返回的值原样替换上面的zh_CN.UTF-8,只要保证结尾的编码方式(这里是UTF-8)与你的django/pyhon设定的编码三者相同即可,对于中文用户,推荐上面的设定,你就不要改了。
在envvars文件中还能看到如下两行:
1 | export APACHE_RUN_USER=www-data |
这里定义的是apache默认运行的用户及组,记下来后面还要用到。
修改虚拟机设定
在ubuntu的apache版本中,不同的虚拟机被单独定义在不同的conf文件中,并由apache2.conf统一聚合,在/etc/apache2目录中,sites-available中存放着每个虚拟机的实际设定文件,sites-enabled中保存sites-available中部分conf的link,这就是说,真正需要修改的是sites-available目录中的文件。
进入sites-available目录,默认可以看到000-default.conf,这是安装时生成的默认配置文件,里面的初始信息非常简单,如果你的默认虚拟机也需要使用来挂载其他应用的话,可以在这个文件当中进行设置,这里我们不动。
还是在sites-available目录中,这次我们新建一个承载django运行wsgi,并服务静态文件的虚拟机:
1 | touch django.conf |
用文本编辑器(nano比较方便)编辑这个文件:
以我的项目为例,django.conf全文是这样的:
1 | ServerAdmin monoyo@gmail.com |
将上面所有/srv/drms/替换为你的django项目的project目录(就是含有manage.py的目录),将/srv/drms/drms/替换为你的默认app目录(含有wsgi.py的目录)。注意/drms和/drms/drms的区别,前一个指project,后一个指app.
注意WSGIDaemonProcess这一行的定义至关重要,在/etc/apache2/envvars中定义的用户和组(www-data)就需要用在这里,这一行的意思是,使用daemon方式执行wsgi,因为wsgi定义在virtualhost中,必须使用daemon方式,其次运行wsgi的用户名/组为www-data。经常有人遇到django wsgi不运行、目录无法访问、文件上传没权限等问题都是因为这里。
注意WSGIScriptAlias定义的内容,这是用户的访问路径,比如在这里我的定义的意思,就是告诉apache,用户会通过http://www.example.com/drms这种路径(域名无关)来访问WSGI,所以,如果你同时定义了/var/www或者相同主机中的其他对外公开的访问路径,必须保证其他地方没有目录使用相同的访问路径,意思就是说如果/var/www是根目录,里面恰好也有个drms,那么访问http://www.example.com/drms就冲突了,则这里的WSGI就不会被运行,只会静态访问/var/www/drms/
注意别名/drms_static/和目录/var/www/drms_static/的定义,这一部分就是设置使用一个VirtualHost同时承载WSGI和静态文件,虽然django官方推荐使用不同的服务器承载静态文件,比如lighttpd/nginx,不过对于小项目来说,一个apache就足够了。 将你的django项目的静态文件cp到这个目录里面吧,同时留意一下这里的设置,在随后的django配置章节中,我会分享一个小技巧,利用DEBUG开关切换开发时的static目录与部署后的static目录。
其他的行应该不用解释,大致都能看懂吧,按照你的路径修改。
修改完毕django.conf后,使用apache提供的快捷程序a2ensite直接将django.conf链接到sites-enabled目录中:
1 | sudo a2ensite django.conf |
如果提示找不到a2ensite命令,就find一下:
1 | sudo find / -name a2ensite |
这个命令的作用,其实就是帮你把sites-available/django.conf链接到sites-enabled/django.conf
顺便检查一下sites-enabled/里面有没有000-default.conf,如果有就表示000-default.conf这个虚拟主机也启用了。
普遍一提,撤销某个虚拟机挂载非常简单,只需要删除sites-enabled/里面对应的conf,然后sudo service apache2 reload就搞定。
在文件系统中修改相应目录的权限
有几个目录的权限需要修改,虽然在VirtualHost中定义了部分目录的权限,但那只是定义了apache为访问者设定的权限,和文件系统权限是两回事。
1 | chmod 755 -R /var/www/drms_static/ |
上面设定了静态文件目录以及内容的权限为755(就是普通权限),避免无法读取的情况出现。
1 | chgrp -R www-data /var/www/drms_static/uploads/ |
上面两行是将uploads及内容的所有者组循环修改为www-data,并加上写权限,因为我的django设定中将uploads指定为ckeditor和FileUpload上传文件的地方,没有上面两句,会遇到OS Permission Denied这类问题。同时chgrp命令中的www-data、apache WSGI的执行用户组(django.conf)、apache envvars里面的用户组这三个地方要保持一致。
需要说明一下,不管是开发时还是部署时,我们都使用apache提供静态文件访问服务,不使用开发服务器的静态文件管理功能,这样可以最大限度的避免django项目设定内容的混乱,可以更方便的从开发模式进入部署模式。
到这里,PostgreSQL/Apache/mod_wsgi/django相关的操作就进行完毕了,紧接着我们开始修改django的设置文件以匹配上面全新的开发、运行环境。
django相关设定
留心的朋友应该能在前两节的设定中看出来,我的django project目录在/home/william/Projects/python/2.7/drms/,因为是从windows平台迁移过来,并且启用WSGI,所以要对settings.py进行一些修改,同时也有一些设定的小技巧与大家分享。
例如我的项目,编辑/home/william/Projects/python2.7/drms/drms/settings.py,将DATABASES['default']['ENGINE']设置为django.db.backends.postgresql_psycopg2,注意DATABASES['default']['HOST']的设定与windows平台可以不同了,这里填写localhost或ip地址或域名,则通过TCP方式与PostgreSQL建立连接,在Linux中,这里还可以留空,则通过unix sockets建立连接。当然,如果数据库在不同的服务器上,还是TCP方式方便一些。
如果你的本机只有一个ip,可以使用下面的设定自动匹配地址:
1 | LOCAL_IP = socket.gethostbyname(socket.gethostname()) |
这里利用了DEBUG开关,切换是runserver还是apache wsgi.
如果发现静态文件无法访问,说明你的/etc/hosts对ip映射做了修改,或者系统有两个以上ip地址。
那么只有手动指定网址了。对于本机开发,可以将LOCAL_IP直接设定为localhost,在ubuntu中,/etc/hosts会定义一个127.0.1.1这样一个本地环回,用gethostbyname()可能会读取到这个地址,如果apache中没有指定访问这个ip,则有可能读取不出静态文件。
注意开发模式时候的:8000,这里假定我们采用默认运行方式,就是直接manage.py runserver不给定端口号,那么默认运行的就是8000端口。
接下来的两行指定静态文件路径:
1 | STATIC_ROOT = '/var/www/drms_static/' |
就像上面提到的,不管开发还是部署,我们都用apache对静态文件提供访问服务。
以上就是需要注意的地方,其他settings超出了本文范围,就不逐一介绍了。
其他注意事项
对于开发模式与部署模式之间的切换需要注意一点,开发模式的目录在/home/william/Projects/python/2.7/drms,而部署的时候,我们需要把drms project目录拷贝到/srv/中,不推荐用链接将drms ln到/srv/,不管apache是否启用FollowSymLink选项,本身django+wsgi的组合牵扯的东西就太多,光文件访问权限的嵌套问题就不容易解决。