2026年02月25日 星期三 阴

缘起

上午同事找我了两次,说我软件有问题。我听完需求,回到座位一看,我最新软件是好的。第二次是他不懂得配置软件。

我想了一下,以后提醒他们用最新软件好了,我在每次软件运行的时候添加软件版本检测。于是用AI花了一天的时间写完并部署到Pythonanywhere了。主要坑点是fastapi是asgi的,而Pythonanywhere是老牌站点,支持的是wsgi。AI引导我搞得乱七八糟,后来AI不经意发现官方文档,我要求AI遵循官方指南,AI才引导我部署成功。部署花了我60%的时间,所以写下此文记录一下。

说到免费的支持python的服务器,除了PythonAnywhere外,我觉得Render(今天没选是看到它好像有个间歇性休眠的问题)、Oracle Cloud Free Tier下次可以尝试一下。

今天还第一次感受了FastAPI,它自动支持swagger,感觉很好。我们要多接触一些现代化的东西,下面看正文:

最近在 PythonAnywhere 上部署 FastAPI 时踩了不少坑,最终通过官方的 ASGICommandLine 方案 成功解决了所有问题。本文将完整梳理部署流程,包括准备工作、具体步骤、常见问题及解决方案,帮助大家快速上手。

为什么选择 PythonAnywhere + FastAPI?

  • PythonAnywhere :免费、易用,适合部署小型 Python Web 应用,支持虚拟环境和自定义域名。
  • FastAPI :高性能、异步支持、自动生成 API 文档,是现代 Python Web 开发的热门选择。
  • 官方 ASGI 方案 :PythonAnywhere 提供的实验性 ASGI 部署方式,直接托管 uvicorn 运行 FastAPI,无需复杂的转发配置,稳定可靠。

参考文献PythonAnywhere ASGICommandLine 官方文档


准备工作

1. 注册 PythonAnywhere 账号

访问 PythonAnywhere 官网 注册免费账号,注册后会自动分配一个子域名(如 yourusername.pythonanywhere.com)。

2. 创建虚拟环境并安装依赖

打开 PythonAnywhere 的 Bash 终端,执行以下命令:

bash

运行

# 创建 Python 3.10 虚拟环境
mkvirtualenv my_venv --python=python3.10

# 激活虚拟环境
workon my_venv

# 安装 FastAPI 和 uvicorn
pip install "uvicorn[standard]" fastapi

# 安装项目依赖(根据你的项目补充)
pip install sqlalchemy python-multipart jinja2

3. 生成 API Token

官方 ASGI 方案需要通过 API Token 连接 PythonAnywhere,步骤如下:

  1. 点击右上角「Account」→「API token」;
  2. 点击「Create a new API token」;
  3. 复制生成的 token(格式类似 1234567890abcdef1234567890abcdef)。

在 Bash 终端配置 API Token:(根据官方指南,只需要生成token就行了,下面这步应该不需要。

bash运行

export PA_API_TOKEN="你的API_TOKEN"

具体部署步骤

1. 删除旧的 Web app(避免冲突)

如果之前在「Web」页面创建过旧的 WSGI 模式 app,先删除:

  1. 打开「Web」页面;
  2. 找到旧 app,点击底部「Delete web app」→ 确认删除。

2. 准备 FastAPI 项目

确保你的项目结构如下(以本文的 Pulse 项目为例):

plaintext

Pulse/
├── main.py          # FastAPI 主文件
├── templates/       # 模板目录
│   ├── login.html   # 登录页面
│   └── admin.html   # 后台页面
└── pulse.db         # 数据库文件(可选,会自动创建)

关键修改 :将 main.py 中的模板目录改为 绝对路径 (避免找不到模板):

python

运行

from fastapi.templating import Jinja2Templates

# 错误:相对路径,部署后会找不到模板,官方好像有说配置静态文件好像有问题,我就临时解决一下
# templates = Jinja2Templates(directory="templates")

# 正确:绝对路径,替换为你的项目实际路径
templates = Jinja2Templates(directory="/home/yourusername/tktools/app/Pulse/templates")

3. 用 pa 命令创建 ASGI 网站

在 Bash 终端执行( 替换 yourusername 为你的 PythonAnywhere 用户名 ):

bash

运行

# 激活虚拟环境
workon my_venv

# 创建 ASGI 网站
pa website create \
  --domain yourusername.pythonanywhere.com \
  --command '/home/yourusername/.virtualenvs/my_venv/bin/uvicorn --app-dir /home/yourusername/tktools/app/Pulse --uds ${DOMAIN_SOCKET} main:app'

命令详解

  • --domain:你的网站域名;
  • --command:启动命令,核心参数说明:
    • /home/yourusername/.virtualenvs/my_venv/bin/uvicorn:虚拟环境中 uvicorn 的绝对路径;
    • --app-dir:FastAPI 项目的根目录(main.py 所在目录);
    • --uds ${DOMAIN_SOCKET}:官方要求的 Unix Socket 监听方式, 禁止替换为 --bind 端口模式
    • main:app:FastAPI 实例入口,对应 main.pyapp = FastAPI() 的实例名。

4. 验证网站创建成功

执行以下命令查看已创建的 ASGI 网站:

bash

运行

pa website get

终端输出你的域名和启动命令,即代表创建成功。

5. 重启并验证部署结果

bash

运行

# 重启网站,加载最新代码
pa website reload --domain yourusername.pythonanywhere.com

# 查看启动日志,确认服务正常运行
tail -50 /var/log/yourusername.pythonanywhere.com.server.log

成功启动日志示例

plaintext

INFO:     Started server process [1]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on unix socket /var/sockets/yourusername.pythonanywhere.com/app.sock (Press CTRL+C to quit)

访问以下地址验证功能:

  • FastAPI 自动文档:https://yourusername.pythonanywhere.com/docs
  • 自定义页面:https://yourusername.pythonanywhere.com/login
  • 健康检查接口:https://yourusername.pythonanywhere.com/health

常见问题及解决方案

1. 模板找不到报错:jinja2.exceptions.TemplateNotFound: login.html

核心原因Jinja2Templates 使用了相对路径,--app-dir 启动时无法正确定位模板目录。

解决方案 :将模板目录路径改为服务器上的 绝对路径 ,参考上文「准备 FastAPI 项目」部分的代码修改。

2. hypercorn 导入错误:ModuleNotFoundError: No module named 'hypercorn.wsgi'

核心原因 :hypercorn 版本适配问题,或 WSGI 转 ASGI 方案的兼容性缺陷。

解决方案 :放弃 hypercorn 适配方案,直接使用本文推荐的官方 ASGICommandLine 原生 uvicorn 部署方案,无需任何适配层。

3. 日志中仍出现旧的 uWSGI 启动信息

核心原因 :旧的 WSGI 模式 Web app 未完全删除,域名被占用。

解决方案 :进入「Web」页面,确认所有旧 app 已删除,重新执行 pa website create 命令创建 ASGI 网站。

4. ASGI 网站不在「Web」页面显示

核心原因 :官方明确说明 ASGI 部署为实验性功能,暂不支持在 Web 页面可视化管理。

解决方案 :正常现象,无需处理。所有管理操作通过 pa 命令行完成,直接访问域名即可使用服务。

5. 修改代码后不生效

核心原因 :代码修改后未重启 ASGI 网站,服务仍运行旧版本代码。

解决方案 :执行 pa website reload --domain yourusername.pythonanywhere.com 重启服务,加载最新代码。


常用 pa 命令汇总

表格

操作 命令
查看所有 ASGI 网站 pa website get
查看指定网站详情 pa website get --domain yourusername.pythonanywhere.com
重启网站(更新代码) pa website reload --domain yourusername.pythonanywhere.com
删除网站 pa website delete --domain yourusername.pythonanywhere.com
为自定义域名申请 SSL 证书 pa website create-autorenew-cert --domain yourcustomdomain.com

总结

PythonAnywhere 的 ASGICommandLine 方案 是部署 FastAPI 的最优选择,它:

  • ✅ 无需复杂的 WSGI 转发 / 适配代码,原生支持 ASGI 应用;
  • ✅ 直接托管 uvicorn 进程,无端口冲突、协议兼容问题;
  • ✅ 完整支持 FastAPI 异步特性、模板渲染、接口文档等所有功能;
  • ✅ 免费账号即可使用,无额外配置门槛。

只要按照本文的步骤操作,重点注意模板路径使用绝对路径,就能快速完成 FastAPI 的部署上线。

官方参考文档PythonAnywhere ASGICommandLine 官方文档

真实记录

以上是 AI 生成的,下面文字是自己的真实记录:

  1. 注册 PythonAnywhere,选择 free 账号并激活。

  2. 登录后,进入 Account → API token,创建 API TOKEN。

    创建就行了,不用在 Bash 里显式调用(除非碰到文末提到的报错)。

  3. 把项目 zip 压缩包上传到目标目录,例如:

    /home/YOURUSERNAME/tktools/app/Pulse

  4. 打开 Consoles,选择 Bash,依次执行下面这些命令。

    创建虚拟环境(我用的是和本地一样的 3.13,注意老账户好像还是 3.10):

    mkvirtualenv my_venv --python=python3.13
    

    安装 pythonanywhere(主要是为了使用 pa 命令,部分错误可忽略):

    pip install --upgrade pythonanywhere
    

    安装 FastAPI 和 uvicorn:

    pip install "uvicorn[standard]" fastapi
    

    解压上传的项目压缩包:

    cd /home/YOURUSERNAME/tktools/app/Pulse
    unzip Pulse.zip
    
  5. 官方给的 main.py 示例大致如下(用于快速验证环境):

    from fastapi import FastAPI
    
    app = FastAPI()
    
    @app.get("/")
    async def root():
        return {"message": "Hello from FastAPI"}
    
  6. 安装项目依赖:

    pip install -r requirements.txt
    
  7. 特别提醒:如果是部署在公网服务器,建议关闭 docs_urlredoc_url; 另外,由于 ASGI 部署的关系,在 PythonAnywhere 上静态文件/模板目录也要强行指定绝对路径,否则容易 404。

    可以参考类似下面的写法(根据自己项目调整):

    DEBUG = False
    
    if DEBUG:
        app = FastAPI(title="Pulse", version="0.1.0")
        templates = Jinja2Templates(directory="templates")
    else:
        app = FastAPI(
            title="Pulse",
            version="0.1.0",
            docs_url=None,   # 关闭对外暴露的 Swagger /docs
            redoc_url=None,  # 关闭 ReDoc 文档
        )
        # 模板目录(替换为你自己的绝对路径)
        templates = Jinja2Templates(directory="/home/yourusername/tktools/app/Pulse/templates")
    
  8. 使用 pa 创建 ASGI 网站(命令与前文一致,这里再贴一次方便对照):

    pa website create \
      --domain yourusername.pythonanywhere.com \
      --command '/home/yourusername/.virtualenvs/my_venv/bin/uvicorn --app-dir /home/yourusername/tktools/app/Pulse --uds ${DOMAIN_SOCKET} main:app'
    
  9. 如果 Bash Console 是在创建 API token 之前开的,可能会报错提示没有 token。

    解决方案:

    • 要么关掉当前 Bash,重新开一个;

    • 要么手动导出环境变量:

      export PA_API_TOKEN="你的API_TOKEN"
      

    重新打开 Bash 后记得先激活虚拟环境:

    workon my_venv
    
  10. 常用的 pa 操作命令:

    查看 website 运行状态:

    pa website get
    

    重启网站:

    pa website reload --domain yourusername.pythonanywhere.com
    

    查看日志(在 Web 页面里也可以点击可视化日志):

    tail -50 /var/log/yourusername.pythonanywhere.com.access.log
    tail -50 /var/log/yourusername.pythonanywhere.com.error.log
    tail -50 /var/log/yourusername.pythonanywhere.com.server.log
    

    删除网站:

    pa website delete --domain YOURUSERNAME.pythonanywhere.com
    

    支持 HTTPS(应该是自定义域名场景,free 账号一般用不到):

    pa website create-autorenew-cert --domain YOURCUSTOMDOMAIN
    
  11. 其他官方参考:

    https://help.pythonanywhere.com/pages/ASGICommandLine/