Fork me on GitHub
Suzf  Blog

Archive Dev

How-to Deploy Django Apps with uWSGI and Nginx on Ubuntu

Django 的部署可以有很多方式,采用 nginx + uwsgi 的方式是其中比较常见的一种方式。

准备工作

安装所需软件

pip install Django
apt-get install nginx

pip install uwsgi
# 注: 在 Debian/Ubuntu 系统中需要安装 python-dev

基本测试

创建一个 test.py 的文件

# test.py
def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return [b"Hello World"] # python3
    #return ["Hello World"] # python2

运行 uWSGI

uwsgi --http :8000 --wsgi-file test.py

参数含义: http :8000: 使用http协议 8000端口 wsgi-file test.py: 加载指定文件 test.py 执行 Curl 命令在终端上返回 Hello world

$curl http://172.16.9.110:8000
Hello World

如果返回的是正确的内容,说明下面工作流程的组件是工作的:

the web client <-> uWSGI <-> Python

测试你的 Django 项目 确保你的项目是可以顺利运行的

python manage.py runserver 0.0.0.0:8000

如果没有报错,使用 uWSGI 的方式运行它

uwsgi --http :8000 --wsgi-file mysite.wsgi

通过浏览器访问正常, 说明下面工作流程的组件是工作的:

the web client <-> uWSGI <-> Django

配置 Nginx

# mysite_nginx.conf

# the upstream component nginx needs to connect to
upstream django {
    server unix:///path/to/your/mysite/mysite.sock; # for a file socket
    # server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}

# configuration of the server
server {
    # the port your site will be served on
    listen      8000;
    # the domain name it will serve for
    server_name .example.com; # substitute your machine's IP address or FQDN
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;   # adjust to taste

    # Django media
    location /media  {
        alias /path/to/your/mysite/media;  # your Django project's media files - amend as required
    }

    location /static {
        alias /path/to/your/mysite/static; # your Django project's static files - amend as required
    }

    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  django;
        include     /path/to/your/mysite/uwsgi_params; # the uwsgi_params file you installed
    }
}

Running the Django application with uswgi and nginx

如果上面一切都显示正常,则下面命令可以拉起django application

uwsgi --socket mysite.sock --wsgi-file mysite.wsgi --chmod-socket=664

Configuring uWSGI to run with a .ini file

每次都运行上面命令拉起django application实在麻烦,使用.ini文件能简化工作,方法如下: 在application目录下创建文件mysite_uwsgi.ini,填入并修改下面内容:

# mysite_uwsgi.ini file
[uwsgi]

# Django-related settings
# the base directory (full path)
chdir           = /path/to/your/project
# Django's wsgi file
module          = project.wsgi
# the virtualenv (full path)
home            = /path/to/virtualenv

# process-related settings
# master
master          = true
# maximum number of worker processes
processes       = 10
# the socket (use the full path to be safe
socket          = /path/to/your/project/mysite.sock
# ... with appropriate permissions - may be needed
# chmod-socket    = 664
# clear environment on exit
vacuum          = true

之后使用这个文件运行 uwsgi

uwsgi --ini mysite_uwsgi.ini # the --ini option is used to specify a file

Once again, test that the Django site works as expected.

参考链接

[0] http://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html

[1] http://www.jianshu.com/p/e6ff4a28ab5a

[译] Python Logging Howto

基本日志记录教程
日志是跟踪一些软件运行时发生的事件的手段。软件的开发人员添加日志调用到他们的代码中,以指示已发生的某些事件。一个事件是通过一个描述性消息可任选地含有可变数据(即是该事件的每次发生潜在不同的数据)中。事件是很重要的,开发者通常通过事件追踪问题, 重要性也可称为水平或严重程度。
什么时候使用 logging
日志提供了简单的日志使用一组方便的功能。这里有 debug()info()warning()error()critical()。要确定何时使用日志记录,请参阅下表,其中规定,对于一组常见任务,使用最好的工具。

Python 简单爬取MM照片

制作爬虫的基本步骤

  1. 需求分析
  2. 分析网站源码<F12>
  3. 编写正则表达式 过滤内容
  4. 生成代码
需求分析
有好多想要的图片,自己又懒得下载;有没有简单而有效地方法呢?

How-to deploy flask web applications use wsgi behind apache

Flask是一个使用Python编写的轻量级Web应用框架。基于Werkzeug WSGI工具箱和Jinja2 模板引擎Flask使用BSD授权。 Flask也被称为“microframework”,因为它使用简单的核心,用extension增加其他功能。Flask没有默认使用的数据库、窗体验证工具。然而,Flask保留了扩增的弹性,可以用Flask-extension加入这些功能:ORM、窗体验证工具、文件上传、各种开放式身份验证技术。 WSGI Web服务器网关接口Python Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器Web应用程序框架之间的一种简单而通用的接口。自从WSGI被开发出来以后,许多其它语言中也出现了类似接口。

Bytes-to-human and human-to-bytes converter

#!/usr/bin/env python

"""
Bytes-to-human / human-to-bytes converter.
Based on: http://goo.gl/kTQMs
Working with Python 2.x and 3.x.

Author: Giampaolo Rodola' <g.rodola [AT] gmail [DOT] com>
License: MIT
"""

# see: http://goo.gl/kTQMs
SYMBOLS = {
    'customary'     : ('B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'),
    'customary_ext' : ('byte', 'kilo', 'mega', 'giga', 'tera', 'peta', 'exa',
                       'zetta', 'iotta'),
    'iec'           : ('Bi', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'),
    'iec_ext'       : ('byte', 'kibi', 'mebi', 'gibi', 'tebi', 'pebi', 'exbi',
                       'zebi', 'yobi'),
}

def bytes2human(n, format='%(value).1f %(symbol)s', symbols='customary'):
    """
    Convert n bytes into a human readable string based on format.
    symbols can be either "customary", "customary_ext", "iec" or "iec_ext",
    see: http://goo.gl/kTQMs

      >>> bytes2human(0)
      '0.0 B'
      >>> bytes2human(0.9)
      '0.0 B'
      >>> bytes2human(1)
      '1.0 B'
      >>> bytes2human(1.9)
      '1.0 B'
      >>> bytes2human(1024)
      '1.0 K'
      >>> bytes2human(1048576)
      '1.0 M'
      >>> bytes2human(1099511627776127398123789121)
      '909.5 Y'

      >>> bytes2human(9856, symbols="customary")
      '9.6 K'
      >>> bytes2human(9856, symbols="customary_ext")
      '9.6 kilo'
      >>> bytes2human(9856, symbols="iec")
      '9.6 Ki'
      >>> bytes2human(9856, symbols="iec_ext")
      '9.6 kibi'

      >>> bytes2human(10000, "%(value).1f %(symbol)s/sec")
      '9.8 K/sec'

      >>> # precision can be adjusted by playing with %f operator
      >>> bytes2human(10000, format="%(value).5f %(symbol)s")
      '9.76562 K'
    """
    n = int(n)
    if n < 0:
        raise ValueError("n < 0")
    symbols = SYMBOLS[symbols]
    prefix = {}
    for i, s in enumerate(symbols[1:]):
        prefix[s] = 1 << (i+1)*10
    for symbol in reversed(symbols[1:]):
        if n >= prefix[symbol]:
            value = float(n) / prefix[symbol]
            return format % locals()
    return format % dict(symbol=symbols[0], value=n)

def human2bytes(s):
    """
    Attempts to guess the string format based on default symbols
    set and return the corresponding bytes as an integer.
    When unable to recognize the format ValueError is raised.

      >>> human2bytes('0 B')
      0
      >>> human2bytes('1 K')
      1024
      >>> human2bytes('1 M')
      1048576
      >>> human2bytes('1 Gi')
      1073741824
      >>> human2bytes('1 tera')
      1099511627776

      >>> human2bytes('0.5kilo')
      512
      >>> human2bytes('0.1  byte')
      0
      >>> human2bytes('1 k')  # k is an alias for K
      1024
      >>> human2bytes('12 foo')
      Traceback (most recent call last):
          ...
      ValueError: can't interpret '12 foo'
    """
    init = s
    num = ""
    while s and s[0:1].isdigit() or s[0:1] == '.':
        num += s[0]
        s = s[1:]
    num = float(num)
    letter = s.strip()
    for name, sset in SYMBOLS.items():
        if letter in sset:
            break
    else:
        if letter == 'k':
            # treat 'k' as an alias for 'K' as per: http://goo.gl/kTQMs
            sset = SYMBOLS['customary']
            letter = letter.upper()
        else:
            raise ValueError("can't interpret %r" % init)
    prefix = {sset[0]:1}
    for i, s in enumerate(sset[1:]):
        prefix[s] = 1 << (i+1)*10
    return int(num * prefix[letter])

Extra: for an alternative version as simple as possible (no global vars, no extra args, easier to customize) see here: http://code.google.com/p/pyftpdlib/source/browse/trunk/test/bench.py?spec=svn984&r=984#137

 

来自 http://code.activestate.com/recipes/578019-bytes-to-human-human-to-bytes-converter/

How-to 使用 PyCharm 运行调试/同步代码

本文介绍如何使用用 PyCharm专业版 实现运行调试/同步代码。

环境要求:

Pycharm Professional Full-featured IDE for Python & Web development

Download: Download Latest Version of PyCharm

如何设置

我们需要设置两个地方:远程服务器 & 远程解析器

设置远程服务器:Tools -> Deployment -> Configuration 打开设置界面,点击“+”号添加远程主机。

主机名称起一个好记的名字 < 这里我设置为 Happy_Code  >, 然后 Type 选择 SFTP

接下来设置用于登陆SFTP的账号信息等,也就是本地登陆远程Linux的账号信息。

 

接下来讲讲如何设置远程解析器

File -> Settings -> Project -> Project Interpreter -> Click configure button - > Add Remote

-> Click Deployment configuration -> chose Happy_code -> next

-> OK

 

密码散列安全

节选自 PHP manual

相关链接  Wooyun

本部分解释使用散列函数对密码进行安全处理背后的原因, 以及如何有效的进行密码散列处理。

  1. 为什么需要把应用程序中用户的密码进行散列化?
  2. 为何诸如 md5 和 sha1 这样的常见散列函数不适合用在密码保护场景?
  3. 如果不建议使用常用散列函数保护密码, 那么我应该如何对密码进行散列处理?
  4. “盐”是什么?
  5. 我应该如何保存“盐”?

为什么需要把应用程序中用户的密码进行散列化?

当设计一个需要接受用户密码的应用时, 对密码进行散列是最基本的,也是必需的安全考虑。 如果不对密码进行散列处理,那么一旦应用的数据库受到攻击, 那么用户的密码将被窃取。 同时,窃取者也可以使用用户账号和密码去尝试其他的应用, 如果用户没有为每个应用单独设置密码,那么将面临风险。

通过对密码进行散列处理,然后再保存到数据库中, 这样就使得攻击者无法直接获取原始密码, 同时还可以保证你的应用可以对原始密码进行相同的散列处理, 然后比对散列结果。

需要着重提醒的是,密码散列只能保护密码 不会被从数据库中直接窃取, 但是无法保证注入到应用中的 恶意代码拦截到原始密码。

为何诸如 md5()sha1() 这样的常见散列函数不适合用在密码保护场景?

MD5,SHA1 以及 SHA256 这样的散列算法是面向快速、高效 进行散列处理而设计的。随着技术进步和计算机硬件的提升, 破解者可以使用“暴力”方式来寻找散列码 所对应的原始数据。

因为现代化计算机可以快速的“反转”上述散列算法的散列值, 所以很多安全专家都强烈建议 不要在密码散列中使用这些散列算法。

如果不建议使用常用散列函数保护密码, 那么我应该如何对密码进行散列处理?

当进行密码散列处理的时候,有两个必须考虑的因素: 计算量以及“盐”。 散列算法的计算量越大, 暴力破解所需的时间就越长。

PHP 5.5 提供了 一个原生密码散列 API, 它提供一种安全的方式来完成密码 散列验证。 PHP 5.3.7 及后续版本中都提供了一个 » 纯 PHP 的兼容库

PHP 5.3 及后续版本中,还可以使用 crypt() 函数, 它支持多种散列算法。 针对每种受支持的散列算法,PHP 都提供了对应的原生实现, 所以在使用此函数的时候, 你需要保证所选的散列算法是你的系统所能够支持的。

当对密码进行散列处理的时候,建议采用 Blowfish 算法, 这是密码散列 API 的默认算法。 相比 MD5 或者 SHA1,这个算法提供了更高的计算量, 同时还有具有良好的伸缩性。

如果使用 crypt() 函数来进行密码验证, 那么你需要选择一种耗时恒定的字符串比较算法来避免时序攻击。 (译注:就是说,字符串比较所消耗的时间恒定, 不随输入数据的多少变化而变化) PHP 中的 == 和 === 操作符strcmp() 函数都不是耗时恒定的字符串比较, 但是 password_verify() 可以帮你完成这项工作。 我们鼓励你尽可能的使用 原生密码散列 API

“盐”是什么?

加解密领域中的“盐”是指在进行散列处理的过程中 加入的一些数据,用来避免从已计算的散列值表 (被称作“彩虹表”)中 对比输出数据从而获取明文密码的风险。

简单而言,“盐”就是为了提高散列值被破解的难度 而加入的少量数据。 现在有很多在线服务都能够提供 计算后的散列值以及其对应的原始输入的清单, 并且数据量极其庞大。 通过加“盐”就可以避免直接从清单中查找到对应明文的风险。

如果不提供“盐”,password_hash() 函数会随机生成“盐”。 非常简单,行之有效。

我应该如何保存“盐”?

当使用 password_hash() 或者 crypt() 函数时, “盐”会被作为生成的散列值的一部分返回。 你可以直接把完整的返回值存储到数据库中, 因为这个返回值中已经包含了足够的信息, 可以直接用在 password_verify()crypt() 函数来进行密码验证。

下图展示了 crypt()password_hash() 函数返回值的结构。 如你所见,算法的信息以及“盐”都已经包含在返回值中, 在后续的密码验证中将会用到这些信息。

crypt-text-rendered

 

date(): It is not safe to rely on the system's timezone settings

date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. PHP 5.3 +  需要在 php.ini 文件中配置 timezone, 或在调用 date() 函数之前使用 date_default_timezone_set() 方法设置 timezone