后端第九课:部署上线(把你的 FastAPI 后端真正跑起来给别人用)

👋 我是 Yulia,一线 AI 应用开发工程师:4 年工程经验,在职做大模型应用落地。

只写一件事------把最新 AI 技术讲成人话 + 给你能直接上手用的代码 (真实可验证,不搬运不注水)。

有用就点个 关注,持续更新大模型应用的前沿实战。
📚 本文是《后端开发从入门到靠谱》系列第 9 篇。第七、八课我们用 FastAPI + 数据库写出了一个有记忆的 AI 后端,但它还跑在本地 127.0.0.1:8000------只有你自己能访问。这一课把它部署上线,让全世界都能用。整个系列共 20 篇,从 0 基础一路到能独立写生产级后端。

你有没有这个疑问:代码明明在本地跑得好好的,为什么别人就是访问不到?本地浏览器打开 127.0.0.1:8000 一切正常,把链接发给朋友,对方却打不开。

这不是代码有问题,而是"本地运行"和"上线运行"是两回事。这一课把中间差的东西------服务器、反向代理、进程管理、容器化、云部署------一次讲透。

读完你会拿到:

  • 一个直觉模型:为什么 127.0.0.1 别人访问不到(内线电话 vs 公网号码)
  • 部署三要素:服务器 / 反向代理 / 进程管理(店铺类比,0 基础秒懂)
  • 生产环境的安全必修课:环境变量与密钥管理(别把 API Key 写进代码)
  • uvicorn 多进程 + Nginx 反向代理(原理 + 可直接用的配置)
  • Docker 容器化(镜像/容器类比 + Dockerfile + 一条命令跑起来)
  • 两条省事落地路线:云服务器 + 宝塔 / Docker 手动部署
  • 常见坑与避坑指南

先看全景图,建立全局认知:
#mermaid-svg-OlNaz6aBocQGAFlN{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-OlNaz6aBocQGAFlN .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-OlNaz6aBocQGAFlN .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-OlNaz6aBocQGAFlN .error-icon{fill:#552222;}#mermaid-svg-OlNaz6aBocQGAFlN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-OlNaz6aBocQGAFlN .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-OlNaz6aBocQGAFlN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OlNaz6aBocQGAFlN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OlNaz6aBocQGAFlN .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-OlNaz6aBocQGAFlN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OlNaz6aBocQGAFlN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OlNaz6aBocQGAFlN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-OlNaz6aBocQGAFlN .marker.cross{stroke:#333333;}#mermaid-svg-OlNaz6aBocQGAFlN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OlNaz6aBocQGAFlN p{margin:0;}#mermaid-svg-OlNaz6aBocQGAFlN .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-OlNaz6aBocQGAFlN .cluster-label text{fill:#333;}#mermaid-svg-OlNaz6aBocQGAFlN .cluster-label span{color:#333;}#mermaid-svg-OlNaz6aBocQGAFlN .cluster-label span p{background-color:transparent;}#mermaid-svg-OlNaz6aBocQGAFlN .label text,#mermaid-svg-OlNaz6aBocQGAFlN span{fill:#333;color:#333;}#mermaid-svg-OlNaz6aBocQGAFlN .node rect,#mermaid-svg-OlNaz6aBocQGAFlN .node circle,#mermaid-svg-OlNaz6aBocQGAFlN .node ellipse,#mermaid-svg-OlNaz6aBocQGAFlN .node polygon,#mermaid-svg-OlNaz6aBocQGAFlN .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-OlNaz6aBocQGAFlN .rough-node .label text,#mermaid-svg-OlNaz6aBocQGAFlN .node .label text,#mermaid-svg-OlNaz6aBocQGAFlN .image-shape .label,#mermaid-svg-OlNaz6aBocQGAFlN .icon-shape .label{text-anchor:middle;}#mermaid-svg-OlNaz6aBocQGAFlN .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-OlNaz6aBocQGAFlN .rough-node .label,#mermaid-svg-OlNaz6aBocQGAFlN .node .label,#mermaid-svg-OlNaz6aBocQGAFlN .image-shape .label,#mermaid-svg-OlNaz6aBocQGAFlN .icon-shape .label{text-align:center;}#mermaid-svg-OlNaz6aBocQGAFlN .node.clickable{cursor:pointer;}#mermaid-svg-OlNaz6aBocQGAFlN .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-OlNaz6aBocQGAFlN .arrowheadPath{fill:#333333;}#mermaid-svg-OlNaz6aBocQGAFlN .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-OlNaz6aBocQGAFlN .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-OlNaz6aBocQGAFlN .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OlNaz6aBocQGAFlN .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-OlNaz6aBocQGAFlN .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OlNaz6aBocQGAFlN .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-OlNaz6aBocQGAFlN .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-OlNaz6aBocQGAFlN .cluster text{fill:#333;}#mermaid-svg-OlNaz6aBocQGAFlN .cluster span{color:#333;}#mermaid-svg-OlNaz6aBocQGAFlN div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-OlNaz6aBocQGAFlN .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-OlNaz6aBocQGAFlN rect.text{fill:none;stroke-width:0;}#mermaid-svg-OlNaz6aBocQGAFlN .icon-shape,#mermaid-svg-OlNaz6aBocQGAFlN .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OlNaz6aBocQGAFlN .icon-shape p,#mermaid-svg-OlNaz6aBocQGAFlN .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-OlNaz6aBocQGAFlN .icon-shape .label rect,#mermaid-svg-OlNaz6aBocQGAFlN .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OlNaz6aBocQGAFlN .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-OlNaz6aBocQGAFlN .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-OlNaz6aBocQGAFlN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-OlNaz6aBocQGAFlN .blue>*{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-OlNaz6aBocQGAFlN .blue span{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-OlNaz6aBocQGAFlN .blue tspan{fill:#fff!important;}#mermaid-svg-OlNaz6aBocQGAFlN .orange>*{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-OlNaz6aBocQGAFlN .orange span{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-OlNaz6aBocQGAFlN .orange tspan{fill:#fff!important;}#mermaid-svg-OlNaz6aBocQGAFlN .green>*{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-OlNaz6aBocQGAFlN .green span{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-OlNaz6aBocQGAFlN .green tspan{fill:#fff!important;}#mermaid-svg-OlNaz6aBocQGAFlN .red>*{fill:#E15759!important;color:#fff!important;stroke:none!important;}#mermaid-svg-OlNaz6aBocQGAFlN .red span{fill:#E15759!important;color:#fff!important;stroke:none!important;}#mermaid-svg-OlNaz6aBocQGAFlN .red tspan{fill:#fff!important;}#mermaid-svg-OlNaz6aBocQGAFlN .cyan>*{fill:#76B7B2!important;color:#fff!important;stroke:none!important;}#mermaid-svg-OlNaz6aBocQGAFlN .cyan span{fill:#76B7B2!important;color:#fff!important;stroke:none!important;}#mermaid-svg-OlNaz6aBocQGAFlN .cyan tspan{fill:#fff!important;} HTTPS
转发请求
读取
用户浏览器
Nginx 反向代理
uvicorn 多进程
FastAPI 应用
数据库
环境变量 密钥

一、为什么本地能跑,别人却访问不到?

先搞清楚最基础、也最容易被忽略的问题。

127.0.0.1 是"本机回环地址",意思是"我自己" 。它像家里的内线电话 :只能自己打给自己,别人打不进来。当 uvicorn 默认监听 127.0.0.1 时,只有你本机能访问。
#mermaid-svg-ncjAhCnRf2HdHrBO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ncjAhCnRf2HdHrBO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ncjAhCnRf2HdHrBO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ncjAhCnRf2HdHrBO .error-icon{fill:#552222;}#mermaid-svg-ncjAhCnRf2HdHrBO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ncjAhCnRf2HdHrBO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ncjAhCnRf2HdHrBO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ncjAhCnRf2HdHrBO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ncjAhCnRf2HdHrBO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ncjAhCnRf2HdHrBO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ncjAhCnRf2HdHrBO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ncjAhCnRf2HdHrBO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ncjAhCnRf2HdHrBO .marker.cross{stroke:#333333;}#mermaid-svg-ncjAhCnRf2HdHrBO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ncjAhCnRf2HdHrBO p{margin:0;}#mermaid-svg-ncjAhCnRf2HdHrBO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ncjAhCnRf2HdHrBO .cluster-label text{fill:#333;}#mermaid-svg-ncjAhCnRf2HdHrBO .cluster-label span{color:#333;}#mermaid-svg-ncjAhCnRf2HdHrBO .cluster-label span p{background-color:transparent;}#mermaid-svg-ncjAhCnRf2HdHrBO .label text,#mermaid-svg-ncjAhCnRf2HdHrBO span{fill:#333;color:#333;}#mermaid-svg-ncjAhCnRf2HdHrBO .node rect,#mermaid-svg-ncjAhCnRf2HdHrBO .node circle,#mermaid-svg-ncjAhCnRf2HdHrBO .node ellipse,#mermaid-svg-ncjAhCnRf2HdHrBO .node polygon,#mermaid-svg-ncjAhCnRf2HdHrBO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ncjAhCnRf2HdHrBO .rough-node .label text,#mermaid-svg-ncjAhCnRf2HdHrBO .node .label text,#mermaid-svg-ncjAhCnRf2HdHrBO .image-shape .label,#mermaid-svg-ncjAhCnRf2HdHrBO .icon-shape .label{text-anchor:middle;}#mermaid-svg-ncjAhCnRf2HdHrBO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ncjAhCnRf2HdHrBO .rough-node .label,#mermaid-svg-ncjAhCnRf2HdHrBO .node .label,#mermaid-svg-ncjAhCnRf2HdHrBO .image-shape .label,#mermaid-svg-ncjAhCnRf2HdHrBO .icon-shape .label{text-align:center;}#mermaid-svg-ncjAhCnRf2HdHrBO .node.clickable{cursor:pointer;}#mermaid-svg-ncjAhCnRf2HdHrBO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ncjAhCnRf2HdHrBO .arrowheadPath{fill:#333333;}#mermaid-svg-ncjAhCnRf2HdHrBO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ncjAhCnRf2HdHrBO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ncjAhCnRf2HdHrBO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ncjAhCnRf2HdHrBO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ncjAhCnRf2HdHrBO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ncjAhCnRf2HdHrBO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ncjAhCnRf2HdHrBO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ncjAhCnRf2HdHrBO .cluster text{fill:#333;}#mermaid-svg-ncjAhCnRf2HdHrBO .cluster span{color:#333;}#mermaid-svg-ncjAhCnRf2HdHrBO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ncjAhCnRf2HdHrBO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ncjAhCnRf2HdHrBO rect.text{fill:none;stroke-width:0;}#mermaid-svg-ncjAhCnRf2HdHrBO .icon-shape,#mermaid-svg-ncjAhCnRf2HdHrBO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ncjAhCnRf2HdHrBO .icon-shape p,#mermaid-svg-ncjAhCnRf2HdHrBO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ncjAhCnRf2HdHrBO .icon-shape .label rect,#mermaid-svg-ncjAhCnRf2HdHrBO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ncjAhCnRf2HdHrBO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ncjAhCnRf2HdHrBO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ncjAhCnRf2HdHrBO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-ncjAhCnRf2HdHrBO .blue>*{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-ncjAhCnRf2HdHrBO .blue span{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-ncjAhCnRf2HdHrBO .blue tspan{fill:#fff!important;}#mermaid-svg-ncjAhCnRf2HdHrBO .orange>*{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-ncjAhCnRf2HdHrBO .orange span{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-ncjAhCnRf2HdHrBO .orange tspan{fill:#fff!important;} 只有自己
全世界
127.0.0.1 内线电话
本机能访问
公网 IP 手机号
别人也能访问

要让别人访问,需要三样东西:

  1. 公网 IP(或域名):像"手机号",别人能通过它找到你的服务器;
  2. 监听 0.0.0.0:让应用监听服务器的所有网卡(而不是只监听本机);
  3. 放行端口 :云服务器的安全组/防火墙默认关着,要手动把 80(HTTP)等端口打开。

127.0.0.1 vs 0.0.0.0 :127.0.0.1 只监听本机回环,0.0.0.0 监听所有网络接口。上线部署时 uvicorn 要写成 --host 0.0.0.0,否则外面的请求根本进不来------这是新手部署的第一个坑。

二、部署三要素:服务器 / 反向代理 / 进程管理

用开店的类比,把部署要解决的三个问题讲清楚:
#mermaid-svg-nWnFDTwy6Zva17cP{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nWnFDTwy6Zva17cP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nWnFDTwy6Zva17cP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nWnFDTwy6Zva17cP .error-icon{fill:#552222;}#mermaid-svg-nWnFDTwy6Zva17cP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nWnFDTwy6Zva17cP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nWnFDTwy6Zva17cP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nWnFDTwy6Zva17cP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nWnFDTwy6Zva17cP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nWnFDTwy6Zva17cP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nWnFDTwy6Zva17cP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nWnFDTwy6Zva17cP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nWnFDTwy6Zva17cP .marker.cross{stroke:#333333;}#mermaid-svg-nWnFDTwy6Zva17cP svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nWnFDTwy6Zva17cP p{margin:0;}#mermaid-svg-nWnFDTwy6Zva17cP .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nWnFDTwy6Zva17cP .cluster-label text{fill:#333;}#mermaid-svg-nWnFDTwy6Zva17cP .cluster-label span{color:#333;}#mermaid-svg-nWnFDTwy6Zva17cP .cluster-label span p{background-color:transparent;}#mermaid-svg-nWnFDTwy6Zva17cP .label text,#mermaid-svg-nWnFDTwy6Zva17cP span{fill:#333;color:#333;}#mermaid-svg-nWnFDTwy6Zva17cP .node rect,#mermaid-svg-nWnFDTwy6Zva17cP .node circle,#mermaid-svg-nWnFDTwy6Zva17cP .node ellipse,#mermaid-svg-nWnFDTwy6Zva17cP .node polygon,#mermaid-svg-nWnFDTwy6Zva17cP .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nWnFDTwy6Zva17cP .rough-node .label text,#mermaid-svg-nWnFDTwy6Zva17cP .node .label text,#mermaid-svg-nWnFDTwy6Zva17cP .image-shape .label,#mermaid-svg-nWnFDTwy6Zva17cP .icon-shape .label{text-anchor:middle;}#mermaid-svg-nWnFDTwy6Zva17cP .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nWnFDTwy6Zva17cP .rough-node .label,#mermaid-svg-nWnFDTwy6Zva17cP .node .label,#mermaid-svg-nWnFDTwy6Zva17cP .image-shape .label,#mermaid-svg-nWnFDTwy6Zva17cP .icon-shape .label{text-align:center;}#mermaid-svg-nWnFDTwy6Zva17cP .node.clickable{cursor:pointer;}#mermaid-svg-nWnFDTwy6Zva17cP .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nWnFDTwy6Zva17cP .arrowheadPath{fill:#333333;}#mermaid-svg-nWnFDTwy6Zva17cP .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nWnFDTwy6Zva17cP .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nWnFDTwy6Zva17cP .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nWnFDTwy6Zva17cP .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nWnFDTwy6Zva17cP .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nWnFDTwy6Zva17cP .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nWnFDTwy6Zva17cP .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nWnFDTwy6Zva17cP .cluster text{fill:#333;}#mermaid-svg-nWnFDTwy6Zva17cP .cluster span{color:#333;}#mermaid-svg-nWnFDTwy6Zva17cP div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nWnFDTwy6Zva17cP .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nWnFDTwy6Zva17cP rect.text{fill:none;stroke-width:0;}#mermaid-svg-nWnFDTwy6Zva17cP .icon-shape,#mermaid-svg-nWnFDTwy6Zva17cP .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nWnFDTwy6Zva17cP .icon-shape p,#mermaid-svg-nWnFDTwy6Zva17cP .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nWnFDTwy6Zva17cP .icon-shape .label rect,#mermaid-svg-nWnFDTwy6Zva17cP .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nWnFDTwy6Zva17cP .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nWnFDTwy6Zva17cP .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nWnFDTwy6Zva17cP :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-nWnFDTwy6Zva17cP .blue>*{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-nWnFDTwy6Zva17cP .blue span{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-nWnFDTwy6Zva17cP .blue tspan{fill:#fff!important;}#mermaid-svg-nWnFDTwy6Zva17cP .orange>*{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-nWnFDTwy6Zva17cP .orange span{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-nWnFDTwy6Zva17cP .orange tspan{fill:#fff!important;}#mermaid-svg-nWnFDTwy6Zva17cP .green>*{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-nWnFDTwy6Zva17cP .green span{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-nWnFDTwy6Zva17cP .green tspan{fill:#fff!important;} 服务器 店铺
反向代理 前台
进程管理 店长

  1. 服务器 = 你的"店铺"。就是一台 24 小时开着的电脑(云服务器),代码跑在上面。
  2. 反向代理(Nginx) = "前台/门卫"。它守在门口(80 端口),接待所有访客,把请求转给后面干活的员工。这样你就不用把应用直接暴露在公网,更安全、也更好管理。
  3. 进程管理 = "店长"。保证"员工"(你的应用进程)一直在岗,万一挂了(崩溃)自动重启,而不是整个店关门。

三、生产环境安全:环境变量与密钥管理

上线前有个必须做的事:别把密钥写死在代码里。

python 复制代码
# ❌ 危险:API Key 硬编码在代码里
API_KEY = "sk-abcdefg123456"

# ✅ 正确:从环境变量读取
import os
API_KEY = os.environ.get("API_KEY")

为什么?因为代码一般会传到 Git 仓库 (GitHub/Gitee),一旦密钥写进代码,就等于把密钥公开了。GitHub 上每天都有爬虫在扫泄露的 API Key,几分钟内就可能被盗刷。

正确做法是把密钥放在环境变量 或独立的配置文件里(这个文件要加进 .gitignore,不提交):

bash 复制代码
# 在服务器上设置环境变量
export API_KEY="sk-你的密钥"

上线前先过一遍:代码里还有没有写死的密码、Key、数据库账号? 有就抽到环境变量里。

四、uvicorn 多进程 + Nginx 反向代理

这是标准的生产部署组合,理解它就掌握了部署的核心。

4.1 uvicorn 多进程

本地开发你用的 uvicorn main:app --reload 是单进程 + 热重载 ,方便开发。生产环境要去掉 --reload(它性能差),并开多个 worker 进程:

bash 复制代码
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4

--workers 4 的意思是启动 4 个进程同时处理请求。为什么需要多进程?回忆第六课讲的 GIL(全局解释器锁) :Python 一个进程同一时刻只能跑一个线程的 Python 代码,多线程对 CPU 密集任务帮助有限,但多进程能真正并行------4 个进程就能同时干 4 件事。

规则:CPU 密集型 用多进程(--workers),IO 密集型 (调大模型、查数据库)用异步(async def)。两者结合,就是 FastAPI 生产的正确姿势。

4.2 Nginx 反向代理

uvicorn 直接暴露在公网也行,但生产都会在前面加一层 Nginx。原因:

  1. 安全:应用躲在 Nginx 后面,只对 Nginx 暴露;
  2. 静态文件:Nginx 处理图片/前端文件比 Python 快得多;
  3. 负载均衡:Nginx 能把请求分发给多个后端进程;
  4. HTTPS:Nginx 统一处理证书加密。

#mermaid-svg-yBQYe5pMyPDDMdHE{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yBQYe5pMyPDDMdHE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yBQYe5pMyPDDMdHE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yBQYe5pMyPDDMdHE .error-icon{fill:#552222;}#mermaid-svg-yBQYe5pMyPDDMdHE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yBQYe5pMyPDDMdHE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yBQYe5pMyPDDMdHE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yBQYe5pMyPDDMdHE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yBQYe5pMyPDDMdHE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yBQYe5pMyPDDMdHE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yBQYe5pMyPDDMdHE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yBQYe5pMyPDDMdHE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yBQYe5pMyPDDMdHE .marker.cross{stroke:#333333;}#mermaid-svg-yBQYe5pMyPDDMdHE svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yBQYe5pMyPDDMdHE p{margin:0;}#mermaid-svg-yBQYe5pMyPDDMdHE .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yBQYe5pMyPDDMdHE .cluster-label text{fill:#333;}#mermaid-svg-yBQYe5pMyPDDMdHE .cluster-label span{color:#333;}#mermaid-svg-yBQYe5pMyPDDMdHE .cluster-label span p{background-color:transparent;}#mermaid-svg-yBQYe5pMyPDDMdHE .label text,#mermaid-svg-yBQYe5pMyPDDMdHE span{fill:#333;color:#333;}#mermaid-svg-yBQYe5pMyPDDMdHE .node rect,#mermaid-svg-yBQYe5pMyPDDMdHE .node circle,#mermaid-svg-yBQYe5pMyPDDMdHE .node ellipse,#mermaid-svg-yBQYe5pMyPDDMdHE .node polygon,#mermaid-svg-yBQYe5pMyPDDMdHE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yBQYe5pMyPDDMdHE .rough-node .label text,#mermaid-svg-yBQYe5pMyPDDMdHE .node .label text,#mermaid-svg-yBQYe5pMyPDDMdHE .image-shape .label,#mermaid-svg-yBQYe5pMyPDDMdHE .icon-shape .label{text-anchor:middle;}#mermaid-svg-yBQYe5pMyPDDMdHE .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yBQYe5pMyPDDMdHE .rough-node .label,#mermaid-svg-yBQYe5pMyPDDMdHE .node .label,#mermaid-svg-yBQYe5pMyPDDMdHE .image-shape .label,#mermaid-svg-yBQYe5pMyPDDMdHE .icon-shape .label{text-align:center;}#mermaid-svg-yBQYe5pMyPDDMdHE .node.clickable{cursor:pointer;}#mermaid-svg-yBQYe5pMyPDDMdHE .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yBQYe5pMyPDDMdHE .arrowheadPath{fill:#333333;}#mermaid-svg-yBQYe5pMyPDDMdHE .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yBQYe5pMyPDDMdHE .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yBQYe5pMyPDDMdHE .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yBQYe5pMyPDDMdHE .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yBQYe5pMyPDDMdHE .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yBQYe5pMyPDDMdHE .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yBQYe5pMyPDDMdHE .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yBQYe5pMyPDDMdHE .cluster text{fill:#333;}#mermaid-svg-yBQYe5pMyPDDMdHE .cluster span{color:#333;}#mermaid-svg-yBQYe5pMyPDDMdHE div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yBQYe5pMyPDDMdHE .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yBQYe5pMyPDDMdHE rect.text{fill:none;stroke-width:0;}#mermaid-svg-yBQYe5pMyPDDMdHE .icon-shape,#mermaid-svg-yBQYe5pMyPDDMdHE .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yBQYe5pMyPDDMdHE .icon-shape p,#mermaid-svg-yBQYe5pMyPDDMdHE .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yBQYe5pMyPDDMdHE .icon-shape .label rect,#mermaid-svg-yBQYe5pMyPDDMdHE .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yBQYe5pMyPDDMdHE .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yBQYe5pMyPDDMdHE .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yBQYe5pMyPDDMdHE :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-yBQYe5pMyPDDMdHE .blue>*{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-yBQYe5pMyPDDMdHE .blue span{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-yBQYe5pMyPDDMdHE .blue tspan{fill:#fff!important;}#mermaid-svg-yBQYe5pMyPDDMdHE .orange>*{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-yBQYe5pMyPDDMdHE .orange span{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-yBQYe5pMyPDDMdHE .orange tspan{fill:#fff!important;}#mermaid-svg-yBQYe5pMyPDDMdHE .green>*{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-yBQYe5pMyPDDMdHE .green span{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-yBQYe5pMyPDDMdHE .green tspan{fill:#fff!important;} 用户请求 80端口
Nginx
worker 1
worker 2
worker 3

一个最简 Nginx 配置(把 80 端口的请求转发给本机 8000 端口的 FastAPI):

nginx 复制代码
server {
    listen 80;
    server_name your-domain.com;

    location / {
        proxy_pass http://127.0.0.1:8000;   # 转给 FastAPI
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

proxy_pass 就是"反向代理"的核心:Nginx 收到请求,转手交给后面的 FastAPI,再把响应转回给用户。用户始终只跟 Nginx 打交道。

五、Docker 容器化:解决"我本地能跑,你那边不行"

部署最常见的一句抱怨是"我本地明明能跑,服务器上就报错"------因为两边的 Python 版本、依赖版本、系统环境不一样。Docker 就是来解决这个的。

一句话:Docker 把"代码 + 运行环境"打包成一个标准箱子,到哪都能原样打开。

两个核心概念:
#mermaid-svg-8YiHbeARpiK0q7lu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8YiHbeARpiK0q7lu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8YiHbeARpiK0q7lu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8YiHbeARpiK0q7lu .error-icon{fill:#552222;}#mermaid-svg-8YiHbeARpiK0q7lu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8YiHbeARpiK0q7lu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8YiHbeARpiK0q7lu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8YiHbeARpiK0q7lu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8YiHbeARpiK0q7lu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8YiHbeARpiK0q7lu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8YiHbeARpiK0q7lu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8YiHbeARpiK0q7lu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8YiHbeARpiK0q7lu .marker.cross{stroke:#333333;}#mermaid-svg-8YiHbeARpiK0q7lu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8YiHbeARpiK0q7lu p{margin:0;}#mermaid-svg-8YiHbeARpiK0q7lu .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8YiHbeARpiK0q7lu .cluster-label text{fill:#333;}#mermaid-svg-8YiHbeARpiK0q7lu .cluster-label span{color:#333;}#mermaid-svg-8YiHbeARpiK0q7lu .cluster-label span p{background-color:transparent;}#mermaid-svg-8YiHbeARpiK0q7lu .label text,#mermaid-svg-8YiHbeARpiK0q7lu span{fill:#333;color:#333;}#mermaid-svg-8YiHbeARpiK0q7lu .node rect,#mermaid-svg-8YiHbeARpiK0q7lu .node circle,#mermaid-svg-8YiHbeARpiK0q7lu .node ellipse,#mermaid-svg-8YiHbeARpiK0q7lu .node polygon,#mermaid-svg-8YiHbeARpiK0q7lu .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8YiHbeARpiK0q7lu .rough-node .label text,#mermaid-svg-8YiHbeARpiK0q7lu .node .label text,#mermaid-svg-8YiHbeARpiK0q7lu .image-shape .label,#mermaid-svg-8YiHbeARpiK0q7lu .icon-shape .label{text-anchor:middle;}#mermaid-svg-8YiHbeARpiK0q7lu .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8YiHbeARpiK0q7lu .rough-node .label,#mermaid-svg-8YiHbeARpiK0q7lu .node .label,#mermaid-svg-8YiHbeARpiK0q7lu .image-shape .label,#mermaid-svg-8YiHbeARpiK0q7lu .icon-shape .label{text-align:center;}#mermaid-svg-8YiHbeARpiK0q7lu .node.clickable{cursor:pointer;}#mermaid-svg-8YiHbeARpiK0q7lu .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8YiHbeARpiK0q7lu .arrowheadPath{fill:#333333;}#mermaid-svg-8YiHbeARpiK0q7lu .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8YiHbeARpiK0q7lu .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8YiHbeARpiK0q7lu .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8YiHbeARpiK0q7lu .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8YiHbeARpiK0q7lu .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8YiHbeARpiK0q7lu .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8YiHbeARpiK0q7lu .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8YiHbeARpiK0q7lu .cluster text{fill:#333;}#mermaid-svg-8YiHbeARpiK0q7lu .cluster span{color:#333;}#mermaid-svg-8YiHbeARpiK0q7lu div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8YiHbeARpiK0q7lu .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8YiHbeARpiK0q7lu rect.text{fill:none;stroke-width:0;}#mermaid-svg-8YiHbeARpiK0q7lu .icon-shape,#mermaid-svg-8YiHbeARpiK0q7lu .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8YiHbeARpiK0q7lu .icon-shape p,#mermaid-svg-8YiHbeARpiK0q7lu .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8YiHbeARpiK0q7lu .icon-shape .label rect,#mermaid-svg-8YiHbeARpiK0q7lu .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8YiHbeARpiK0q7lu .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8YiHbeARpiK0q7lu .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8YiHbeARpiK0q7lu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-8YiHbeARpiK0q7lu .blue>*{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-8YiHbeARpiK0q7lu .blue span{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-8YiHbeARpiK0q7lu .blue tspan{fill:#fff!important;}#mermaid-svg-8YiHbeARpiK0q7lu .orange>*{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-8YiHbeARpiK0q7lu .orange span{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-8YiHbeARpiK0q7lu .orange tspan{fill:#fff!important;} 构建
镜像 Image 菜谱
容器 Container 做出来的菜

  • 镜像(Image):像"菜谱/模具",定义了运行环境长什么样(装什么 Python 版本、装什么依赖)。
  • 容器(Container):像"按菜谱做出来的菜/用模具倒出来的成品",是真正在运行的实例。

用一个 Dockerfile(构建说明书)描述你的应用环境:

dockerfile 复制代码
FROM python:3.11-slim          # 基础镜像:带 Python 3.11
WORKDIR /app                    # 工作目录
COPY requirements.txt .
RUN pip install -r requirements.txt   # 装依赖
COPY . .                        # 把代码拷进去
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

构建镜像 + 运行容器(-p 80:8000 把服务器的 80 端口映射到容器的 8000 端口):

bash 复制代码
docker build -t myapp .        # 按 Dockerfile 构建镜像
docker run -d -p 80:8000 myapp # 后台运行容器

一条 docker run 命令,你的应用就在服务器上跑起来了------无论服务器是什么系统、装没装 Python,都一样。这就是 Docker 成为部署主流的原因。

六、两条省事落地路线

理论讲完,给你两条真正落地的路线:
#mermaid-svg-BuRnH0cLxGfcxnEC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BuRnH0cLxGfcxnEC .error-icon{fill:#552222;}#mermaid-svg-BuRnH0cLxGfcxnEC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BuRnH0cLxGfcxnEC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BuRnH0cLxGfcxnEC .marker.cross{stroke:#333333;}#mermaid-svg-BuRnH0cLxGfcxnEC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BuRnH0cLxGfcxnEC p{margin:0;}#mermaid-svg-BuRnH0cLxGfcxnEC .edge{stroke-width:3;}#mermaid-svg-BuRnH0cLxGfcxnEC .section--1 rect,#mermaid-svg-BuRnH0cLxGfcxnEC .section--1 path,#mermaid-svg-BuRnH0cLxGfcxnEC .section--1 circle,#mermaid-svg-BuRnH0cLxGfcxnEC .section--1 polygon,#mermaid-svg-BuRnH0cLxGfcxnEC .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .section--1 text{fill:#ffffff;}#mermaid-svg-BuRnH0cLxGfcxnEC .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-depth--1{stroke-width:17;}#mermaid-svg-BuRnH0cLxGfcxnEC .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled circle,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:lightgray;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:#efefef;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-0 rect,#mermaid-svg-BuRnH0cLxGfcxnEC .section-0 path,#mermaid-svg-BuRnH0cLxGfcxnEC .section-0 circle,#mermaid-svg-BuRnH0cLxGfcxnEC .section-0 polygon,#mermaid-svg-BuRnH0cLxGfcxnEC .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-BuRnH0cLxGfcxnEC .section-0 text{fill:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .node-icon-0{font-size:40px;color:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-depth-0{stroke-width:14;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled circle,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:lightgray;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:#efefef;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-1 rect,#mermaid-svg-BuRnH0cLxGfcxnEC .section-1 path,#mermaid-svg-BuRnH0cLxGfcxnEC .section-1 circle,#mermaid-svg-BuRnH0cLxGfcxnEC .section-1 polygon,#mermaid-svg-BuRnH0cLxGfcxnEC .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .section-1 text{fill:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .node-icon-1{font-size:40px;color:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-depth-1{stroke-width:11;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled circle,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:lightgray;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:#efefef;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-2 rect,#mermaid-svg-BuRnH0cLxGfcxnEC .section-2 path,#mermaid-svg-BuRnH0cLxGfcxnEC .section-2 circle,#mermaid-svg-BuRnH0cLxGfcxnEC .section-2 polygon,#mermaid-svg-BuRnH0cLxGfcxnEC .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .section-2 text{fill:#ffffff;}#mermaid-svg-BuRnH0cLxGfcxnEC .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-depth-2{stroke-width:8;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled circle,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:lightgray;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:#efefef;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-3 rect,#mermaid-svg-BuRnH0cLxGfcxnEC .section-3 path,#mermaid-svg-BuRnH0cLxGfcxnEC .section-3 circle,#mermaid-svg-BuRnH0cLxGfcxnEC .section-3 polygon,#mermaid-svg-BuRnH0cLxGfcxnEC .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .section-3 text{fill:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .node-icon-3{font-size:40px;color:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-depth-3{stroke-width:5;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled circle,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:lightgray;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:#efefef;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-4 rect,#mermaid-svg-BuRnH0cLxGfcxnEC .section-4 path,#mermaid-svg-BuRnH0cLxGfcxnEC .section-4 circle,#mermaid-svg-BuRnH0cLxGfcxnEC .section-4 polygon,#mermaid-svg-BuRnH0cLxGfcxnEC .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .section-4 text{fill:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .node-icon-4{font-size:40px;color:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-depth-4{stroke-width:2;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled circle,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:lightgray;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:#efefef;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-5 rect,#mermaid-svg-BuRnH0cLxGfcxnEC .section-5 path,#mermaid-svg-BuRnH0cLxGfcxnEC .section-5 circle,#mermaid-svg-BuRnH0cLxGfcxnEC .section-5 polygon,#mermaid-svg-BuRnH0cLxGfcxnEC .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .section-5 text{fill:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .node-icon-5{font-size:40px;color:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-depth-5{stroke-width:-1;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled circle,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:lightgray;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:#efefef;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-6 rect,#mermaid-svg-BuRnH0cLxGfcxnEC .section-6 path,#mermaid-svg-BuRnH0cLxGfcxnEC .section-6 circle,#mermaid-svg-BuRnH0cLxGfcxnEC .section-6 polygon,#mermaid-svg-BuRnH0cLxGfcxnEC .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .section-6 text{fill:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .node-icon-6{font-size:40px;color:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-depth-6{stroke-width:-4;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled circle,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:lightgray;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:#efefef;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-7 rect,#mermaid-svg-BuRnH0cLxGfcxnEC .section-7 path,#mermaid-svg-BuRnH0cLxGfcxnEC .section-7 circle,#mermaid-svg-BuRnH0cLxGfcxnEC .section-7 polygon,#mermaid-svg-BuRnH0cLxGfcxnEC .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .section-7 text{fill:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .node-icon-7{font-size:40px;color:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-depth-7{stroke-width:-7;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled circle,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:lightgray;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:#efefef;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-8 rect,#mermaid-svg-BuRnH0cLxGfcxnEC .section-8 path,#mermaid-svg-BuRnH0cLxGfcxnEC .section-8 circle,#mermaid-svg-BuRnH0cLxGfcxnEC .section-8 polygon,#mermaid-svg-BuRnH0cLxGfcxnEC .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .section-8 text{fill:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .node-icon-8{font-size:40px;color:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-depth-8{stroke-width:-10;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled circle,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:lightgray;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:#efefef;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-9 rect,#mermaid-svg-BuRnH0cLxGfcxnEC .section-9 path,#mermaid-svg-BuRnH0cLxGfcxnEC .section-9 circle,#mermaid-svg-BuRnH0cLxGfcxnEC .section-9 polygon,#mermaid-svg-BuRnH0cLxGfcxnEC .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .section-9 text{fill:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .node-icon-9{font-size:40px;color:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-depth-9{stroke-width:-13;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled circle,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:lightgray;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:#efefef;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-10 rect,#mermaid-svg-BuRnH0cLxGfcxnEC .section-10 path,#mermaid-svg-BuRnH0cLxGfcxnEC .section-10 circle,#mermaid-svg-BuRnH0cLxGfcxnEC .section-10 polygon,#mermaid-svg-BuRnH0cLxGfcxnEC .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .section-10 text{fill:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .node-icon-10{font-size:40px;color:black;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .edge-depth-10{stroke-width:-16;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled circle,#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:lightgray;}#mermaid-svg-BuRnH0cLxGfcxnEC .disabled text{fill:#efefef;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-root rect,#mermaid-svg-BuRnH0cLxGfcxnEC .section-root path,#mermaid-svg-BuRnH0cLxGfcxnEC .section-root circle,#mermaid-svg-BuRnH0cLxGfcxnEC .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-BuRnH0cLxGfcxnEC .section-root text{fill:#ffffff;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-root span{color:#ffffff;}#mermaid-svg-BuRnH0cLxGfcxnEC .section-2 span{color:#ffffff;}#mermaid-svg-BuRnH0cLxGfcxnEC .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-BuRnH0cLxGfcxnEC .edge{fill:none;}#mermaid-svg-BuRnH0cLxGfcxnEC .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-BuRnH0cLxGfcxnEC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 部署路线
路线一 宝塔面板
云服务器
装宝塔
一键部署
路线二 Docker
Dockerfile
构建镜像
跑容器

路线一:云服务器 + 宝塔面板(最省事,新手首选)

  1. 阿里云 / 腾讯云买一台云服务器(学生机、轻量应用服务器最便宜);
  2. 装宝塔面板(一个网页版服务器管理工具,装好后在浏览器里点点鼠标就能装 Nginx、Python、部署);
  3. 在宝塔里创建站点、上传代码、配置 Nginx,几乎不用敲命令。

路线二:Docker + Nginx(更专业,可迁移)

  1. 写好 Dockerfile,docker build 出镜像;
  2. docker run -p 80:8000 跑起来;
  3. 需要时再在前面加 Nginx 做反向代理和 HTTPS。

建议:先走路线一,快速体验到"上线"的成就感;等熟悉了,再学路线二,掌握更专业的容器化部署。

七、常见坑与避坑指南

坑 原因 解决方案
别人访问不了 uvicorn 监听 127.0.0.1 改成 --host 0.0.0.0
端口不通 云服务器安全组没放行 在安全组里放行 80/8000 端口
密钥泄露 API Key 写进代码并提交了 Git 抽到环境变量,.gitignore 排除配置文件
服务一关就停 没做进程管理 用 --workers + 系统服务/宝塔守护进程
服务器报"依赖不存在" 环境不一致 用 Docker 统一环境
忘记 --workers 单进程扛不住并发 生产开多进程

总结:一张图带走

这课的核心,一句话串起来:

  • 本地跑 ≠ 上线跑 :127.0.0.1 是内线电话,只有自己能访问;上线要公网 IP + 0.0.0.0 + 放行端口。
  • 部署三要素:服务器(店铺)+ 反向代理(前台 Nginx)+ 进程管理(店长,挂了自动重启)。
  • 安全第一:密钥放环境变量,别写进代码提交到 Git。
  • 标准组合 :uvicorn --workers 4(多进程并行)+ Nginx(反向代理/静态文件/HTTPS)。
  • Docker 解决环境不一致 :镜像 = 菜谱,容器 = 做出来的菜,一条 docker run 到处能跑。
  • 省事路线:新手用云服务器 + 宝塔,进阶用 Docker + Nginx。

后端第九课:部署上线(把你的 FastAPI 后端真正跑起来给别人用)

三个立即可用的行动:

  1. 把第七、八课的 FastAPI 项目,用 uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4 跑起来,先让局域网里另一台设备能访问;
  2. 检查代码里有没有写死的 API Key,抽到环境变量里;
  3. 买一台最便宜的云服务器,走宝塔路线把你的后端真正部署上线,发给朋友一个链接。

后端第九课:部署上线(把你的 FastAPI 后端真正跑起来给别人用)


如果这篇对你有帮助,点个赞、收藏一下 ,下一篇我们讲 AI 应用后端架构------把前面学的串起来,看一个生产级 AI 应用后端到底长什么样。

关注我,这个系列共 20 篇:Python 语法 → FastAPI 实战 → 数据库 → 部署上线 → AI 应用后端架构,一路带你到能独立写生产级后端。

你部署时踩过什么坑?是安全组忘了放行端口,还是把 API Key 提交到了 GitHub 里?评论区聊聊,我挨个回。

(本文部署方案基于 Linux 云服务器 + Nginx + Docker 的标准实践,具体命令随版本略有差异,以官方文档为准,有变化评论区提醒我。)

相关推荐
云勤通1 小时前
智慧后勤系统哪家定制能力强
大数据·python
想七想八不如114081 小时前
元学习简单入门
人工智能·pytorch·python·深度学习·学习·机器学习
Zucker n1 小时前
一款适合研究生科研工作安排的日历
linux·数据库·python
尼给路达哟2 小时前
node(koa)和python(fastapi)面试
python·面试·fastapi
曲径海盗3 小时前
【Python 学习第 32 天】字符串基础
python·学习笔记·编程入门
田里的水稻4 小时前
PyTorch_torchvision---数据集下载\TensorBoard可视化
人工智能·pytorch·python·深度学习·机器学习
程序员正茂4 小时前
Win11使用自定义训练集训练ncnn模型
python·yolo·图像识别·移动端·ncnn
zwd20054 小时前
Manim 画布尺寸与像素换算详解:frame_width、frame_height、pixel_width 和画质参数(0.21.0 实测)
python·分辨率·manim·数学动画·frame_width·manim教程
最强小杰4 小时前
Claude Opus 4.8 调用报 529 怎么办?并发限制触发过载——退避策略与降级方案完整指南
运维·网络·python·ai