centos下apache+django配置多个网站

之前就已经写过一篇《在linux服务器上部署django项目》,在那篇博文里,我用的操作系统是ubuntu的,而且没有配置域名,直接在一台服务器下放的一个网站,而且用的是mod_wsgi的全局模式。今天的这篇,我将使用mod_wsgi的daemon mode,而且配置多个网站–一个域名对应多个网站。

我的环境:

centos6.7
Apache/2.2.15
python2.7.12
django1.9.7
mod_wsgi4.5.3

本文的前提是环境已经配好了,如果没有配好,可以参考《在linux服务器上部署django项目》。

接下来,以2个django项目,1个php项目为例,进行网站的配置。

2个django项目的地址:

/mywebsite/django1
/mywebsite/django2

php项目的地址

/mywebsite/myphp

使用mod_wsgi的daemon mode

这个例子,我们将第一个django项目配置到服务器上,使用mod_wsgidaemon mode

对应的httpd.conf文件应该这么写:

<VirtualHost *:80>
     ServerName lookfor404.com           # 域名 
     WSGIDaemonProcess django1 python-path=/mywebsite/django1
     WSGIProcessGroup django1
     WSGIScriptAlias / /mywebsite/django1/yourproject/wsgi.py   #在 /mywebsite/django1 下,project和app在同一级目录
    <Directory /mywebsite/django1/yourproject>
       <Files wsgi.py>
          Order Deny,Allow
          Allow from All
       </Files>
    </Directory>

   #别忘了静态文件配置,这个和一般的php项目是类似的
    Alias /static "/your/path/collectedstatic"
    <Directory "/your/path/collectedstatic">
        Order deny,allow
        Allow from all
    </Directory>
</VirtualHost>

但是据测试,有时候可能会出现错误,在log里面提示如下:

Permission denied: mod_wsgi (pid=10458): Unable to connect to WSGI daemon process ‘lookfor404’ on ‘/etc/httpd/logs/wsgi.10453.0.1.sock’ as user with uid=11.

逛了半天的stackoverflow,最终看到一个靠谱的答案提到这个网址,
https://code.google.com/archive/p/modwsgi/wikis/ConfigurationIssues.wiki#Location_Of_UNIX_Sockets

解决方法就是,在virtualhost外面加多一句
WSGISocketPrefix /var/run/wsgi

一个域名对应多个网站

接下来,看看怎么用一个域名配置多个网站。

比如,我想要的效果是这样的:访问lookfor404.com/django1,进入django1这个项目;访问lookfor404.com/django2,进入django2这个项目;访问lookfor404.com/myphp,进入myphp这个项目。同样的,直接看配置文件。为了看起来清楚,我把静态文件设置先忽略了。

#----------django1项目配置
<VirtualHost *:80>
     ServerName lookfor404.com           # 域名 
     WSGIDaemonProcess django1 python-path=/mywebsite/django1
     WSGIProcessGroup django1
     #注意,以下发生变化,即第二个参数为访问的路径
     WSGIScriptAlias /django1 /mywebsite/django1/yourproject/wsgi.py   
    <Directory /mywebsite/django1/yourproject>
       <Files wsgi.py>
          Order Deny,Allow
          Allow from All
       </Files>
    </Directory>
</VirtualHost>

#----------django2项目配置
<VirtualHost *:80>
     ServerName lookfor404.com           # 域名 
     WSGIDaemonProcess django2 python-path=/mywebsite/django2
     WSGIProcessGroup django2
     #如下,即访问url为lookfor404.com/django2
     WSGIScriptAlias /django2 /mywebsite/django2/yourproject/wsgi.py   
    <Directory /mywebsite/django2/yourproject>
       <Files wsgi.py>
          Order Deny,Allow
          Allow from All
       </Files>
    </Directory>
</VirtualHost>

#----------myphp项目配置
<VirtualHost *:80>
     ServerName lookfor404.com   # 域名 
     DocumentRoot /mywebsite/myphp
     <IfModule alias_module>
          #设置访问url为lookfor404.com/myphp
          Alias /myphp "/mywebsite/myphp"
         <Directory "/mywebsite/myphp">
          AllowOverride all
          Order allow,deny
          Allow from all
         </Directory>
      </IfModule>
</VirtualHost>

总结来说,这种配置适用于你只有一个域名,而你有多个网站程序,而且你不使用子域名。对于django项目,通过WSGIScriptAlias的第一个参数就可以设定访问的域名子路径了,对于php项目,使用Alias即可解决问题。

另外,多个域名多个网站这种情况就不说了,直接在servername里设置就行。

django项目出现WSGI Bad Bad Request (400) 错误

最后还要说一下这个错误,明明之前一切配置都顺利,用ip访问也没问题,但是一用域名访问就出错了,原来是新版django的问题,需要到setting.py里面设置可访问的域名:

ALLOWED_HOSTS = [
‘lookfor404.com’, # 只允许主域名
‘.lookfor404.com’, # 允许主域名以及子域名
‘.lookfor404.com.’, # 允许FQDN以及子域名
]

然后重启一下apache就行了。

 

折腾记录:将wordpress搬家到腾讯云

由于腾讯云有学生计划,每个月可以有50块的代金券,于是我就愉快地用上了腾讯云的服务器。本来迁移一个wordpress应该是很简单的事情,居然被我折腾了一天!!!整整一天!!所以,还是记录一下吧。

想象中的迁移其实相当简单啊,由于先前已经把apache、php模块、mysql都装好了,只要把数据库和网站文件复制过来,然后改一下wp-config.php就行啦。但没想到的是,由于版本的不一致和权限的问题,我踩了不少坑。

第一坑:mysql版本不一致

在腾讯云,我的系统是centos6.7,mysql是通过yum安装的,看看版本:

rpm -qa | grep mysql

mysql版本

5.1版本的,而我在另外在另外一台服务器上面的mysql是5.6版本的,所以,当我想愉快的用navicat-for-mysql来进行数据传输的时候,出现了编码错误,无法传输。高版本的mysql有这样的排序规则:utf8mb4_unicode_ci,低版本的没有。

所以,我只能去踩第二个坑了。

第二坑:不能直接把数据库搬过来

踩完第一坑,想着说,既然不能这么传输数据库,那我就直接导出sql,然后在新的数据库执行就好了。

导出、导入完毕,然后上传wordpress文件到服务器,更改wp-config.php中的数据库配置。然后配置虚拟主机,重启apache,一切正常。

浏览器输入ip来访问。居然重定向到apache的默认页面去了。很明显,数据库根本连接不了。。

最后的解决方法是,老老实实的,先不导入数据库,让wordpress自己完成安装,把默认的表都建齐了,然后把默认的数据给删掉,最后把之前导出的sql文件里的insert语句重新执行一遍,相当于重新写数据了。

第三坑:固定链接与.htaccess文件

网站的url设计用的是域名+文章名,这个可以在wordpress后台的“固定链接”里面设置。但是我设置了之后,发现居然只有“朴素”模式可以用,采用别的固定链接,都会404。

搜索引擎和wordpress都告诉我,是.htaccess文件的问题。

wordpress的.htaccess文件

于是我在网站根目录下新建了一个.htaccess文件,把它告诉我要填写的内容写进去了,保存。

vim .htaccess

RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ – [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

然后,在apache的virtual host配置里,加了以下设置,使.htaccess生效:

<Directory “/mypath/wordpress”>
AllowOverride ALL
Order allow,deny
Allow from all
</Directory>

其中,AllowOverride ALL是一定要加的,这个代表使用.htaccess的策略。

但是,问题出现了,加了这个配置之后,图片、css、js等静态文件访问不了了。

经过好久好久的测试,千言万语可以通过以下一行命令解决:

将路径先切换到wordpress网站根目录,然后

chown -R apache:apache ./*

把所有文件的拥有者改成apache,把所属的组改成apache,这样apache就有权限了。这也直接能解决第四个坑

第四坑:在线更新wordpress出错

无论是升级wordpress还是升级插件,总是会出现权限错误,都不成功。

都是权限不足!如果你够暴力,直接全部777权限,解决,但不建议这么做。我最终还是选择了把网站的owner和group都改成了apache,正如坑三所提到的那样。

总结

权限问题!权限问题!权限问题!

这个问题在我配置网站的时候经常有,次次有,所以一定要把系统的各种权限搞懂,不要每次都用root去倒腾一些东西,得不偿失!要建立起良好的权限管理的习惯。

这篇写的思路比较混乱,之后再把之前配置整个服务器的过程记录一下。

运行ggplot出现问题:no display name and no $DISPLAY environment variable

最近在用django做一个项目,关于数据可视化的。作图方面,之前用过百度的echart,这个是在前端直接调用的,这次想尝试在后台直接生成图,然后存在服务器上,之后前端再把图片显示出来就好了。

用的ggplot。

在windows下,用runserver测试,没问题。但是在服务器上,就跑不了了,出现了这样的提示:

tkinter.TclError: no display name and no $DISPLAY environment variable

查看了一下debug信息,发现貌似和Matplotlib有关,继续顺藤摸瓜。

找到了问题所在:http://matplotlib.org/faq/howto_faq.html#howto-webapp

官网的英文解释:

Many users report initial problems trying to use maptlotlib in web application servers, because by default matplotlib ships configured to work with a graphical user interface which may require an X11 connection. Since many barebones application servers do not have X11 enabled, you may get errors if you don’t configure matplotlib for use in these environments. Most importantly, you need to decide what kinds of images you want to generate (PNG, PDF, SVG) and configure the appropriate default backend. For 99% of users, this will be the Agg backend, which uses the C++ antigrain rendering engine to make nice PNGs

不想读完也没关系,大概说下怎么回事。

不同的系统有不同的用户图形接口,默认的接口在windows下跑是没有问题的,问题是我们很多的webapp都不在windows上跑,一般在linux上面,所以要更改它的默认配置,把模式更改成Agg。

纯代码解决方案

这也是大部分人在网上诸如stackoverflow的问答平台得到的解决方案,在引入pyplot、pylab之前,要先更改matplotlib的后端模式为”Agg”。直接贴代码吧!

# do this before importing pylab or pyplot
Import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot asplt

更改配置文件方案

就我的情况而言,上面那种解决方案似乎不适用,因为我是在django中使用的ggplot,它调用matplotlib的时机,我并不是很清楚。所以试了几次,都没有能把matplotlib.use('Agg')这句代码放在正确的位置上,因而也解决不了错误。

所以我转向了另一种解决方案,也是从官网启发而来。

好了,这里告诉我们,什么是backend:

http://matplotlib.org/faq/usage_faq.html#what-is-a-backend

然后这里告诉我们,怎么改配置文件:

http://matplotlib.org/users/customizing.html#customizing-matplotlib

看到下面这个地方:

matplotlibrc文件

没错,它的配置文件就是matplotlibrc,在哪里呢?不同系统不一样,我的系统是ubuntu,运行了命令whereis matlotlibrc,找到了。

matplotlibrc文件位置

编辑一下:

sudo vim /etc/matplotlibrc

找到backend这里,然后将其改成Agg,如下!

# The default backend; one of GTK GTKAgg GTKCairo GTK3Agg GTK3Cairo
# CocoaAgg MacOSX Qt4Agg Qt5Agg TkAgg WX WXAgg Agg Cairo GDK PS PDF SVG
# Template.
# You can also deploy your own backend outside of matplotlib by
# referring to the module name (which must be in the PYTHONPATH) as
# ‘module://my_backend’.
backend : Agg

保存,运行,错误消失。

在linux服务器上部署django项目

不得不承认,django自带的runserver功能确实强大,使得我们在开发的过程中可以轻松的在本地调试、查看网站。但开发是开发,做的项目总归是要部署到服务器上面去的,最近把项目部署到linux上了,这里记录一下。

官方文档:https://docs.djangoproject.com/en/1.9/howto/deployment/

我是参照着文档部署的。下面是我的环境:

ubuntu14.04.3
python2.7.6
apache2.4.7
django1.9.7
mod_wsgi4.5.3

接下来进入配置环节。

安装python-dev

默认情况下,ubuntu系统是安装了python的,不过如果只用这个python,在后面的部署过程就会出问题,先查看你的python版本,不出意外的话是2.7.x,然后额外安装一个对应的dev版。

apt-get install python2.7-dev

安装django

这个很简单,直接pip安装就行,选择好你要的版本。

pip install Django==1.9.7

安装python的mysql驱动

如果你的数据库用的是mysql,还得安装这个。

sudo apt-get install python-mysqldb

安装Apache

在ubuntu系统上,Apache是预装了的,但是它不支持apxs的,对于之后要安装的wsgi组件来说,apxs是必须的。还得安装一个Apache的dev版。先确认你已经安装的Apache版本,我的是Apache2,所以直接运行以下命令继续安装dev版:

sudo apt-get install apache2-dev

安装编译mod_wsgi

有了上述的准备工作之后,安装mod_wsgi就不是什么问题了。

这个是官方文档:https://modwsgi.readthedocs.io/en/develop/user-guides/quick-installation-guide.html

我记录一下我安装编译的步骤。

先去下载源代码:https://github.com/GrahamDumpleton/mod_wsgi/releases

我下载的是mod_wsgi-4.5.3.tar.gz。

然后上传到服务器,解压:

tar xvfz mod_wsgi-X.Y.tar.gz

PS:X,Y为你实际的文件版本,跟文件名一致即可。

解压之后,cd到对应的目录。然后运行

./configure

./configure命令
然后继续运行:

make

最后运行(PS:这一步是需要管理员权限的):

sudo make install

安装成功:
mod_wsgi安装成功
注意图片的第一行,说的是mod_wsgi安装的路径;还有最后一行,要给mod_wsgi.so加上对应的权限。

sudo chmod 644 /usr/lib/apache2/modules/mod_wsgi.so

配置mod_wsgi到Apache上

安装成功之后,要更改一下Apache的配置文件。编辑(不同系统下Apache配置文件不一样,有的是httpd.conf)

sudo vim /etc/apache2/apache2.conf

在文件的最后一行,加上
LoadModule wsgi_module /usr/lib/apache2/modules/mod_wsgi.so
其中第三个参数,是刚才安装完的mod_wsgi.so对应的路径。

部署django项目

django项目刚开始的时候,我们一般都是运行startproject命令来生成项目,这样做有一个好处,django会帮我们自动生成wsgi的配置文件。

首先把本地的django项目复制到服务器上,一般是/var/www/html下,以你Apache的配置为准。

然后我们继续编辑Apache的配置文件:

sudo vim /etc/apache2/apache2.conf

在最后,添加如下内容:

WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py
WSGIPythonPath /path/to/mysite.com

Require all granted< /Files>

要注意,/path/to/mysite.com/ 这个路径不要搞错,就是你项目的路径。

配置完毕,重启Apache。

sudo apachectl restart

访问网站
直接输入ip地址访问网站,发现访问不了,查看了一下Apache的error log:

from django.core.wsgi import get_wsgi_application
ImportError: No module named ‘django.core.wsgi’

后来发现,原来是权限问题,无法执行django里面的文件。心累。。

加个权限就行了。

cd /usr/local/lib/python2.7/dist-package
sudo chmod a+x django

ok,项目就这么部署完毕了,如果你是正式的项目,记得把django的debug模式关掉。

django中的Q()函数:应用于model数据查询的与(and)或(or)操作

问题背景

之前用django的时候,数据库这一块也没有涉及到比较复杂一点的查询,一般就是一个filter()或者一个get()就搞定了,前几天做一个可视化的项目时,遇到了多条件复合查询,看了下文档,django的orm还是挺好用的,Q()函数可以解决这个问题。

比如我要查询id为1或者id为2的一个数据,在filter里面,是不能够这么直接来的:filter(id=1,id=2),只能使用Q函数。为了更深入地理解Q函数,我参考官方文档,整理一下它的用法。

文档位置:https://docs.djangoproject.com/en/1.9/topics/db/queries/#complex-lookups-with-q-objects

django中Q()函数的介绍

如果你需要进行复杂的查询(比如or条件),你可以使用Q对象。

Q对象是用来封装查询参数的,比如,它可以仅仅用来封装单独一个like查询:

from django.db.models import Q
Q(question__startswith='What')

Q函数可以通过逻辑符号连接

Q对象可以和&|这两个符号一起来使用,即and和or。下面这个例子就用or将两个查询组合在了一起:

Q(question__startswith='Who') | Q(question__startswith='What')

相当于以下sql语句:

WHERE question LIKE 'Who%' OR question LIKE 'What%'

另外,还可以使用非符号~,比如:

Q(question__startswith='Who') | ~Q(pub_date__year=2005)

Q函数用于数据库查询

以上介绍了Q的组合方法,那么怎么把它应用到数据库的查询呢?一般而言,可以把它们放到filter(),get()或者exclude()里面,比如:

Poll.objects().filter(Q(question__startswith='Who') | ~Q(pub_date__year=2005))

Q函数和关键字参数混合使用

另外,Q对象还可以和关键字参数一起使用,不过Q一定要放在前面,以下是正确例子:

Poll.objects.get(
    Q(question__startswith='Who'),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

相当于sql查询语句如下:

SELECT * from polls WHERE question LIKE 'Who%'
    AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

关键字参数放在前面是错误的用法!!如下是错误的!

# 错误用法
Poll.objects.get(
    question__startswith='Who',
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

我的实践

我喜欢这样来用Q对象。先在外面将条件组合好,然后再传入filter()get()或者exclude()里面,代码片段如下:

from django.db.models import Q
my_filter = Q()
my_filter = my_filter | Q(id=1)
my_filter = my_filter | Q(name="lipengfei")
result = People.objects.filter(my_filter)

真的是404了

deadline是最佳动力,这句话从来就没有错。

准备了一个学期的软件工程课程设计,在最后两个星期里进度突飞猛进,最终获得老师的肯定,也是不容易。

唯一让我心塞的是,答辩的早上,我猛然发现,我的文件夹中仅仅剩下测试用例,文档全部不翼而飞!不知道是前一天凌晨准备测试用例的时候误删操作还是怎么样,总而言之,文档不见了!

这是什么文档呢?还得从我的这个项目说起。

这个项目,做的是一个基于校园的买卖系统,前端用bootstrap2.0,整站用基于python的django框架。除了有点前端和后台的基础,对上面的技术路线基本没接触过。也就是从头学起了。

因而,在这个过程中,用文档记录下了开发的过程,当时还没有开博客。

到项目进行到一半的时候,我就开了这个个人博客,当时已经想着说,把这次相对来说较为完整的项目经历,记录到博客上面。于是word便成为了我的记事本。

可惜事与愿违,强行恢复也找不到这些文件了,真的是404了。

后来想想也没什么,毕竟代码是自己亲力亲为,思路是自己亲力亲为,所以这些文档的记录,根本就不会消失,他们就在我脑子里。所以,到之后有时间,我准备把这次项目的开发过程,完整的记录到博客上面,和大家一起学习。