1.1 更新系统并安装基础依赖
bash
# 更新系统包
sudo apt update
sudo apt upgrade -y
# 安装必要依赖
sudo apt install -y python3 python3-pip python3-venv nginx git
sudo apt install -y build-essential python3-dev
1.2 创建项目目录结构
bash
# 创建项目目录
sudo mkdir -p /opt/mfc-server/{app,logs,data/uploads,data/files,config}
sudo mkdir -p /var/log/mfc-server
# 设置目录权限
sudo chown -R $USER:$USER /opt/mfc-server
sudo chmod -R 755 /opt/mfc-server
2. 创建 Flask 应用
2.1 创建虚拟环境
bash
cd /opt/mfc-server
python3 -m venv venv
source venv/bin/activate
2.2 安装 Python 依赖
创建 requirements.txt:
使用 vim 编辑器
bash
vim requirements.txt
在vim中:
-
按 i 进入插入模式
-
输入内容:
bash
flask==2.3.3
gunicorn==21.2.0
python-dotenv==1.0.0
-
按 Esc 退出插入模式
-
输入 :wq 保存并退出
安装依赖:
bash
pip install -r requirements.txt
2.3 创建 Flask 应用
创建 /opt/mfc-server/app/__init__.py:
bash
import os
from flask import Flask
from dotenv import load_dotenv
load_dotenv()
def create_app():
app = Flask(__name__)
# 基础配置
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'dev-secret-key')
app.config['MAX_CONTENT_LENGTH'] = 1 * 1024 * 1024 # 1MB
return app
创建 /opt/mfc-server/app/main.py:
bash
import os
import json
import logging
from datetime import datetime
from flask import request, jsonify, send_file
from app import create_app
app = create_app()
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(levelname)s %(name)s %(message)s',
handlers=[
logging.FileHandler('/var/log/mfc-server/app.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
# 数据目录
UPLOAD_DIR = '/opt/mfc-server/data/uploads'
FILE_DIR = '/opt/mfc-server/data/files'
@app.route('/api/v1/health', methods=['GET'])
def health_check():
"""健康检查端点"""
return jsonify({
"status": "healthy",
"timestamp": datetime.now().isoformat(),
"service": "mfc-data-server"
})
@app.route('/api/v1/data', methods=['POST'])
def receive_data():
"""接收客户端数据"""
try:
client_ip = request.remote_addr
timestamp = datetime.now().isoformat()
# 记录请求信息
logger.info(f"Data request from {client_ip}")
# 获取数据
if request.content_type == 'application/json':
data = request.get_json()
if data:
data_str = json.dumps(data, ensure_ascii=False)
else:
data_str = ""
else:
data_str = request.get_data(as_text=True)
# 验证数据大小
if len(data_str) > 1024: # 限制1KB
logger.warning(f"Data too large from {client_ip}: {len(data_str)} bytes")
return jsonify({"error": "Data too large"}), 400
# 保存数据到文件
date_str = datetime.now().strftime('%Y%m%d')
log_file = os.path.join(UPLOAD_DIR, f"data_{date_str}.log")
with open(log_file, 'a', encoding='utf-8') as f:
log_entry = {
"timestamp": timestamp,
"client_ip": client_ip,
"data": data_str,
"data_length": len(data_str)
}
f.write(json.dumps(log_entry, ensure_ascii=False) + '\n')
logger.info(f"Data saved from {client_ip}: {len(data_str)} bytes")
return jsonify({
"status": "success",
"timestamp": timestamp,
"received_bytes": len(data_str),
"message": "Data received successfully"
})
except Exception as e:
logger.error(f"Error processing data from {request.remote_addr}: {str(e)}")
return jsonify({"error": "Internal server error"}), 500
@app.route('/api/v1/file', methods=['GET'])
def download_file():
"""提供文件下载"""
try:
filename = request.args.get('name', 'config.txt')
file_path = os.path.join(FILE_DIR, filename)
# 安全检查:防止目录遍历攻击
if '..' in filename or filename.startswith('/'):
return jsonify({"error": "Invalid filename"}), 400
if not os.path.exists(file_path):
logger.warning(f"File not found: {filename} requested by {request.remote_addr}")
return jsonify({"error": "File not found"}), 404
logger.info(f"File downloaded: {filename} by {request.remote_addr}")
return send_file(file_path, as_attachment=True)
except Exception as e:
logger.error(f"Error serving file: {str(e)}")
return jsonify({"error": "Internal server error"}), 500
@app.route('/api/v1/stats', methods=['GET'])
def get_stats():
"""获取服务器统计信息(可选)"""
try:
# 计算今日接收的数据量
date_str = datetime.now().strftime('%Y%m%d')
log_file = os.path.join(UPLOAD_DIR, f"data_{date_str}.log")
count = 0
if os.path.exists(log_file):
with open(log_file, 'r', encoding='utf-8') as f:
count = sum(1 for _ in f)
return jsonify({
"status": "success",
"requests_today": count,
"timestamp": datetime.now().isoformat()
})
except Exception as e:
logger.error(f"Error getting stats: {str(e)}")
return jsonify({"error": "Internal server error"}), 500
if __name__ == '__main__':
# 确保目录存在
os.makedirs(UPLOAD_DIR, exist_ok=True)
os.makedirs(FILE_DIR, exist_ok=True)
# 开发模式运行
app.run(host='0.0.0.0', port=8082, debug=True)
创建 /opt/mfc-server/run.py:
bash
from app.main import app
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8082)
3. 配置 Gunicorn
3.1 创建 Gunicorn 配置文件
创建 /opt/mfc-server/config/gunicorn.conf.py:
bash
import multiprocessing
# 服务器绑定
bind = "127.0.0.1:8082"
# 工作进程数
workers = multiprocessing.cpu_count() * 2 + 1
# 工作模式
worker_class = "sync"
# 最大并发连接数
worker_connections = 1000
# 超时设置
timeout = 30
keepalive = 2
# 进程名称
proc_name = "mfc-server"
# 日志配置
accesslog = "/var/log/mfc-server/gunicorn_access.log"
errorlog = "/var/log/mfc-server/gunicorn_error.log"
loglevel = "info"
# 最大请求数(防止内存泄漏)
max_requests = 1000
max_requests_jitter = 100
# 预加载应用(减少内存占用和启动时间)
preload_app = True
# 守护进程模式(通过systemd管理,这里设为False)
daemon = False
3.2 创建启动脚本
创建 /opt/mfc-server/start_server.sh:
bash
#!/bin/bash
cd /opt/mfc-server
# 激活虚拟环境
source venv/bin/activate
# 启动Gunicorn
exec gunicorn -c config/gunicorn.conf.py "app.main:app"
设置执行权限:
bash
chmod +x /opt/mfc-server/start_server.sh
4. 配置 Nginx
4.1 创建 Nginx 配置文件
创建 /etc/nginx/sites-available/mfc-server:
bash
# MFC数据服务器配置
server {
listen 80;
server_name your-domain.com; # 替换为您的域名或IP
# 客户端大小限制
client_max_body_size 1M;
# 访问日志
access_log /var/log/nginx/mfc_access.log;
error_log /var/log/nginx/mfc_error.log;
# 静态文件服务(如果需要)
location /static/ {
alias /opt/mfc-server/static/;
expires 30d;
add_header Cache-Control "public, immutable";
}
# API反向代理配置
location /api/ {
# 代理到Gunicorn
proxy_pass http://127.0.0.1:8082;
# 设置代理头
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;
# 超时设置
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
# 缓冲区设置
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
# 禁用代理重定向
proxy_redirect off;
}
# 根路径重定向到健康检查
location = / {
proxy_pass http://127.0.0.1:8082/api/v1/health;
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;
}
# 安全设置:隐藏服务器版本
server_tokens off;
}
4.2 启用 Nginx 站点
bash
# 创建符号链接
sudo ln -s /etc/nginx/sites-available/mfc-server /etc/nginx/sites-enabled/
# 测试Nginx配置
sudo nginx -t
# 重启Nginx
sudo systemctl restart nginx
# 设置Nginx开机自启
sudo systemctl enable nginx
5. 创建 Systemd 服务
5.1 创建 Systemd 服务文件
创建 /etc/systemd/system/mfc-server.service:
bash
[Unit]
Description=MFC Data Server
After=network.target
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/mfc-server
Environment=PATH=/opt/mfc-server/venv/bin
ExecStart=/opt/mfc-server/venv/bin/gunicorn -c config/gunicorn.conf.py "app.main:app"
ExecReload=/bin/kill -s HUP $MAINPID
Restart=always
RestartSec=3
# 安全设置
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/opt/mfc-server /var/log/mfc-server
# 日志设置
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
5.2 启动并启用服务
bash
# 重新加载systemd配置
sudo systemctl daemon-reload
# 启动服务
sudo systemctl start mfc-server
# 设置开机自启
sudo systemctl enable mfc-server
# 检查服务状态
sudo systemctl status mfc-server
6. 创建示例配置文件
6.1 创建示例配置文件
创建 /opt/mfc-server/data/files/config.txt:
bash
# MFC客户端配置文件
# 更新时间: 2024-01-01
[Server]
server_url=http://your-domain.com/api/v1/data
file_url=http://your-domain.com/api/v1/file
[Client]
device_id=default_device
check_interval=3600
max_retries=3
[Data]
format=json
encoding=utf-8
7. 配置日志轮转
7.1 配置 Logrotate
创建 /etc/logrotate.d/mfc-server:
bash
/var/log/mfc-server/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
copytruncate
postrotate
systemctl reload mfc-server > /dev/null 2>/dev/null || true
endscript
}
8. 防火墙配置
8.1 配置防火墙(如果启用)
bash
# 开放HTTP端口(80)
sudo ufw allow 80/tcp
# 如果使用其他防火墙工具,确保80端口开放
9. 部署验证
9.1 测试API端点
bash
# 健康检查
curl http://your-domain.com/api/v1/health
# 发送测试数据
curl -X POST http://your-domain.com/api/v1/data \
-H "Content-Type: application/json" \
-d '{"device_id": "test_device", "data": "test message"}'
# 下载配置文件
curl -O http://your-domain.com/api/v1/file?name=config.txt
9.2 检查服务状态
bash
# 检查应用服务
sudo systemctl status mfc-server
# 检查Nginx服务
sudo systemctl status nginx
# 检查日志
sudo tail -f /var/log/mfc-server/app.log
sudo tail -f /var/log/nginx/mfc_access.log
10. 监控和维护
10.1 创建监控脚本
创建 /opt/mfc-server/scripts/health_check.sh:
bash
#!/bin/bash
# 健康检查脚本
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost/api/v1/health)
if [ "$response" != "200" ]; then
echo "Service is down! HTTP Code: $response"
# 可以添加重启逻辑或发送通知
systemctl restart mfc-server
else
echo "Service is healthy"
fi
10.2 设置定时监控
bash
# 编辑crontab
crontab -e
# 添加健康检查(每5分钟一次)
*/5 * * * * /opt/mfc-server/scripts/health_check.sh >> /var/log/mfc-server/health_check.log 2>&1
部署完成后的目录结构
bash
/opt/mfc-server/
├── app/
│ ├── __init__.py
│ └── main.py
├── config/
│ └── gunicorn.conf.py
├── data/
│ ├── uploads/
│ └── files/
│ └── config.txt
├── logs/
├── scripts/
│ └── health_check.sh
├── venv/
├── requirements.txt
├── run.py
└── start_server.sh
如果有问题
问题诊断步骤
1. 首先检查Gunicorn服务状态
bash
# 检查mfc-server服务状态
sudo systemctl status mfc-server
# 如果服务不存在或失败,重新加载并启动
sudo systemctl daemon-reload
sudo systemctl start mfc-server
sudo systemctl status mfc-server
# 查看服务日志
sudo journalctl -u mfc-server -f
2. 直接测试Gunicorn服务
bash
# 直接在本地测试Gunicorn(确保服务在运行)
curl http://127.0.0.1:8082/api/v1/health
# 如果这个能工作,说明Flask应用正常
测试2:测试数据接收接口
bash
curl -X POST http://127.0.0.1:8082/api/v1/data \
-H "Content-Type: application/json" \
-d '{"device_id": "test_device_001", "data": "Hello from test", "timestamp": "2024-01-01T12:00:00Z"}'
3. 检查Nginx配置
查看Nginx配置文件:
bash
# 检查Nginx配置语法
sudo nginx -t
# 查看当前的Nginx配置
cat /etc/nginx/sites-available/mfc-server
# 检查是否已启用站点
ls -la /etc/nginx/sites-enabled/