阿里云Linux云服务器部署Python项目——从零到生产环境的完整实战指南

apphuang2026年06月10日 09:00:2112

🔥 写在前面:部署不是「跑起来就行」,而是让它在公网上活下去

很多开发者在本地把 Flask 或 Django 跑通之后,第一反应是:python app.py或 python manage.py runserver 0.0.0.0:8000,然后兴冲冲地买了台阿里云 ECS,发现外网根本访问不了,或者一关 SSH 窗口进程就没了,又或者被卡在 Nginx 502、静态文件 404、安全组没放行、端口被防火墙拦住……这不是你的错。本地开发服务器和生产环境之间,隔着的不是一行代码,而是一整套工程体系。这篇文章的目标很简单:把这条链路彻底拆开,让你知道每一步在解决什么问题,然后给出一份可以直接照抄执行的完整方案。无论你用的是 Flask还是 Django,无论你的镜像是 Ubuntu 22.04/20.04还是 CentOS 7/Alibaba Cloud Linux 3,本文的架构思路和配置模板都能直接套用。

一、先搞清楚你在搭什么:请求到底是怎么走到你的 Python 代码的

很多人一上来就闷头敲命令,但不理解架构,一旦报错就不知道从哪里下手。我们先把生产环境的请求链路画清楚:
浏览器 / 客户端 │ │ HTTPS (443) 或 HTTP (80) ▼┌──────────────┐│ Nginx │ ← 面向公网的「门面」:处理SSL、静态文件、压缩、反向代理│ (反向代理) │└──────┬───────┘ │ proxy_pass 到内网端口 (如 127.0.0.1:8000) ▼┌──────────────┐│ Gunicorn │ ← WSGI HTTP Server:真正把请求翻译成 environ 字典│ / uWSGI │ 交给 Flask/Django 处理,再把响应包装回来└──────┬───────┘ │ ▼┌──────────────┐│ Flask / ││ Django App │ ← 你的业务代码└──────────────┘ │ ▼┌──────────────┐│ MySQL/ ││ PostgreSQL │ ← 数据库(可选但大多数项目需要)└──────────────┘
一句话记住这个链路:Nginx 挡在最外面负责「接客」,Gunicorn 负责「翻译协议」,你的 App 负责「干活」,数据库负责「存东西」。任何一个环节断掉,你看到的都是 502/503/404/连接超时。

⚠️ 友情提醒:Flask 自带的 app.run()和 Django 的 runserver都只是开发服务器,单线程、弱并发、不做信号处理,绝对不能用于生产。生产环境必须用 Gunicorn 或 uWSGI 这类 WSGI Server 来托管。

需要先登录阿里云控制台,点击:阿里云控制台

二、购买 ECS 与最关键的「安全组」配置(这一步错了,后面全白搭)

2.1 选配置时的关键决策


  • 实例规格:如果是个人项目或小型 API 服务,2 vCPU / 2GB起步即可跑起来(不过 2GB 内存跑 Python + Nginx + MySQL 会比较紧);如果带关系型数据库,建议至少 2 vCPU / 4GB。


  • 镜像选择:推荐 Ubuntu 22.04 LTS(资料多、apt 系好用)或 Alibaba Cloud Linux 3(阿里云自家优化版,兼容 CentOS/RHEL 系)。新手强烈建议选 Ubuntu,踩坑最少。


  • 网络:务必勾选「分配公网 IPv4 地址」,否则你买到的就是一台没有公网入口的内网机器。


  • 带宽:按流量计费的话 1~5 Mbps 够测试;正式上线建议 5 Mbps 起步或按固定带宽评估。


2.2 安全组 —— 阿里云的「云防火墙」

安全组是阿里云在网络层做的访问控制,优先级比服务器内部的 iptables / ufw / firewalld 还高。哪怕你服务器里的 Nginx 跑得再完美,安全组没放行端口,外网一样访问不了。你需要至少放行以下规则(在 ECS 控制台 → 本实例 → 安全组 → 入方向 中添加):
协议端口范围授权对象用途
TCP22你的办公网 IP(别写 0.0.0.0/0!)SSH 连接
TCP800.0.0.0/0HTTP 公网访问
TCP4430.0.0.0/0HTTPS 公网访问
TCP8000(仅调试时可临时开)你的办公网 IP直接测 Gunicorn 用(生产环境应通过 Nginx 走 80/443,8000 不对外)

✅ 安全建议:22 端口的授权对象千万别偷懒填 0.0.0.0/0(允许全世界扫),只放行你自己常用的公网 IP 段。后面我们还会把 SSH 改成密钥登录并改掉默认端口,进一步锁死入口。


三、SSH 连上去,先做服务器基础加固

拿到公网 IP 后,打开你本地的终端(Windows 用户用 PowerShell / CMD / XShell / MobaXterm 均可):
ssh root@你的公网IP
首次登录会提示指纹确认,输入 root 密码(在控制台可以重置实例密码),进去后第一件事——更新系统并把基础编译工具装好:📌 如果你选的是 Ubuntu 22.04 / 20.04:
# 更新软件源并升级已有包sudo apt update && sudo apt upgrade -y# 安装编译 Python 所需的底层依赖(非常重要!缺一项可能导致 pip install 某些包时报错)sudo apt install -y \ build-essential \ libssl-dev libffi-dev \ python3-dev python3-venv python3-pip \ zlib1g-dev libbz2-dev \ libreadline-dev libsqlite3-dev \ wget curl git \ software-properties-common# 验证系统自带 Python3 版本sudo python3 --version
📌 如果你选的是 CentOS 7/8 或 Alibaba Cloud Linux 3(yum/dnf 系):
# CentOS 7sudo yum groupinstall -y "Development Tools"sudo yum install -y \ openssl-devel bzip2-devel libffi-devel \ zlib-devel readline-devel sqlite-devel \ wget curl git# Alibaba Cloud Linux 3 / CentOS 8(用 dnf)sudo dnf groupinstall -y "Development Tools"sudo dnf install -y \ openssl-devel bzip2-devel libffi-devel \ zlib-devel readline-devel sqlite-devel \ wget curl git python3-pip

3.1 创建专用部署用户(强烈推荐,别一直顶着 root 干)

root 权限太大,一旦你运行的某个 Python 包或脚本被恶意利用,就是整台服务器沦陷。正确做法是建一个普通用户专用于部署:
# 创建用户(名字随便取,deploy / app / flaskuser 都行)sudo adduser deploysudo usermod -aG sudo deploy# 切换到该用户su - deploy

四、安装「可用的」Python 版本(重点:别被系统 Python 绑架)

这是新手最容易翻车的一步。Ubuntu 22.04 自带的 python3 一般是 3.10,CentOS 7 自带的可能是 3.6,而你的项目可能需要 3.9+、3.11+。而且——

⛔ 永远不要卸载或替换系统自带的 python3!很多 Linux 系统工具(apt、yum 本身的部分组件、cloud-init 等)依赖它,你删了它,系统可能直接废掉。正确的做法是并行安装你要的版本,然后用虚拟环境隔离。

方案A:系统源里就有你想要的版本(最简单,优先选)

Ubuntu 22.04 可以通过 deadsnakesPPA 装任意版本:
# Ubuntu 专属sudo apt install -y software-properties-commonsudo add-apt-repository -y ppa:deadsnakes/ppasudo apt updatesudo apt install -y python3.11 python3.11-venv python3.11-dev python3.11-distutils# 验证python3.11 --version

方案B:源码编译安装(通用、可控、生产环境最稳妥)

当你需要某个精确到小版本的 Python(比如 3.11.5),或者你的系统是 CentOS 7 这种源里版本很老的,就用编译安装:
# 下载源码(以 3.11.5 为例,可自行换版本)cd /tmpwget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgztar-xzf Python-3.11.5.tgzcd Python-3.11.5# 配置:指定安装到 /usr/local/python3.11,不碰系统 python3./configure --prefix=/usr/local/python3.11 --enable-optimizations \ --with-ensurepip=install# 编译(-j 后面跟 CPU 核心数,加快速度)make -j(nproc)# 安装(注意是 altinstall,不是 install!避免覆盖系统 python3)sudo make altinstall# 建个好用的软链接sudo ln -sf /usr/local/python3.11/bin/python3.11 /usr/local/bin/python3.11sudo ln -sf /usr/local/python3.11/bin/pip3.11 /usr/local/bin/pip3.11# 验证python3.11 --versionpip3.11 --version

💡 编译时如果报 No module named '_ctypes',说明你漏装了 libffi-dev(Ubuntu)或 libffi-devel(CentOS),回去补装再重新 make 即可。


五、创建项目目录与 Python 虚拟环境(隔离 = 安心)

虚拟环境的核心价值就一句话:让这个项目用的包版本,跟其他项目和系统 Python 互不干扰。今天跑一个 Django 4.x 的项目,明天另一个要用 aiohttp 的旧版,没有虚拟环境你就会陷入 dependency hell。

# 项目统一放一个约定俗成的目录(你也可以按喜好改)cd ~mkdir -p /home/deploy/appscd /home/deploy/apps# 创建虚拟环境(假设我们用 python3.11)python3.11 -m venv venv# 激活nsource venv/bin/activate# 提示符前面会出现 (venv) 字样,说明进去了# 顺手升级 pip 到最新(用阿里云镜像加速)pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/pip install --upgrade pip wheel

💡 小技巧:把 pip 镜像指向阿里云,后续装依赖速度快得多。如果你更喜欢清华源,把 URL 换成 https://pypi.tuna.tsinghua.edu.cn/simple/ 也行。


六、把你的 Python 项目传到服务器上(三种方式,从土到优雅)

方式一:SCP(最快、最直接,适合一次性传压缩包)

在你本地电脑的终端里执行:

# 本地:先把项目打成 tar.gz# cd /path/to/your/project# tar -czf myproject.tar.gz myproject/# 上传到服务器scp myproject.tar.gz deploy@你的公网IP:/home/deploy/apps/# 然后在服务器上解压ssh deploy@你的公网IPcd /home/deploy/appstar -xzf myproject.tar.gz

方式二:Git Clone(最优雅,推荐长期使用)

如果你项目在 GitHub / Gitee / GitLab 上,直接服务器里 clone,以后每次更新只需要 git pull

cd /home/deploy/appsgit clone https://github.com/你的用户名/你的仓库.git myprojectcd myproject# 确保虚拟环境已激活nsource ../venv/bin/activate# 装依赖pip install -r requirements.txt

方式三:rsync(增量同步,适合频繁迭代)

# 本地执行(排除 venv 和 __pycache__ 等不需要传的)rsync -avz --exclude 'venv' --exclude '__pycache__' --exclude '.git' \\ /local/path/to/myproject/ \\ deploy@你的公网IP:/home/deploy/apps/myproject/

📦 装依赖——这里是第二常见的翻车区

# 确保虚拟环境激活中(提示符有 (venv))cd /home/deploy/apps/myproject# 如果你项目有 requirements.txtpip install -r requirements.txt# 如果没有,手动装核心组件pip install Flask gunicorn# 或 Djangopip install Django gunicorn# 如果你的项目用 MySQLpip install mysqlclient# 如果 mysqlclient 编译报错(很常见),改用纯 Python 实现的替代pip install pymysql# Django 的话在 settings.py 上方加:import pymysql; pymysql.install_as_MySQLdb()# 如果用 PostgreSQLpip install psycopg2-binary

七、用 Gunicorn 把应用真正跑起来(告别 runserver / app.run)

7.1 Flask 项目的 Gunicorn 启动方式

假设你有个 app.py,里面 Flask 实例名叫 app(即 app = Flask(__name__)):

# 确保在虚拟环境激活状态下cd /home/deploy/apps/myproject# 测试启动(绑 0.0.0.0:8000 让所有网卡都能收到)/home/deploy/apps/venv/bin/gunicorn -w 3 -b 127.0.0.1:8000 app:app

-w 3 表示开 3 个 worker 进程(一般设为核心数的 2+1,比如 2 核设 3~4);app:app 的意思是「模块名:Flask实例名」。如果你的入口文件叫 main.py,实例也叫 app,那就是 main:app

7.2 Django 项目的 Gunicorn 启动方式

Django 的入口是项目目录下的 wsgi.py,Gunicorn 要找的是 项目名.wsgi:application

cd /home/deploy/apps/myproject# 测试启动/home/deploy/apps/venv/bin/gunicorn \\ -w 3 \\ -b 127.0.0.1:8000 \\ myproject.wsgi:application

⚠️ 注意这里我们绑的是 127.0.0.1:8000 而不是 0.0.0.0:8000Gunicorn 不应该直接暴露于公网,它只接受来自本机 Nginx 的请求就够了。外网流量统一走 Nginx 的 80/443,再由 Nginx 反代到 8000。这就是「反向代理」的安全边界。

阿里云Linux云服务器部署Python项目——从零到生产环境的完整实战指南

7.3 写一个 Gunicorn 配置文件(比命令行参数优雅得多)

在项目根目录创建 gunicorn_config.py

# /home/deploy/apps/myproject/gunicorn_config.pyimport multiprocessing# 绑定的 IP 和端口(只收本机请求)bind = \"127.0.0.1:8000\"# Worker 进程数:建议 (2 × CPU核心) + 1workers = multiprocessing.cpu_count() * 2 + 1# 每个 worker 的线程数(IO 密集型可以适当调大)threads = 2# Worker 类型:sync 是默认值;IO密集型可考虑 gthreadworker_class = \"sync\"# 请求超时(秒)——如果 worker 处理超过 30s 会被强制重启timeout = 30keepalive = 5# 访问日志和错误日志accesslog = \"/home/deploy/apps/myproject/logs/access.log\"errorlog = \"/home/deploy/apps/myproject/logs/error.log\"loglevel = \"info\"# 进程名前缀proc_name = \"myproject\"# 优雅重载graceful_timeout = 10
# 先创建日志目录mkdir -p /home/deploy/apps/myproject/logs# 用配置文件启动/home/deploy/apps/venv/bin/gunicorn -c gunicorn_config.py app:app# Django 的话把最后一截换成:myproject.wsgi:application

八、安装并配置 Nginx —— 对外的大门面

8.1 安装 Nginx

Ubuntu:sudo apt install nginx -y;CentOS:sudo yum install nginx -y(CentOS 可能需要先 sudo yum install epel-release)。

# Ubuntusudo apt install nginx -ysudo systemctl start nginxsudo systemctl enable nginx# 测试:浏览器访问 http://你的公网IP# 应该能看到 Nginx 默认欢迎页——说明 Nginx 起来了,安全组 80 也通了

8.2 给项目写一份 Nginx 站点配置

Flask 项目的 Nginx 配置示例:

# 创建配置文件sudo nano /etc/nginx/sites-available/myproject# ==================== 粘贴以下内容 ====================server { # 监听 80 端口(HTTP) listen 80; server_name 你的公网IP; # 如果有域名就写你的域名,如 example.com # ---- 1) 让 Nginx 直接处理静态文件(Flask 通常需要自己管 static) ---- location /static { alias /home/deploy/apps/myproject/static; # 改成你的 static 实际路径 } # ---- 2) 所有其他请求转给 Gunicorn ---- location / { proxy_pass http://127.0.0.1:8000; # 把真实客户端 IP 等信息传递给后端 proxy_set_header Hosthost; proxy_set_header X-Real-IP remote
a
	

ddr;proxy
s
	

et
h
	

eaderX−Forwarded−Forproxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto scheme; # WebSocket 支持(如果你的 Flask 用了 Flask-SocketIO,这行必须) proxy_http_version 1.1; proxy_set_header Upgradehttp_upgrade; proxy_set_header Connection "upgrade"; }}# ==================== 结束 ====================
Django 项目的 Nginx 配置示例(多了 static 和 media 的处理):
# 假设你已在 Django settings.py 中配置了:# STATIC_ROOT = BASE_DIR / "staticfiles"# MEDIA_ROOT = BASE_DIR / "media"# 并已执行:python manage.py collectstatic# 创建配置sudo nano /etc/nginx/sites-available/myproject# ==================== 粘贴 ====================server { listen 80; server_name 你的公网IP; # 或你的域名 # 访问日志(可选) access_log /var/log/nginx/myproject_access.log; error_log /var/log/nginx/myproject_error.log; # 静态文件 —— Nginx 直接serve,不经过 Django,性能最优 location /static/ { alias /home/deploy/apps/myproject/staticfiles/; } # 媒体文件(用户上传的) location /media/ { alias /home/deploy/apps/myproject/media/; } # 动态请求 → Gunicorn location / { proxy_pass http://127.0.0.1:8000;proxy_set_header Host host;proxy
s
	

et
h
	

eaderX−Real−IPremote_addr; proxy_set_header X-Forwarded-For proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Protoscheme; }}# ==================== 结束 ====================

8.3 激活配置并让 Nginx 加载

# Ubuntu(sites-available / sites-enabled 体系)sudo ln -sf /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled/# 删除默认欢迎页配置(可选,不然可能抢根路径)sudo rm -f /etc/nginx/sites-enabled/default# 检查配置语法有没有语法错误(非常有用的命令)sudo nginx -t# 重载sudo systemctl reload nginx# ===== CentOS 用户注意 =====# CentOS 的 nginx 不用 sites-available,直接把 server {} 块# 写成 /etc/nginx/conf.d/myproject.conf 就行,然后 nginx -t && systemctl reload nginx

九、进程守护 —— 让服务在后台永久存活(systemd 篇,推荐)

你现在已经能用 Gunicorn 把应用跑起来、Nginx 也能转发了。但问题是:你一退出 SSH,Gunicorn 进程就没了。即使加了 &后台运行,服务器一重启也不会自动拉起。生产环境的正确答案是:把它注册为系统服务(systemd),让操作系统替你管生命周期。
# 创建 systemd unit 文件sudo nano /etc/systemd/system/myproject.service# ==================== 内容如下 ====================[Unit]Description=Gunicorn daemon for myprojectAfter=network.target[Service]# 以哪个用户运行(不要用 root 生产环境更安全,这里先用 deploy 举例)User=deployGroup=www-data# 工作目录WorkingDirectory=/home/deploy/apps/myproject# 环境变量(如果settings用环境变量注入,在这里设)Environment="PATH=/home/deploy/apps/venv/bin"# 如果你需要 Flask 的 FLASK_ENV 之类,也写这里:# Environment="FLASK_ENV=production"# 启动命令ExecStart=/home/deploy/apps/venv/bin/gunicorn -c gunicorn_config.py app:app# Django 换成:ExecStart=/home/deploy/apps/venv/bin/gunicorn -c gunicorn_config.py myproject.wsgi:application# 自动重启策略Restart=alwaysRestartSec=3# 如果希望每次 reload 信号做优雅重启而非强杀# Type=notify 需要 Gunicorn 加 --worker-class gthread 之类的配合# 简单场景下 Type=simple 最稳[Install]WantedBy=multi-user.target# ==================== 结束 ====================
写好配置文件后,启用并启动服务:
# 让 systemd 重新加载配置sudo systemctl daemon-reload# 设置开机自启sudo systemctl enable myproject.service# 立即启动sudo systemctl start myproject.service# 查看状态,看是 active (running) 还是 failedsudo systemctl status myproject.service# 实时查看日志(按 Ctrl+C 退出)sudo journalctl -u myproject.service -f
至此,你的 Gunicorn 进程就被 systemd 守护起来了。服务器重启后它会自动启动,进程意外退出也会自动重启。你之后更新代码,流程是:
# 更新代码cd /home/deploy/apps/myproject# 比如 git pull# 重启服务(会重新加载代码)sudo systemctl restart myproject.service

十、接入数据库(MySQL / PostgreSQL)

绝大多数 Python Web 项目都需要数据库,这里分别给出 MySQL 和 PostgreSQL 的快速安装、配置,以及 Python 如何连接。

10.1 MySQL 安装与配置

# Ubuntusudo apt install mysql-server -y# 启动并开机自启sudo systemctl start mysqlsudo systemctl enable mysql# 安全初始化(会问你几个选项,建议都选 Y,设 root 密码,禁匿名等)sudo mysql_secure_installation
# 登录 MySQL 创建数据库和专属用户sudo mysql -u root -p# 进入 MySQL 命令行后执行CREATE DATABASE myproject CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;# 创建一个专门给 Python 应用连接的用户(比直接用 root 安全)CREATE USER 'project_user'@'localhost' IDENTIFIED BY '一个强密码';# 给这个用户赋予对 myproject 数据库的所有权限GRANT ALL PRIVILEGES ON myproject.* TO 'project_user'@'localhost';# 刷新权限FLUSH PRIVILEGES;# 退出EXIT;

10.2 PostgreSQL 安装与配置

# Ubuntusudo apt install postgresql postgresql-contrib -ysudo systemctl start postgresqlsudo systemctl enable postgresql
# 切换到 postgres 系统用户,用它的命令行工具 psqlsudo -u postgres psql# 在 PostgreSQL 命令行中CREATE DATABASE myproject;# 创建用户并设密码CREATE USER project_user WITH PASSWORD '一个强密码';# 把数据库的权限给这个用户GRANT ALL PRIVILEGES ON DATABASE myproject TO project_user;# 退出\q

10.3 在 Python 项目里连接数据库

Flask 示例(Flask-SQLAlchemy):
# 安装驱动# MySQL:pip install mysqlclient 或 pymysql# PostgreSQL:pip install psycopg2-binary# 配置数据库 URL# MySQL (pymysql) 格式:# SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://project_user:密码@localhost/myproject'# PostgreSQL 格式:# SQLALCHEMY_DATABASE_URI = 'postgresql://project_user:密码@localhost/myproject'
Django 示例(修改 settings.py):
# settings.pyDATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', # 或 'django.db.backends.mysql' 'NAME': 'myproject', 'USER': 'project_user', 'PASSWORD': '你的强密码', 'HOST': 'localhost', 'PORT': '5432', # PostgreSQL 默认 5432,MySQL 默认 3306 }}# 如果用的是 MySQL 且驱动是 pymysql,需要在 settings.py 顶部加:# import pymysql# pymysql.install_as_MySQLdb()
然后应用迁移:python manage.py migrate。

十一、上 HTTPS —— 免费 SSL 证书(Let's Encrypt + Certbot)

现在浏览器对 HTTP 不友好,而且 API 调用、微信小程序等都要求 HTTPS。用 Let's Encrypt 免费证书,三个月自动续期,省心。
# Ubuntu 安装 Certbot 和 Nginx 插件sudo apt install certbot python3-certbot-nginx -y# 假设你已有一个域名(比如 example.com)解析到了你的 ECS IP# 执行(把 example.com 换成你的域名)sudo certbot --nginx -d example.com -d www.example.com
Certbot 会自动修改你的 Nginx 配置,把 80 端口的 HTTP 重定向到 443 的 HTTPS,并且自动配置证书路径和自动续期。之后你的 Nginx 配置会被自动改造成类似这样:
server { listen 80; server_name example.com www.example.com;return 301 https://server
n
	

amerequest_uri; # 强制跳转 HTTPS}server { listen 443 ssl http2; server_name example.com www.example.com; # 证书路径,certbot 自动管理 ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;  # SSL 优化配置(certbot 自动生成) include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;  # ... 你原来的 location 配置 ... location / { proxy_pass http://127.0.0.1:8000;# 注意:因为走了 HTTPS,传给 Gunicorn 的 header 要调整 proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-Ssl on; proxy_set_header Host host;proxy
s
	

et
h
	

eaderX−Real−IPremote_addr; proxy_set_header X-Forwarded-For proxy_add_x_forwarded_for; }}

验证自动续期任务:sudo systemctl status certbot.timer,看到 enabled 和 active 即可。


十二、故障排查速查表(出问题时先看这里)

部署过程不出错是不可能的,关键是快速定位。

现象可能原因排查命令
外网访问 80 端口没反应 / 连接超时1. 阿里云安全组没放行 80
2. 服务器防火墙(ufw/iptables)拦了
3. Nginx 没启动
curl -I http://localhost (本机测 Nginx)
sudo systemctl status nginx
sudo ufw status
502 Bad Gateway1. Gunicorn 没启动
2. Nginx 配置里 proxy_pass 的端口和 Gunicorn 绑定的端口不一致
3. 用户/组权限导致 Nginx 无权访问 socket 或进程
sudo systemctl status myproject.service
netstat -tlnp | grep 8000 看端口监听
ps aux | grep gunicorn 看进程
静态文件 4041. Nginx 配置的 alias 路径错误
2. 静态文件目录权限不对(Nginx 用户 www-data 没读取权限)
3. Django 没执行 collectstatic
ls -la /home/deploy/apps/myproject/staticfiles/
检查 Nginx 配置文件 alias 路径
Django: python manage.py collectstatic
数据库连接失败
(OperationalError: (2003, \"Can't connect\")
1. 数据库服务没启动
2. 用户/密码/数据库名写错了
3. 数据库只允许本地连接(localhost),但代码里写了 127.0.0.1 或公网 IP
sudo systemctl status mysqlsudo systemctl status postgresql
登录数据库手动测试连接
确认 settings.py 里的 HOST 是 'localhost' 或 '127.0.0.1'
ImportError: No module named xxx1. 虚拟环境没激活就运行
2. pip 安装的包在另一个虚拟环境,当前激活的不是它
3. requirements.txt 漏写了这个包
which python 看 python 路径
echoVIRTUAL_ENV 看虚拟环境路径 pip list | grep xxx看包有没有
Gunicorn 启动就挂 systemctl 状态是 failed1. 配置文件语法错误 2. 虚拟环境路径不对 3. Python 代码本身在导入时就报错(比如数据库配置写错)sudo journalctl -u myproject.service -n 20看最近 20 行日志 手动在虚拟环境里执行启动命令,看具体报错 检查 gunicorn_config.py 里的路径
日志是你最好的朋友,养成习惯,一有问题先看:
# Nginx 错误日志tail -f /var/log/nginx/error.log# Nginx 访问日志tail -f /var/log/nginx/access.log# Gunicorn 错误日志(你在 gunicorn_config.py 里指定的)tail -f /home/deploy/apps/myproject/logs/error.log# Gunicorn 访问日志tail -f /home/deploy/apps/myproject/logs/access.log# systemd 服务日志sudo journalctl -u myproject.service -f

🎯 部署 Checklist 与总结

走完这 8000 多字的长文,你已经打通了从一台裸机 ECS 到能抗住并发、有 HTTPS、有数据库、有日志、有进程守护的完整 Python 生产环境。最后再帮你梳理一下核心步骤,下次部署时对着打勾即可:

  1. 购买 ECS:选好配置,务必配置安全组(开放 22, 80, 443)。


  2. SSH 登录:创建专用部署用户,不要全程 root。


  3. 编译 Python:用 altinstall或 PPA 安装指定版本,不替换系统 Python。

    阿里云Linux云服务器部署Python项目——从零到生产环境的完整实战指南


  4. 虚拟环境:每个项目独立 venv,pip 换国内源。


  5. 上传代码:SCP/Git/rsync 三选一,用 Git 最优雅。


  6. 装依赖:在激活的虚拟环境中 pip install -r requirements.txt。


  7. Gunicorn 启动:写配置文件,绑 127.0.0.1:8000,绝不对公网开放 8000。


  8. Nginx 配置:80/443 接公网,proxy_pass 到 127.0.0.1:8000,处理好 static/media。


  9. 阿里云Linux云服务器部署Python项目——从零到生产环境的完整实战指南

  10. 进程守护:用 systemd 把 Gunicorn 做成服务,开机自启 + 失败重启。


  11. 数据库:MySQL/PostgreSQL 安装、建库、建专属用户,Python 里用环境变量或配置文件连接。


  12. HTTPS:Certbot 自动申请 Let's Encrypt 证书,自动续期。


  13. 日志与监控:养成 journalctl和 tail -f看日志的习惯。


生产部署是一个系统工程,第一次做会觉得很琐碎,但一旦跑通,下次就是 10 分钟的事。你现在已经拥有了一个可扩展、可维护、有安全基线的基础设施。接下来你可以在此基础上做更多事:加 Redis 缓存、上 Docker 容器化、用 CI/CD 自动部署、接入 ELK 日志分析、配置监控告警……但那是另一个故事了。祝你部署顺利,一次成功!

🤔 简单问与答


  1. 为什么一定要用 Nginx + Gunicorn,而不能直接用 python app.py或 runserver? 因为 Flask/Django 自带的服务器是单线程同步模型,性能极差,且没有任何生产级特性(如进程管理、优雅重启、负载均衡)。Gunicorn 是 WSGI HTTP 服务器,专门为生产环境设计,支持多进程/多线程。Nginx 负责处理静态文件、SSL 卸载、负载均衡、防 DDoS 等,让 Gunicorn 专心处理动态请求。


  2. 阿里云Linux云服务器部署Python项目——从零到生产环境的完整实战指南

  3. 为什么一定要用虚拟环境? 虚拟环境让你为每个项目隔离 Python 包依赖。项目 A 用 Django 4.0,项目 B 用 Django 3.2,如果没有虚拟环境,你会在 pip 升级降级中崩溃。虚拟环境是 Python 项目隔离的基石。


  4. 为什么在 Nginx 配置里,Gunicorn 绑定 127.0.0.1 而不是 0.0.0.0? 安全考虑。127.0.0.1 是本地回环地址,只有本机(即 Nginx)能访问。如果你绑 0.0.0.0,意味着公网可以直接访问 8000 端口,绕过了 Nginx 的安全防护和静态文件处理。


  5. 阿里云安全组和服务器内部的防火墙(ufw/iptables)是什么关系? 阿里云安全组是云平台层面的网络 ACL,优先级最高,流量先过它。如果安全组没放行端口,流量根本到不了你的服务器。服务器内部的 ufw/iptables 是操作系统层的防火墙。两者可以叠加使用,但生产环境通常只在安全组做控制,服务器内部防火墙默认全开,避免配置冲突。


  6. systemd 和 Supervisor 选哪个? 如果服务器是较新的 Linux 发行版(Ubuntu 16.04+、CentOS 7+),优先用 systemd,因为它是系统自带的进程管理器,与操作系统集成更好(日志统一到 journalctl,开机启动更可靠)。Supervisor 是 Python 写的第三方进程管理工具,配置更灵活,适合老系统或需要复杂进程管理场景。


  7. 部署完成后,怎么更新代码? 标准流程是:git pull拉代码 → 如果有数据库变更执行 python manage.py migrate(Django)→ 如果有静态文件变更执行 python manage.py collectstatic(Django)→ 最后 sudo systemctl restart myproject.service重启 Gunicorn 进程。建议把这套流程写成 shell 脚本或交给 CI/CD 工具。


相关文章

买阿里云服务器能便宜吗?十年代理揭秘 3 大省钱攻略!

买阿里云服务器能便宜吗?十年代理揭秘 3 大省钱攻略!

作为深耕阿里云代理领域 10 年的 “老司机”,经常被问到:“买阿里云服务器能便宜吗?有没有优惠价格?” 今天就用实打实的行业经验告诉你:不仅能便宜,选对渠道还能省一大笔! 这篇文章带你解锁阿里云服务…

做了 10 年腾讯云代理,我想跟你聊聊返佣那些事儿​

做了 10 年腾讯云代理,我想跟你聊聊返佣那些事儿​

最近总有朋友问我:“腾讯云有返点吗?腾讯云服务器能拿佣金不?返佣比例到底有多少?” 作为一个在腾讯云代理行业摸爬滚打了 10 年的 “老人”,今天就来跟大家好好…

阿里云代理商返佣机制深度解析:头部代理优势与企业合作策略

阿里云代理商返佣机制深度解析:头部代理优势与企业合作策略

阿里云代理商的核心价值定位1. 代理商的角色与职责阿里云代理商作为阿里云生态的核心合作伙伴,承担着双重核心职能:• 产品销售:负责推广销售阿里云全系列云产品,包括云服务器ECS、云数据库RDS、对象存…

阿里云代理商返佣机制深度解析:头部代理优势与企业合作策略

阿里云代理商返佣机制深度解析:头部代理优势与企业合作策略

01一、阿里云代理商的核心价值定位1. 代理商的角色与职责阿里云代理商作为阿里云生态的核心合作伙伴,承担着双重核心职能:• 产品销售:负责推广销售阿里云全系列云产品,包括云服务器ECS、云数据库RDS…

阿里云代理商有哪些?阿里云代理返点是真的么?

阿里云代理商有哪些?阿里云代理返点是真的么?

一,阿里云代理商基本介绍阿里云代理商通俗一点,就是指从事阿里云云服务器,云数据库等阿里云公有云产品销售的代理商,每销售一件阿里云公有云产品出去,阿里云给予该代理商一定比例的提成。在阿里云官方定义中,这…

2026阿里云代理商生态全解析:五级代理体系、返佣政策与企业上云指南

2026阿里云代理商生态全解析:五级代理体系、返佣政策与企业上云指南

一、阿里云五级代理体系:权益阶梯与合作价值1. 五级代理的核心权益差异阿里云构建了多层次的代理生态体系,涵盖全国总代理、区域核心代理、行业ISV(独立软件开发商)、金牌/银牌认证代理及标准代理五大核心…