当前位置: 首页 > article >正文

Linux部署python web项目Flask + gunicorn + nginx

文章目录

  • 一、安装python&使用虚拟环境
  • 二、python程序重要参数加密
    • 2.1 非对称加密(RSA)
    • 2.2 生成密钥对
    • 2.4 以连接数据库参数加密为例
      • 2.4.1 工具类RSA.py
  • 三、一个简单的Flask项目
  • 四、安装配置gunicorn
  • 4.1 安装
    • 4.2 启动/配置(选择eventlet)
      • 4.2.1 命令行方式配置参数
      • 4.2.2 配置文件方式配置参数
  • 五、安装配置nginx
    • 5.1 安装
    • 5.2 配置
  • 六、运维
    • 6.1 启动gunicorn服务
    • 6.2 停止gunicorn服务

一、安装python&使用虚拟环境

参见Arch Linux 定时运行python脚本(crontab)

二、python程序重要参数加密

2.1 非对称加密(RSA)

用某用户密钥加密后所得的信息,只能用该用户的解密密钥才能解密。如果知道了其中一个,并不能计算出另外一个。因此如果公开了一对密钥中的一个,并不会危害到另外一个的秘密性质。称公开的密钥为公钥;不公开的密钥为私钥。
参考“公钥加密”

  • 生成RSA密钥对
  • 私钥存储在服务器上(运维人员做好秘钥管理)
  • 公钥公开给开发人员,用于代码中进行重要配置加密

2.2 生成密钥对

安装pycryptodome

pip install pycryptodome
from Crypto.PublicKey import RSA

key = RSA.generate(2048)
private_key = key.export_key()
with open("private.pem", "wb") as f:
    f.write(private_key)

public_key = key.publickey().export_key()
with open("public.pem", "wb") as f:
    f.write(public_key)

2.4 以连接数据库参数加密为例

【RSA加密/解密】PKCS1_OAEP和PKCS1_v1_5

2.4.1 工具类RSA.py

from Crypto.Cipher import PKCS1_OAEP as PKCS1_cipher
from Crypto.PublicKey import RSA
# 读取密钥
def get_key(path):
    with open(path) as f:
        pem_data = f.read()
        return RSA.importKey(pem_data)
# 公钥加密
def encrypt(msg, pub_path):
    key = get_key(pub_path)
    cipher = PKCS1_cipher.new(key)
    encrypt_msg = cipher.encrypt(msg.encode("utf-8"))
    return base64.b64encode(encrypt_msg).decode()
# 私钥加密
def decrypt(msg, pri_path):
    key = get_key(pri_path)
    cipher = PKCS1_cipher.new(key)
    decrypt_data = cipher.decrypt(base64.b64decode(msg))
    return decrypt_data.decode("utf-8")
  
if __name__ == '__main__':
    original_msg = "hello world"
    encrypted_data = encrypt(original_msg, "./pub_key.pem")
    print("encrypt_data:", encrypted_data)
    decrypted_data = decrypt(encrypted_data, "./pri_key.pem")
    print("decrypt_data:", decrypted_data)

三、一个简单的Flask项目

pip install Flask

my_first_flask.py

from flask import Flask, render_template

app = Flask(__name__, template_folder="template")

@app.route("/t/hello")
def hello_world():
    return "<p>Hello, World!</p>"
@app.route("/t/index")
def index():
	return render_template('index.html')

template/index.html

<h1>index</h1>

四、安装配置gunicorn

4.1 安装

Web项目开启异步workers

$ pip install gunicorn
# web 项目必须启用 Async Workers(使用eventlet)
$ pip install greenlet            # Required for both
$ pip install eventlet            # For eventlet workers
# web 项目必须启用 Async Workers(使用gevent)
$ pip install greenlet            # Required for both
$ pip install gevent              # For gevent workers

4.2 启动/配置(选择eventlet)

参考博客
配置说明-官网

4.2.1 命令行方式配置参数

# 运行
# -k 配置使用workers 默认sync(同步),异步根据不同安装选择eventlet/gevent
nohup python -m gunicorn -w 5 -k eventlet -b 0.0.0.0:9999 -t 120 my_first_flask:app >> my_first_flask.log 2>&1 &

# 根据进程号优雅关闭
kill -TERM 13078

4.2.2 配置文件方式配置参数

在这里插入图片描述
gunicorn.conf.py


# **运行配置**

# 并行工作进程数
workers = 4
 
# 指定每个工作者的线程数
threads = 2
 
# 使用nginx反向代理,默认本地访问端口 9999
bind = '127.0.0.1:9999'

## 修改是否重新加载
#reload = True

#
#daemon = True

## 超时时间,默认30
timeout=30

worker_class='eventlet'

# **日志文件配置**
#loglevel="info"
#accesslog="log/access.log"
#errorlog="log/error.log"
logconfig_dict = {
    'version':1,
    'disable_existing_loggers': True,
    "root": {"level": "INFO", "handlers": ["root_handler"]},
    'loggers':{
        "gunicorn.error": {
            "level": "INFO",# 打日志的等级可以换的,下面的同理
            "handlers": ["error_file"], # 对应下面的键
            "propagate": 1,
            "qualname": "gunicorn.error"
        },

        "gunicorn.access": {
            "level": "DEBUG",
            "handlers": ["access_file"],
            "propagate": 0,
            "qualname": "gunicorn.access"
        }
    },
    'handlers':{
        "error_file": {
            "class": "logging.handlers.RotatingFileHandler",
            "backupCount": 3,
           # "when":"D",
           # "interval":1,
            "maxBytes": 1024 * 1024 * 10,
            "formatter": "generic",
            "encoding": "utf-8",
            "filename": "log/gunicorn.error.log"
        },
        "access_file": {
            "class": "logging.handlers.TimedRotatingFileHandler",
            "backupCount": 3,
            "when":"D",
            "interval":1,
            "formatter": "generic",
            "filename": "log/gunicorn.access.log",
        },
        "root_handler":{
            "class": "logging.handlers.TimedRotatingFileHandler",
            "backupCount": 3,
            "when":"D",
            "interval":1,
            "formatter": "generic",
            "filename": "log/gunicorn.root.log",
        }
    },
    'formatters':{
        "generic": {
            "format": "'[%(process)d] [%(asctime)s] %(levelname)s [%(filename)s:%(lineno)s] %(message)s'", # 打日志的格式
            "datefmt": "[%Y-%m-%d %H:%M:%S %z]",# 时间显示方法
            "class": "logging.Formatter"
        },
        "access": {
            "format": "'[%(process)d] [%(asctime)s] %(levelname)s [%(filename)s:%(lineno)s] %(message)s'",
            "class": "logging.Formatter"
        }
    }
}
# gunicorn当前的process id
pidfile="gunicorn.pid"

日志配置参照

五、安装配置nginx

5.1 安装

(1)使用包管理工具

# 安装
sudo pacman -S nginx

# 验证是否安装成功
nginx -v
# 查看当前是否启动nginx(有master,worker)
ps -ef | grep nginx
# 查看当前nginx状态
systemctl status nginx
# 立即启动
systemctl start nginx
# 立即重启
systemctl restart nginx
# 设置开机自启动

(2)使用源码编译(TODO)

5.2 配置

/etc/nginx/nginx.conf

user http;
worker_processes auto;
worker_cpu_affinity auto;

events {
    multi_accept on;
    worker_connections 1024;
}

http {
    charset utf-8;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    server_tokens off;
    log_not_found off;
    types_hash_max_size 4096;
    client_max_body_size 16M;
    log_format test 'upstat=$upstream_status';
    # MIME
    include mime.types;
    default_type application/octet-stream;

    # logging
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log warn;

    # load configs
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;    

    server {
    	listen 9888;
	server_name 172.XXX.XXX.XXX;
	location /test/ {
		proxy_pass http://localhost:9999/t/;
	}
	error_page 400 401 402 403 404 405 406 407 408 409 /40x.html;
	location = /40x.html {
		root /usr/share/nginx/html;
	}
        access_log /var/log/nginx/access_test.log test;
    }
}

假设本机ip地址为:172.XXX.XXX.XXX。
访问:172.XXX.XXX.XXX:9888/test/path1,重定向到localhost:9999/t/path1
访问:172.XXX.XXX.XXX:9888/test/hello,重定向到localhost:9999/t/hello

六、运维

6.1 启动gunicorn服务

文件名:start

#!/bin/bash

if [ "$#" -lt 1 ]; then
	echo "Please provide one argument."
else
	source ../bin/activate
	python -m gunicorn --check-config $1 
	python -m gunicorn -c gunicorn.conf.py $1 -D
	deactivate
fi
[rebecca@study src]$. start my_first_flask:app

6.2 停止gunicorn服务

文件名:stop

#!/bin/bash

head -n 1 gunicorn.pid | xargs kill -TERM 

[rebecca@study src]$. stop

http://www.kler.cn/a/320846.html

相关文章:

  • [ACTF2020]Upload 1--详细解析
  • uniapp vue3的下拉刷新和上拉加载
  • async 和 await的使用
  • 【模板】字典树luoguP8306
  • zabbix7.0实操指南:基于麒麟V10操作系统部署zabbix7.0
  • 无效的目标发行版17和无法连接Maven进程问题
  • 《经典图论算法》约翰逊算法(Johnson)
  • 前端插件开发用什么技术比较好,用来程序自动化下载
  • TypeScript 设计模式之【单例模式】
  • [每日一练]修复表中的名字
  • Dependency Check:一款针对应用程序依赖组件的安全检测工具
  • ACM MM24 | Hi3D: 3D生成领域再突破!新视角生成和高分辨率生成双SOTA(复旦智象等)
  • Java 编码系列:异常处理与自定义异常
  • 一些广泛认可的编程工具,在不同的方面帮助我们提升效率
  • 使用cmd命令窗口操作mongodb
  • Scikit-LearnTensorFlow机器学习实用指南(三):一个完整的机器学习项目【下】
  • mask2former训练自定义数据集
  • Leetcode算法基础篇-位运算
  • 架构师论文备考-论软件系统架构评估
  • 云轴科技ZStack AIOS平台智塔亮相华为全联接大会
  • 在 macOS 上安装 ADB给安卓手机装APK,同样适用智能电视、车机
  • 单词的秘密2
  • DNS协议解析
  • leetcode第十三题:罗马数字转整数
  • win 录屏软件有哪些?5个软件帮助你快速进行电脑录屏。
  • 记录一次学习--委派攻击学习