您的位置:首页 > 运维架构 > Nginx

Django: 之Apache、Nginx部署以及发送邮件

2016-03-17 22:23 696 查看
在这里讲述部署的方法和常见的问题,并给出了在BAE,JAE,SAE等上面部署的实例。

Django + nginx + Gunicorn/uwsgi部署方式,参见另一篇:Django部署(nginx)

如果是自己的服务器(比如阿里云的或者自己搭建的虚拟机)请看下文:

如果你是新手,个人推荐你用Ubuntu,除非你对Linux非常熟悉,Ubuntu服务器的优点:

一、开机apache2等都自动启动,不需要额外设置

二、安装软件非常方便apt-get搞定

三、安装ssh,git等也非常容易,几乎是傻瓜化

可以先用用Linux Mint,它用起来更简单,和ubuntu兼容。

下面是Ubuntu上部署详细步骤:

1、安装apache2和mod_wsgi

wulaoer@wulaoer:~$sudo apt-get install apache2

# Python 2
wulaoer@wulaoer:~$ sudo apt-get install libapache2-mod-wsgi

# Python 3
wulaoer@wulaoer:~$sudo apt-get install libapache2-mod-wsgi-py3


2、确认安装的apache2版本号

wulaoer@wulaoer:~$ apache2 -v
Server version: Apache/2.4.12 (Ubuntu)
Server built:   Jul 24 2015 15:59:00


3、准备一个新网站

wulaoer@wulaoer:~$ sudo vi /etc/apache2/sites-available/sitename.conf
sudo: 无法解析主机:wulaoer
<VirtualHost *:80>
ServerName www.yourdomain.com
ServerAlias otherdomain.com
ServerAdmin wulaoer@163.com

Alias /media/ /home/tu/blog/media/
Alias /static/ /home/tu/blog/static/

<Directory /home/tu/blog/media>
Order deny,allow

Allow from all
</Directory>

<Directory /home/tu/blog/static>
Require all granted
</Directory>

WSGIScriptAlias / /home/tu/blog/blog/wsgi.py
# WSGIDaemonProcess ziqiangxuetang.com python-path=/home/tu/blog:/home/tu/.virtualenvs/blog/lib/python2.7/site-packages
# WSGIProcessGroup ziqiangxuetang.com

<Directory /home/tu/blog/blog>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
</VirtualHost>


如果你的apache的版本号是 2.2.x

用下面的代替 Require all granted

Order deny,allow
Allow from all


备注:把上面配置的文件中这两句的备注去掉,可以使用virtualenv来部署网站,当然也可以只写一个/home/tu/blog

# WSGIDaemonProcess ziqiangxuetang.com python-path=/home/tu/blog:/home/tu/.virtualenvs/blog/lib/python2.7/site-packages
# WSGIProcessGroup ziqiangxuetang.com


4、修改wsgi.py文件

注意:上面如果写了WSGIDaemonProcess 的话,这一步可以跳过,即可以不修改 wsgi.py 文件。 

上面的配置中写的WSGIScriptAlias / /home/tu/blog/blog/wsgi.py

就是把apache2和你的网站project联系起来了

import os
from os.path import join,dirname,abspath

PROJECT_DIR = dirname(dirname(abspath(__file__)))#3
import sys # 4
sys.path.insert(0,PROJECT_DIR) # 5

os.environ["DJANGO_SETTINGS_MODULE"] = "blog.settings" # 7

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()


第3、4、5行为新加内容,作用是让脚本找到django项目的位置,也可以在sitename.conf中做,用WSGIPythonPath,想连接的自行搜索,第7行如果一台服务器有多个django project时一定要修改成上面那样,否则访问的时候会发生网站互相串的情况,即访问A网站到了B网站,一会正常,一会不正常(当然可以使用mod_wsgi daemon模式,点击这里

5、设置目录和文件权限

一般目录权限设置为755,文件权限设置为644

假如项目位置在/home/tu/wulaoer(在wulaoer下面有一个manage.py,wulaoer是项目名称)

cd /home/tu/
sudo chmod -R 644 wulaoer
sudo find wulaoer -type d -exec chmod 755 \{\} \;


上传文件夹权限

media文件夹一般用来存放用户上传文件,static一般用来放自己网站的js,css,图片等,在settings.py中的相关设置

STATIC_URL为静态文件的网址STATIC_ROOT为静态文件的根目录,

MEDIA_URL为用户上传文件夹的根目录,MEDIA_URL为对应的访问网址

在settings.py中设置:

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/dev/howto/static-files/ STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR,'static')

# upload folder
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')


在Linux服务器上,用户上传目录还要设置给www-data用户的写权限,下面的方法比较好,不影响原来的用户编辑。

假如上传目录为wulaoer/media/uploads文件夹,进入media文件夹,将uploads用户组改为www-data,并且赋予改组写权限:

cd media/ # 进入media文件夹
sudo chgrp -R www-data uploads
sudo chmod -R g+w uploads


备注:这两条命令,比直接用sudo chown -R www-data:www-data uploads好,因为下面的命令不影响文件原来所属用户编辑文件,fedora系统应该不用设置上面的权限,但是个人强烈推荐用ubuntu,除非你对linux非常熟悉,你自己可以选择。

如果你是一段氏sqlite3数据库,还会提示Attempt to write a readonly database,同样要给www-data写数据库的权限

进入项目目录的上一级,比如project目录为/home/tu/wulaoer哪就进入/home/tu执行下面的命令(和修改上传文件类似)

sudo chgrp www-data blog
sudo chmod g+w blog
sudo chgrp www-data blog/db.sqlite3  # 更改为你的数据库名称
sudo chmod g+w blog/db.sqlite3


备注:上面的不要加-R,-R是更改包括所有的子文件夹和文件,这样不安全。个人建议可以专门弄一个文件夹,用它来放sqlite3数据库,给该文件夹www-data写权限,而不是整个项目给写权限,有些文件只要读懂权限就够了,给写权限会造成不安全。

6、激活新网站

sudo a2ensite sitename 或 sudo a2ensite sitename.conf


如果顺利,这样网站就搭建成功了,访问你的网址试试看,如果发现问题就接着看下面的。

7、错误排查

一、没有静态文件,网站打开很乱,没有布局,多半是静态文件没有生效。

1、确保你的配置文件中的路径是正确的

2、确保你的settings.py中的文件设置正确

3、收集静态文件

python manage.py collectstatic


二、网站打开后报错

这时你可以把settings.py更改

DEBUG = True


重启服务器

sudo service apache2 restart


再访问网站来查看具体的出错信息。

如果这样做还看不到出错信息,只是显示一个服务器错误,你可以查看apache2的错误日志

cat /var/log/apache2/error.log


根据错误日志里面的内容进行修改!

总结:

部署时文件对应关系:

sitename.conf ---> wsgi.py---> settings.py----> urls.py ----> views.py


扩展

明白了上面的关系,一个Django project使用多个域名或让app使用子域名很简单,只要新建wsgi.py文件,更改里面对应的settings文件,新的settings文件可以对应新的urls.py,从而做到访问与原来不同的地址!

Django 部署(Nginx)

1、运行开发服务器测试

cd wulaoer # 进入项目 wulaoer 目录
python manage.py runserver


2、安装nginx和需要的包

2.1 安装nginx等软件

ubuntu/Linux Mint等,下面简写为(ubuntu):

sudo apt-get install python-dev nginx


centos/Fedora/redhat等,下面简写为(centos)

sudo yum install epel-release
sudo yum install python-devel nginx


2.2安装supervisor,一个专门用来管理进程的工具,我们用它来管理gunicorn/uwsgi

sudo pip install supervisor


Ubuntu用户,请直接看3,一下是Centos注意事项:

Centos下,如果不是非常懂SELinux和iptables的话,为了方便调试,可以先临时关闭它们,如果发现部署了之后出不来结果,可以临时关闭测试一下,这样就知道是不是SELinux和iptables的问题

CentOS 7 iptables如何使用http://stackoverflow.com/questions/24756240/

将SELinux设置为宽容模式,方便调试:

sudo setenforce 0


防火墙相关的设置:

可以选择临时关闭防火墙
sudo service iptables stop

或者开放一些需要的端口,比如 80
sudo iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT


上面的两条命令,如果是Centos 7 用

临时关闭防火墙
sudo systemctl stop firewalld

或者 开放需要的端口
sudo firewall-cmd --zone=public --add-port=80/tcp --permanent
sudo firewall-cmd --reload


备注:由于我们还没有用最新版的Fedora, 新版Fedora需要用dnf来安装包,需求的同学自测,可以参考这里

3、使用gunicorn/uwsgi来部署(二选一)

注意:以下为二选一,不需要两个都用

3.1使用gunicorn(纯Python实现的包):

sudo pip install gunicorn


在项目目录下运行下面的命令进行测试:

gunicorn -w4 -b0.0.0.0:8001 wulaoer.wsgi


-w表示开启多少个worker,-b表示要使用的ip和port,我们这里用的是8001,0.0.0.0代表监控电脑的所有ip。

如果使用了virtualenv可以这样

/path/to/env/bin/gunicorn --chdir /path/to/project --pythonpath /path/to/env/ -w4 -b0.0.0.0:8017 project.wsgi:application


用--pythonpath指定依赖包路径,多个点时候用逗号,隔开,如:'/path/to/lib,/home/tu/lib'

3.2使用uwsgi(纯C 语音实现的包):

安装uwsgi

sudo pip install uwsgi


使用uwsgi运行项目

uwsgi --http :8001 --chdir /path/to/project --home=/path/to/env --module project.wsgi


这样就可以跑了, --home指定virtualenv路径,如果没有可以去掉。project.wsgi指project/wsgi.py文件

如果端口提示已经被占用:

probably another instance of uWSGI is running on the same address (:8002).
bind(): Address already in use [core/socket.c line 764]


这时可用把相关的进程kill掉:

按照端口进行查询:

lsof -i :8002


可用查出:

COMMAND  PID USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
uwsgi   2208   tu    4u  IPv4 0x53492abadb5c9659      0t0  TCP *:teradataordbms (LISTEN)
uwsgi   2209   tu    4u  IPv4 0x53492abadb5c9659      0t0  TCP *:teradataordbms (LISTEN)


这时根据PID可以用下面的命令kill掉相关的程序:

sudo kill -9 2208 2209


按照程序名称查询:

ps aux | grep uwsgi


4、使用supervisor来管理进程

安装supervisor软件包

(sudo) pip install supervisor


生成supervisor默认配置文件,比如我们放在/etc/supervisord.conf路径中:

(sudo) echo_supervisord_conf > /etc/supervisord.conf


打开supervisor.conf在最底部添加(每行前面不要有空格,防止报错):

[program:wulaoer]
command=/path/to/uwsgi --http :8003 --chdir /path/to/wulaoer --module wulaoer.wsgi
directory=/path/to/wulaoer
startsecs=0
stopwaitsecs=0
autostart=true
autorestart=true


command中写上对应的命令,这样,就可以用supervisor来管理来。

启动supervisor

(sudo) supervisord -c /etc/supervisord.conf


重启wulaoer程序(项目):

(sudo) supervisorctl -c /etc/supervisord.conf restart wulaoer


启动,停止,或重启supervisor管理的某个程序或所有程序:

(sudo) supervisorctl -c /etc/supervisord.conf [start|stop|restart] [program-name|all]


以uwsgi为例,上面这样使用一行命令太长了,我们是一ini配置文件来搞定,比如项目在/home/tu/wulaoer这个位置。

在其中新建一个uwsgi.ini全路径为/home/tu/wulaoer/uwsgi.ini

[uwsgi]
socket = /tmp/wulaoer.sock
chdir=/home/tu/wulaoer
wsgi-file = zqxt/wsgi.py
touch-reload=/home/tu/wulaoer/reload

processes = 2
threads = 4

chmod-socket = 664
chown-socket=tu:www-data


注意上面的/tmp/wulaoer.sock,一会我们把它和nginx关联起来。

在项目上新建一个空白的reload文件,只要touch一下这个文件(touch reload)项目就会重启。

修改supervisor配置文件中的command一行:

[program:wulaoer]
command=/path/to/uwsgi --ini /home/tu/wulaoer/uwsgi.ini
directory=/path/to/wulaoer
startsecs=0


然后重启一下supervisor:

(sudo) supervisorctl -c /etc/supervisord.conf restart wulaoer或者
(sudo) supervisorctl -c /etc/supervisord.conf restart all


5、配置nginx

新建一个网站wulaoer

sudo vim /etc/nginx/sites-available/wulaoer.conf


写入一下内容

server {
listen      80;
server_name www.wulaoer.org;
charset     utf-8;

client_max_body_size 75M;

location /media  {
alias /path/to/project/media;
}

location /static {
alias /path/to/project/static;
}

location / {
uwsgi_pass  unix:///tmp/wulaoer..sock;
include     /etc/nginx/uwsgi_params;
}
}


激活网站:

sudo ln -s /etc/nginx/sites-available/zqxt.conf /etc/nginx/sites-enabled/wulaoer.conf


测试配置语法问题

sudo service nginx configtest


重启nginx服务器:

sudo service nginx reload 或者 sudo service nginx restart


一些有用的参考教程:

Django 官网部署教程:

https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/gunicorn/

https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/uwsgi/

一些博客相关教程:

http://www.ituring.com.cn/article/201045

http://www.jianshu.com/p/be9dd421fb8d

http://blog.csdn.net/tengzhaorong/article/details/12833157

nginx 与 socket

http://uwsgi-docs.readthedocs.org/en/latest/tutorials/Django_and_nginx.html#configure-nginx-for-your-site

防火墙:

iptables: https://www.digitalocean.com/community/tutorials/how-to-setup-a-basic-ip-tables-configuration-on-centos-6

centos 7 FireWalld: http://stackoverflow.com/questions/24756240/how-can-i-use-iptables-on-centos-7

ubuntu ufw 防火墙:http://wiki.ubuntu.org.cn/Ufw%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97

uwsgi ini 配置文件:http://uwsgi-docs.readthedocs.org/en/latest/tutorials/Django_and_nginx.html#configuring-uwsgi-to-run-with-a-ini-file

Django 发送邮件

我们常常会用到一些发送邮件的功能,比如有人提交了应聘的表单,可以向HR的邮箱发送邮件,这样HR不看网站就可以知道有人在网站上提交了应聘信息。

1、配置相关参数

如果用的是阿里云的企业邮箱,则类似于下面:

在settings.py的最后面加上这些

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

EMAIL_USE_TLS = False
EMAIL_HOST = 'smtp.wulaoer.org'
EMAIL_PORT = 25
EMAIL_HOST_USER = 'mail@wulaoer.org'
EMAIL_HOST_PASSWORD = 'xxxx'
DEFAULT_FROM_EMAIL = 'mail@wulaoer.org'


DEFAULT_FROM_EMAIL 还可以写成这样:

DEFAULT_FROM_EMAIL = 'wulaoer <wulaoer@163.com>'


这样别人收到的邮件就会有你设定的名称,如下:

发件人:wulaoer <wulaoer@163.com>


下面是一些常用的邮箱:

163邮箱  126邮箱  QQ邮箱

其他邮箱参数可能登陆邮箱看帮助信息,也可以尝试在搜索引擎中搜索:“SMTP 邮箱名称”,比如:“163 SMTP” 进行查找。

2、发送邮件

2.1官网的一个例子:

from django.core.mail import send_mail

send_mail('Subject here', 'Here is the message.', 'from@example.com',
['to@example.com'], fail_silently=False)


2.2 一次性发送多个邮件:

from django.core.mail import send_mass_mail

message1 = ('Subject here', 'Here is the message', 'from@example.com', ['first@example.com', 'other@example.com'])
message2 = ('Another Subject', 'Here is another message', 'from@example.com', ['second@test.com'])


备注:send_mail每次发送邮件都会建立一个连接,发送多封邮件时建立多个连接。而send_mass_mail是建立单个连接发送多封邮件,所以一次性发送多封邮件时send_mass_mail要优与send_mail。

2.3 如果我们想在邮件中添加附件,发送html格式的内容

from django.conf import settings
from django.core.mail import EmailMultiAlternatives

from_email = settings.DEFAULT_FROM_EMAIL
# subject 主题 content 内容 to_addr 是一个列表,发送给哪些人
msg = EmailMultiAlternatives(subject, content, from_email, [to_addr])

msg.content_subtype = "html"

# 添加附件(可选)
msg.attach_file('./twz.pdf')

# 发送
msg.send()


上面的做法可能有一些风险,除非你确定你的接收者都可以阅读html格式的邮件。

为了安全起见,你可以弄两个版本,一个纯文本(text/plain)的为默认的,另外在提供一个html版本的(好像好多国外发送的邮件都是纯文本的)

from __future__ import unicode_literals

from django.conf import settings
from django.core.mail import EmailMultiAlternatives

subject = '来自吴老二的问候'

text_content = '这是一封重要的邮件.'

html_content = '<p>这是一封<strong>重要的</strong>邮件.</p>'

msg = EmailMultiAlternatives(subject, text_content, from_email, [to@youemail.com])

msg.attach_alternative(html_content, "text/html")

msg.send()


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: