服务器上怎么跑Python程序

结论: 在服务器上跑 Python 程序的标准流程是:用 python3 -m venv 建独立虚拟环境隔离依赖,用 pip 安装 requirements,Web 类应用交给 Gunicorn(或 uWSGI)以 WSGI 方式启动,再用 systemd 或 Supervisor 做进程守护,最后由 Nginx 反向代理对外提供 80/443 服务。切忌用 root 直接 python app.py 挂在后台。

引言:从"能跑起来"到"能稳定跑"

在服务器上运行 Python 程序有两个阶段。第一阶段是"跑起来"——python3 app.py 看到输出就算成功;第二阶段是"稳定跑"——SSH 断开不中断、崩溃能自动拉起、开机能自启、日志可追溯、多版本依赖不打架。绝大多数人卡在第二阶段。

本文以 Ubuntu 24.04 LTS(默认 Python 3.12)为例,覆盖 Web 应用(Flask / Django / FastAPI)与常驻脚本两类场景,给出从虚拟环境到 systemd 守护的完整链路。截至 2026 年,这套组合仍是 Python 服务端部署的主流做法。

Python 程序的运行方式怎么选?

先给结论:选型取决于程序类型与规模,不要一上来就用最重的方案。

方式适用优点缺点
python3 xxx.py一次性脚本、调试零配置终端断开即退出
nohup / screen临时测试简单崩溃不重启,无开机自启
Gunicorn + systemdFlask/Django 生产(推荐)多进程、自动重启、日志规范需写单元文件
uWSGI + Nginx高并发、需 uwsgi 协议性能强、功能全配置复杂
Supervisor多进程统一管理自带进程组与 Web 面板额外装组件
Docker多应用隔离交付环境一致性最好需掌握容器技术

判断标准很简单:Web 服务用 Gunicorn + systemd(或 Supervisor);一次性脚本用 cron + venv;多服务混布、要求环境一致性时用 Docker。

第一步:安装 Python 与创建虚拟环境

结论:永远不要在系统的全局 Python 环境里装业务依赖。虚拟环境(Virtual Environment)是 Python 部署的第一原则。

bash
sudo apt update
sudo apt install -y python3 python3-venv python3-pip python3-dev build-essential

python3 --version          # Ubuntu 24.04 为 Python 3.12
which python3

重要提示:Ubuntu 24.04 启用了 PEP 668 的"外部管理环境(externally-managed-environment)"标记,直接执行 pip install xxx 会报错 error: externally-managed-environment。这不是故障,而是系统在提醒你别污染全局环境。正确做法是建虚拟环境(不要用 --break-system-packages,除非你明确知道在做什么)。

bash
# 建一个统一的虚拟环境存放目录
sudo mkdir -p /opt/venvs
sudo python3 -m venv /opt/venvs/myapp

# 激活(激活后命令行前面会出现 (myapp))
source /opt/venvs/myapp/bin/activate

# 升级 pip 并安装依赖
python -m pip install --upgrade pip wheel setuptools
pip install -r /opt/apps/myapp/requirements.txt

# 退出虚拟环境
deactivate

虚拟环境的关键认知:

  • 不需要"激活"也能用,直接调用绝对路径更稳妥,尤其是在 systemd 与 crontab 中:/opt/venvs/myapp/bin/python /opt/apps/myapp/app.py。
  • 依赖清单用 pip freeze > requirements.txt 导出,生产环境建议锁定版本号(flask==3.0.3)。
  • 虚拟环境目录可以整体打包迁移,但跨机器迁移含 C 扩展的包时需重新编译,最好在同版本系统上操作。

第二步:用 Gunicorn 启动 Web 应用

结论:Flask、Django 自带的开发服务器(app.run())是单线程、无优化的,绝对不能用于生产。生产必须用 WSGI 服务器(WSGI Server),Gunicorn 是最通用的选择。

bash
source /opt/venvs/myapp/bin/activate
pip install gunicorn

# Flask:模块名:应用实例名
gunicorn -w 4 -k gthread --threads 2 -b 127.0.0.1:8000 'app:app'

# Django:项目包.wsgi
gunicorn -w 4 -b 127.0.0.1:8000 'myproject.wsgi:application'

# FastAPI(ASGI,需用 uvicorn worker)
pip install uvicorn[standard]
gunicorn -w 4 -k uvicorn.workers.UvicornWorker -b 127.0.0.1:8000 'main:app'

参数含义:

  • -w 4:工作进程数,经验公式为 CPU 核心数 × 2 + 1;2 核机器设 4~5 即可,过多反而因内存与上下文切换变慢。
  • -k gthread:使用线程 worker,配合 --threads 提升 IO 密集型场景吞吐。
  • -b 127.0.0.1:8000:只监听本机,由 Nginx 对外,避免直接暴露。
  • --timeout 60:worker 无响应超过该秒数会被重启,处理长任务时需调大。

生产环境建议把参数写进配置文件,便于版本管理:

python
# /opt/apps/myapp/gunicorn.conf.py
bind = "127.0.0.1:8000"
workers = 4
worker_class = "gthread"
threads = 2
timeout = 60
graceful_timeout = 30
keepalive = 5
max_requests = 2000            # 处理 N 个请求后自动重启 worker,缓解内存泄漏
max_requests_jitter = 200
accesslog = "/var/log/myapp/access.log"
errorlog  = "/var/log/myapp/error.log"
loglevel  = "info"
preload_app = True             # 预加载应用,节省内存并可在启动时暴露错误
bash
sudo mkdir -p /var/log/myapp && sudo chown www-data:www-data /var/log/myapp
/opt/venvs/myapp/bin/gunicorn -c /opt/apps/myapp/gunicorn.conf.py 'app:app'

若你更偏好 uWSGI,核心配置如下(二选一,不必同时装):

ini
[uwsgi]
chdir           = /opt/apps/myapp
module          = app:app
master          = true
processes       = 4
threads         = 2
socket          = 127.0.0.1:8001
vacuum          = true
die-on-term     = true
logto           = /var/log/myapp/uwsgi.log

第三步:用 systemd 守护进程(推荐)

结论:systemd 是 Linux 自带的进程管理器,能实现开机自启、崩溃自动重启、日志统一收集,比 nohup 与 screen 可靠得多,也不需要额外安装组件。

创建 /etc/systemd/system/myapp.service:

ini
[Unit]
Description=My Python Web App (Gunicorn)
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
User=www-data
Group=www-data
WorkingDirectory=/opt/apps/myapp
Environment="PATH=/opt/venvs/myapp/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
EnvironmentFile=-/etc/myapp.env
ExecStart=/opt/venvs/myapp/bin/gunicorn -c /opt/apps/myapp/gunicorn.conf.py 'app:app'
ExecReload=/bin/kill -HUP $MAINPID
KillMode=mixed
KillSignal=SIGTERM
TimeoutStopSec=30
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myapp

[Install]
WantedBy=multi-user.target

敏感配置放进 /etc/myapp.env(注意权限设为 600):

bash
sudo tee /etc/myapp.env <<'EOF'
FLASK_ENV=production
SECRET_KEY=改成随机长字符串
DATABASE_URL=mysql+pymysql://user:pass@127.0.0.1:3306/dbname
TZ=Asia/Shanghai
EOF
sudo chmod 600 /etc/myapp.env

启用与日常管理:

bash
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service

systemctl status myapp --no-pager
sudo systemctl restart myapp
sudo systemctl reload myapp            # 触发 ExecReload,Gunicorn 平滑重载
journalctl -u myapp -f                 # 实时日志
journalctl -u myapp --since '1 hour ago' --no-pager

Type=notify 需要 Gunicorn 安装时带 sdnotify(默认已支持);若启动报 Failed to read SERVICE_READY,把 Type 改成 simple 即可。

第四步:用 Supervisor 统一管理(可选)

结论:当你需要在一台机器上管理多个非系统级进程(Python 服务、队列消费者、Node 服务),Supervisor 提供了统一的控制面板与启停命令,比逐个写 systemd 单元更顺手。

bash
sudo apt install -y supervisor
sudo systemctl enable --now supervisor

创建 /etc/supervisor/conf.d/myapp.conf:

ini
[program:myapp]
command=/opt/venvs/myapp/bin/gunicorn -c /opt/apps/myapp/gunicorn.conf.py app:app
directory=/opt/apps/myapp
user=www-data
autostart=true
autorestart=true
startsecs=10
startretries=3
stopasgroup=true
killasgroup=true
redirect_stderr=true
stdout_logfile=/var/log/myapp/supervisor.log
stdout_logfile_maxbytes=50MB
stdout_logfile_backups=5
environment=PATH="/opt/venvs/myapp/bin",TZ="Asia/Shanghai"
bash
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl status
sudo supervisorctl restart myapp
sudo supervisorctl tail -f myapp       # 看日志

stopasgroup=true 与 killasgroup=true 很关键:Gunicorn 会 fork 子进程,不设这两项时停止主进程后子进程可能残留,导致端口占用。

第五步:配置 Nginx 反向代理

结论:Python 应用不直接对外,由 Nginx 处理静态文件、HTTPS、缓冲与限流,只把动态请求转发给 Gunicorn。

nginx
server {
    listen 80;
    server_name api.example.com;
    client_max_body_size 20m;

    location /static/ {
        alias /opt/apps/myapp/static/;      # 静态文件由 Nginx 直接返回
        expires 30d;
        access_log off;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        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 5s;
        proxy_read_timeout    60s;          # 应与 Gunicorn 的 timeout 相匹配
    }
}
bash
sudo nginx -t && sudo systemctl reload nginx
curl -I http://127.0.0.1:8000          # 先确认应用本身能响应
curl -I https://api.example.com        # 再确认代理链路