Nginx 与 Flask 搭建 HTTP/HTTPS 服务器
- 环境搭建
-
- 1、Nginx 安装
- 2、Flask 安装
- 3、OpenSSL 生成 https 所需秘钥与证书
- 4、配置 Nginx 代理到 Flask
- 5、重启 Nginx 服务
- 6、Flask Demo 程序
- 7、服务器开机自启动
- 8、简单的网页服务器
环境搭建
1、Nginx 安装
sudo apt install nginx
安装完毕,浏览器或者curl访问 http://<Nginx服务器IP> ,测试Nginx服务是否正常。
2、Flask 安装
# 安装 python3 与 pip3 工具
sudo apt install python3 python3-pip
# 使用 pip3 安装 flask
pip3 install flask
3、OpenSSL 生成 https 所需秘钥与证书
# 创建一个私钥
sudo openssl genrsa -des3 -out server.key 2048
# 移除私钥中的密码短语(可选,但推荐在测试环境中这样做)
sudo openssl rsa -in server.key -out server_no_pass.key
# 生成自签名证书请求
sudo openssl req -new -key server_no_pass.key -out server.csr
# 生成自签名证书,有效期为 365 天
sudo openssl x509 -req -days 365 -in server.csr -signkey server_no_pass.key -out server.crt
4、配置 Nginx 代理到 Flask
备份 /etc/nginx/sites-available/default 文件,超级权限修改 default 文件,支持 http/https 代理。
# 备份 Nginx 配置文件
sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.bak
# 配置代理
sudo vim /etc/nginx/sites-available/default
添加以下内容至 default 文件
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name localhost.linux;
location / {
# 代理到 Flask 应用
proxy_pass http://localhost:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 443 ssl;
server_name localhost.linux;
# SSL 配置,包括证书和私钥
ssl_certificate /etc/nginx/certificate/server.crt;
ssl_certificate_key /etc/nginx/certificate/server_no_pass.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
# 代理到 Flask 应用
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
5、重启 Nginx 服务
# 重启 Nginx 服务
sudo service nginx reload
# 或者使用以下命令
sudo nginx -s reload
6、Flask Demo 程序
- 在项目目录下创建 demo.py 测试 Flask 服务器from flask import Flask, request, render_template, jsonify, Response
from werkzeug.middleware.proxy_fix import ProxyFixapp = Flask(__name__)
# 应用 ProxyFix 中间件来修复代理环境中的请求信息,没有该行内容则Flask获取的请求IP 为 Nginx 代理 ip 127.0.0.1
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_host=1, x_proto=1)@app.route("/", methods=["GET", "PUT"])
def index():
# 打印请求头
headers = request.headers
for header, value in headers.items():
print(f"{header}: {value}")# 打印请求 IP
print(request.remote_addr)
xml_string = '<html><h1>Flask Demo</h1><p>这是一个Flask APP 示例</p></html>'
response = Response(xml_string, status=200)
return responseif __name__ == "__main__":
print("flask starting …", flush=True)
app.run(debug=True) # 如果不使用 5000端口,可以使用 port=1234切换端口 - 执行 demo 测试效果# 运行 demo
python3 demo.py &
# curl get 内容
curl -X GET http://127.0.0.1
7、服务器开机自启动
- 在 python 代码所在目录创建 start.shpython3 ~/nginx/autopic/demo.py &
- 使用 cron 开机执行任务crontab -e
# flask 开机自启动 以绝对路径启动服务,保证日志在预期目录生成
@reboot cd /home/username/nginx/autopic && /home/username/nginx/autopic/start.sh
8、简单的网页服务器
from flask import Flask, request, render_template, jsonify, Response, send_from_directory,send_file,abort
from pathlib import Path
from werkzeug.middleware.proxy_fix import ProxyFix
import xml.etree.ElementTree as ET # xml
import logging
import jwt
import datetime
import secrets
import os
import base64
from xml.etree import ElementTree
import binascii
import timetool
import master_camera
from csvmode import csv_file
# 配置 模板文件(html)目录为 html;后续 html 文件放在对应目录下即可
app = Flask(__name__, template_folder='html')
# 应用 ProxyFix 中间件来修复代理环境中的请求信息,没有该行内容则Flask获取的请求IP 为 Nginx 代理 ip 127.0.0.1
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_host=1, x_proto=1)
# 配置日志系统
log_file = "app.log" # 日志文件名
logging.basicConfig(
filename=log_file,
level=logging.INFO,
format="%(asctime)s:%(levelname)s:%(message)s",
)
@app.route("/xxx", methods=["GET"])
def index():
xml_string = "<html><h1>Flask Demo</h1><p>这是一个Flask APP 示例</p><p>阴云不蔽月,依旧照我心。何须念桑梓,心安即吾乡。</p></html>"
response = Response(xml_string, status=200)
logging.info(xml_string)
return response
@app.route("/", methods=["GET"])
@app.route("/home", methods=["GET"])
def home():
logging.info("/HOME")
# 前面初始化 Flask 时配置了 template_folder ,访问的 home/index.html 在 html/home/index.html
return render_template('home/index.html'), 200
@app.route("/360", methods=["GET"])
def T360():
return render_template('test/360.html'), 200
@app.route("/code", methods=["GET"])
def code_flask():
return render_template('code/index.html'), 200
@app.route("/demo", methods=["GET"])
def demo_flask():
return render_template('demo/index.html'), 200
@app.route("/about", methods=["GET"])
def about_flask():
return render_template('about/index.html'), 200
# 设置视频文件的目录
VIDEO_DIR = '.'
BASE_DIR = Path(__file__).resolve().parent
# 创建一个路由来服务视频文件
@app.route('/<path:filepath>')
def serve_file(filepath):
# 构建文件的完整路径
file_path = BASE_DIR / filepath
# 确保文件存在且是文件而不是目录
if not file_path.exists() or not file_path.is_file():
abort(404)
# 禁止访问某些敏感目录或文件
# 例如,不允许访问'.env'文件或任何隐藏文件
if any(file_path.parts[–1].startswith(prefix) for prefix in ('.', '_')):
abort(403)
# 使用send_file发送文件
# return send_file(str(file_path), as_attachment=False, mimetype='video/mp4')
return send_file(str(file_path), as_attachment=False)
@app.errorhandler(404)
def page_not_found(e):
return render_template('404/index.html'), 404
if __name__ == "__main__":
# 在生产环境中,应该使用 WSGI 服务器(如Gunicorn)和反向代理(如Nginx)
# 这里仅用于开发和测试目的
print("flask starting …", flush=True)
app.run(debug=True)
评论前必须登录!
注册