当你拥有一个前后端分离的项目后下一步就是将它部署到云服务器上让所有人都能通过公网访问。本文将带你从购买阿里云 ECS 服务器开始到使用 Docker Compose 一键编排所有服务最终通过公网 IP 访问你的网站。整个过程循序渐进每一步都配有截图和解释。一、购买阿里云 ECS 云服务器1.1 选择服务器配置访问阿里云 ECS 购买页面https://ecs-buy.aliyun.com/ecs#/custom/prepay/cn-hangzhou根据你的需求选择合适的配置选型建议个人网站或小型项目一般选择 2 核 4G 即可满足需求后续不够可以随时升级。1.2 选择操作系统镜像这里选择你熟悉的 Linux 发行版推荐CentOS 7或Ubuntu 22.04。本文演示使用 Ubuntu 22.04。1.3 选择拓展程序阿里云提供了“拓展程序”选项可以在创建服务器时预装一些工具。为了后续部署方便我这里勾选了Docker已配置镜像加速这样服务器到手就能直接使用 Docker。为什么用 Docker 部署Docker 可以将应用及其依赖打包成容器实现“一次构建到处运行”避免了环境不一致的问题。后面我们会用 Docker Compose 一键编排所有服务。1.4 磁盘与备份系统盘和数据盘按需选择。个人网站默认配置即可不够用后续可以随时扩容。备份服务根据预算选择。1.5 公网 IP 与安全组非常重要一定要勾选“分配公网 IPv4 地址”否则你的服务器无法从外网访问。安全组相当于云端的防火墙后续我们会专门配置端口规则先使用默认即可。1.6 设置登录密码自定义一个 root 密码后续 SSH 远程连接需要用到。1.7 创建成功购买完成后在控制台就能看到你的服务器实例以及它的公网 IP。二、SSH 远程连接服务器使用 MobaXterm 或其他 SSH 工具连接服务器填入公网 IP 和刚才设置的密码。连接成功后先验证一下 Docker 是否已经就绪docker--version服务器准备工作到此完成下面开始用 Docker Compose 部署项目。三、项目文件准备这个非常重要能不能部署成功就看docker-compose.yml写的对不对这里用一个全栈单体项目暖屿Warm Isle作为示例技术栈为服务技术端口数据库MySQL 8.03306缓存Redis 7 Alpine6379消息队列RabbitMQ 3.135672 / 15672管理面板搜索引擎Elasticsearch 8.129200后端FastAPIPython8000前端Nginx Vue SPA803.1docker-compose.yml编排文件根据自己的项目情况进行编排一定不要照抄我的以下是完整的编排文件定义了所有服务、数据卷和网络# # 暖屿 (Warm Isle) — 完整容器编排基础设施 应用# # 一键启动全部服务:# docker-compose up -d## 服务清单:# mysql:8.0 → 3306 (关系型数据库)# redis:7-alpine → 6379 (缓存/会话/AI 计数器)# rabbitmq:3.13 → 5672 (消息队列) / 15672 (管理面板)# elasticsearch:8.12 → 9200 (全文搜索单节点)# backend → 8000 (FastAPI — 内部端口)# frontend → 80 (Nginx Vue SPA)# services:# ──────────────────────────────────────────────────────────────────# MySQL 8.0 — 关系型数据库# ──────────────────────────────────────────────────────────────────mysql:image:mysql:8.0container_name:warm-isle-mysqlrestart:unless-stoppedenvironment:MYSQL_ROOT_PASSWORD:${MYSQL_ROOT_PASSWORD:-root}MYSQL_DATABASE:${MYSQL_DATABASE:-warm_isle_db}ports:-${MYSQL_PORT:-3306}:3306volumes:-mysql_data:/var/lib/mysqlnetworks:-warm-isle-nethealthcheck:test:[CMD,mysqladmin,ping,-h,localhost]interval:10stimeout:5sretries:5# ──────────────────────────────────────────────────────────────────# Redis 7 Alpine — 缓存 会话# ──────────────────────────────────────────────────────────────────redis:image:redis:7-alpinecontainer_name:warm-isle-redisrestart:unless-stoppedports:-${REDIS_PORT:-6379}:6379volumes:-redis_data:/datanetworks:-warm-isle-nethealthcheck:test:[CMD,redis-cli,ping]interval:10stimeout:5sretries:5# ──────────────────────────────────────────────────────────────────# RabbitMQ 3.13 — 消息队列# ──────────────────────────────────────────────────────────────────rabbitmq:image:rabbitmq:3.13-managementcontainer_name:warm-isle-rabbitmqrestart:unless-stoppedports:-5672:5672-15672:15672networks:-warm-isle-nethealthcheck:test:[CMD,rabbitmq-diagnostics,check_port_connectivity]interval:10stimeout:5sretries:5# ──────────────────────────────────────────────────────────────────# Elasticsearch 8.12 — 全文搜索引擎# ──────────────────────────────────────────────────────────────────elasticsearch:image:elasticsearch:8.12.0container_name:warm-isle-esrestart:unless-stoppedenvironment:-discovery.typesingle-node-xpack.security.enabledfalse-ES_JAVA_OPTS-Xms512m -Xmx512mports:-9200:9200volumes:-es_data:/usr/share/elasticsearch/datanetworks:-warm-isle-nethealthcheck:test:[CMD-SHELL,curl -s http://localhost:9200/_cluster/health | grep -E green|yellow /dev/null,]interval:10stimeout:5sretries:10# ──────────────────────────────────────────────────────────────────# Backend — FastAPI 后端源码挂载 热重载# ──────────────────────────────────────────────────────────────────backend:build:./backendcontainer_name:warm-isle-backendrestart:unless-stoppedenv_file:-./backend/.envenvironment:-DATABASE_URLmysqlasyncmy://root:${MYSQL_ROOT_PASSWORD:-root}mysql:3306/${MYSQL_DATABASE:-warm_isle_db}-REDIS_URLredis://redis:6379/0-MQ_URLamqp://guest:guestrabbitmq:5672/-ES_HOSTShttp://elasticsearch:9200volumes:-./backend:/app-/app/__pycache__ports:-8000:8000depends_on:mysql:condition:service_healthyredis:condition:service_healthynetworks:-warm-isle-net# ──────────────────────────────────────────────────────────────────# Frontend — Nginx Vue SPA# ──────────────────────────────────────────────────────────────────frontend:build:./frontendcontainer_name:warm-isle-frontendrestart:unless-stoppedports:-80:80depends_on:-backendnetworks:-warm-isle-netvolumes:mysql_data:redis_data:es_data:networks:warm-isle-net:driver:bridge说明restart: unless-stopped确保服务异常退出或服务器重启后自动恢复。depends_on配合healthcheck确保数据库和缓存就绪后才启动后端。volumes将源码挂载到容器内配合--reload实现热更新。3.2 前端 Dockerfile多阶段构建# ══════════════════════════════════════════════════════ # 暖屿 (Warm Isle) — 前端 Dockerfile多阶段构建 # ══════════════════════════════════════════════════════ # ── 阶段 1: Node 构建 ───────────────────────────────── FROM node:22-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # ── 阶段 2: Nginx 运行 ─────────────────────────────── FROM nginx:1.27-alpine RUN rm -f /etc/nginx/conf.d/default.conf COPY nginx.conf /etc/nginx/conf.d/default.conf COPY --frombuilder /app/dist /usr/share/nginx/html EXPOSE 80 CMD [nginx, -g, daemon off;]为什么用多阶段构建构建阶段使用 Node 镜像编译运行阶段只保留轻量级 Nginx 镜像最终镜像体积大幅减小。3.3 后端 Dockerfile# ══════════════════════════════════════════════════════ # 暖屿 (Warm Isle) — 后端 Dockerfile # ══════════════════════════════════════════════════════ FROM python:3.12-slim WORKDIR /app # ── 系统依赖 ────────────────────────────────────────── RUN apt-get update apt-get install -y --no-install-recommends \ gcc default-libmysqlclient-dev pkg-config \ rm -rf /var/lib/apt/lists/* # ── Python 依赖 ────────────────────────────────────── COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt EXPOSE 8000 CMD [uvicorn, app.main:app, --host, 0.0.0.0, --port, 8000, --reload]--reload参数会监听文件变化并自动重启非常适合开发环境。四、上传项目到服务器推荐两种方式首选 Git Clone。方法一Git Clone推荐如果服务器上没有 Git先安装aptupdateaptinstallgit-y然后直接克隆仓库cd/optgitclone https://gitee.com/xcaiqq/warm-isle.gitcdwarm-isle后续代码更新只需git pull配合 Docker 的热挂载机制就能自动生效不需要重新上传。方法二SCP 打包上传适合项目还未推送到 Git 的情况# 本地打包排除 node_modulestar-czfwarm-isle.tar.gz\--excludenode_modules\--exclude__pycache__\--exclude*.pyc\--excludedist.# 传到服务器并解压scpwarm-isle.tar.gz root你的服务器IP:/opt/sshroot你的服务器IPcd /opt tar -xzf warm-isle.tar.gz -C warm-isle推荐方法一后续改代码直接git pull 热更新省时省力。五、一键启动项目进入服务器的项目目录你刚刚上传的项目位置执行dockercompose up-d-d表示后台运行。首次启动会构建镜像并拉取所有依赖耗时较长请耐心等待。如果遇到报错修改好代码后git pull再次执行docker compose up -d即可。Docker 会智能地利用缓存只重新构建变化的部分。常见问题pip 下载慢如果构建时从 PyPI 下载依赖很慢国内服务器常见可以在 Dockerfile 中指定国内 pip 镜像源RUN pip install --no-cache-dir -i https://mirrors.aliyun.com/pypi/simple/ -r requirements.txt六、查看日志确认启动状态dockercompose logs backend如果看到没有报错说明启动成功。七、配置阿里云安全组开放端口服务启动后还需要在阿里云控制台配置安全组规则才能从公网访问。7.1 进入安全组管理登录阿里云控制台 → ECS → 安全组找到你的服务器绑定的安全组。7.2 添加规则点击“添加规则”开放前端所需的80 端口HTTP入方向端口范围80/80授权对象0.0.0.0/0允许所有 IP 访问描述nginx添加完成后浏览器访问http://你的公网IP就能看到你的网站了。以通过公网 IP 访问。后续更新代码只需git pullDocker 会自动热更新非常方便
阿里云 ECS 购买 + Docker Compose 部署全栈项目完整指南
当你拥有一个前后端分离的项目后下一步就是将它部署到云服务器上让所有人都能通过公网访问。本文将带你从购买阿里云 ECS 服务器开始到使用 Docker Compose 一键编排所有服务最终通过公网 IP 访问你的网站。整个过程循序渐进每一步都配有截图和解释。一、购买阿里云 ECS 云服务器1.1 选择服务器配置访问阿里云 ECS 购买页面https://ecs-buy.aliyun.com/ecs#/custom/prepay/cn-hangzhou根据你的需求选择合适的配置选型建议个人网站或小型项目一般选择 2 核 4G 即可满足需求后续不够可以随时升级。1.2 选择操作系统镜像这里选择你熟悉的 Linux 发行版推荐CentOS 7或Ubuntu 22.04。本文演示使用 Ubuntu 22.04。1.3 选择拓展程序阿里云提供了“拓展程序”选项可以在创建服务器时预装一些工具。为了后续部署方便我这里勾选了Docker已配置镜像加速这样服务器到手就能直接使用 Docker。为什么用 Docker 部署Docker 可以将应用及其依赖打包成容器实现“一次构建到处运行”避免了环境不一致的问题。后面我们会用 Docker Compose 一键编排所有服务。1.4 磁盘与备份系统盘和数据盘按需选择。个人网站默认配置即可不够用后续可以随时扩容。备份服务根据预算选择。1.5 公网 IP 与安全组非常重要一定要勾选“分配公网 IPv4 地址”否则你的服务器无法从外网访问。安全组相当于云端的防火墙后续我们会专门配置端口规则先使用默认即可。1.6 设置登录密码自定义一个 root 密码后续 SSH 远程连接需要用到。1.7 创建成功购买完成后在控制台就能看到你的服务器实例以及它的公网 IP。二、SSH 远程连接服务器使用 MobaXterm 或其他 SSH 工具连接服务器填入公网 IP 和刚才设置的密码。连接成功后先验证一下 Docker 是否已经就绪docker--version服务器准备工作到此完成下面开始用 Docker Compose 部署项目。三、项目文件准备这个非常重要能不能部署成功就看docker-compose.yml写的对不对这里用一个全栈单体项目暖屿Warm Isle作为示例技术栈为服务技术端口数据库MySQL 8.03306缓存Redis 7 Alpine6379消息队列RabbitMQ 3.135672 / 15672管理面板搜索引擎Elasticsearch 8.129200后端FastAPIPython8000前端Nginx Vue SPA803.1docker-compose.yml编排文件根据自己的项目情况进行编排一定不要照抄我的以下是完整的编排文件定义了所有服务、数据卷和网络# # 暖屿 (Warm Isle) — 完整容器编排基础设施 应用# # 一键启动全部服务:# docker-compose up -d## 服务清单:# mysql:8.0 → 3306 (关系型数据库)# redis:7-alpine → 6379 (缓存/会话/AI 计数器)# rabbitmq:3.13 → 5672 (消息队列) / 15672 (管理面板)# elasticsearch:8.12 → 9200 (全文搜索单节点)# backend → 8000 (FastAPI — 内部端口)# frontend → 80 (Nginx Vue SPA)# services:# ──────────────────────────────────────────────────────────────────# MySQL 8.0 — 关系型数据库# ──────────────────────────────────────────────────────────────────mysql:image:mysql:8.0container_name:warm-isle-mysqlrestart:unless-stoppedenvironment:MYSQL_ROOT_PASSWORD:${MYSQL_ROOT_PASSWORD:-root}MYSQL_DATABASE:${MYSQL_DATABASE:-warm_isle_db}ports:-${MYSQL_PORT:-3306}:3306volumes:-mysql_data:/var/lib/mysqlnetworks:-warm-isle-nethealthcheck:test:[CMD,mysqladmin,ping,-h,localhost]interval:10stimeout:5sretries:5# ──────────────────────────────────────────────────────────────────# Redis 7 Alpine — 缓存 会话# ──────────────────────────────────────────────────────────────────redis:image:redis:7-alpinecontainer_name:warm-isle-redisrestart:unless-stoppedports:-${REDIS_PORT:-6379}:6379volumes:-redis_data:/datanetworks:-warm-isle-nethealthcheck:test:[CMD,redis-cli,ping]interval:10stimeout:5sretries:5# ──────────────────────────────────────────────────────────────────# RabbitMQ 3.13 — 消息队列# ──────────────────────────────────────────────────────────────────rabbitmq:image:rabbitmq:3.13-managementcontainer_name:warm-isle-rabbitmqrestart:unless-stoppedports:-5672:5672-15672:15672networks:-warm-isle-nethealthcheck:test:[CMD,rabbitmq-diagnostics,check_port_connectivity]interval:10stimeout:5sretries:5# ──────────────────────────────────────────────────────────────────# Elasticsearch 8.12 — 全文搜索引擎# ──────────────────────────────────────────────────────────────────elasticsearch:image:elasticsearch:8.12.0container_name:warm-isle-esrestart:unless-stoppedenvironment:-discovery.typesingle-node-xpack.security.enabledfalse-ES_JAVA_OPTS-Xms512m -Xmx512mports:-9200:9200volumes:-es_data:/usr/share/elasticsearch/datanetworks:-warm-isle-nethealthcheck:test:[CMD-SHELL,curl -s http://localhost:9200/_cluster/health | grep -E green|yellow /dev/null,]interval:10stimeout:5sretries:10# ──────────────────────────────────────────────────────────────────# Backend — FastAPI 后端源码挂载 热重载# ──────────────────────────────────────────────────────────────────backend:build:./backendcontainer_name:warm-isle-backendrestart:unless-stoppedenv_file:-./backend/.envenvironment:-DATABASE_URLmysqlasyncmy://root:${MYSQL_ROOT_PASSWORD:-root}mysql:3306/${MYSQL_DATABASE:-warm_isle_db}-REDIS_URLredis://redis:6379/0-MQ_URLamqp://guest:guestrabbitmq:5672/-ES_HOSTShttp://elasticsearch:9200volumes:-./backend:/app-/app/__pycache__ports:-8000:8000depends_on:mysql:condition:service_healthyredis:condition:service_healthynetworks:-warm-isle-net# ──────────────────────────────────────────────────────────────────# Frontend — Nginx Vue SPA# ──────────────────────────────────────────────────────────────────frontend:build:./frontendcontainer_name:warm-isle-frontendrestart:unless-stoppedports:-80:80depends_on:-backendnetworks:-warm-isle-netvolumes:mysql_data:redis_data:es_data:networks:warm-isle-net:driver:bridge说明restart: unless-stopped确保服务异常退出或服务器重启后自动恢复。depends_on配合healthcheck确保数据库和缓存就绪后才启动后端。volumes将源码挂载到容器内配合--reload实现热更新。3.2 前端 Dockerfile多阶段构建# ══════════════════════════════════════════════════════ # 暖屿 (Warm Isle) — 前端 Dockerfile多阶段构建 # ══════════════════════════════════════════════════════ # ── 阶段 1: Node 构建 ───────────────────────────────── FROM node:22-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # ── 阶段 2: Nginx 运行 ─────────────────────────────── FROM nginx:1.27-alpine RUN rm -f /etc/nginx/conf.d/default.conf COPY nginx.conf /etc/nginx/conf.d/default.conf COPY --frombuilder /app/dist /usr/share/nginx/html EXPOSE 80 CMD [nginx, -g, daemon off;]为什么用多阶段构建构建阶段使用 Node 镜像编译运行阶段只保留轻量级 Nginx 镜像最终镜像体积大幅减小。3.3 后端 Dockerfile# ══════════════════════════════════════════════════════ # 暖屿 (Warm Isle) — 后端 Dockerfile # ══════════════════════════════════════════════════════ FROM python:3.12-slim WORKDIR /app # ── 系统依赖 ────────────────────────────────────────── RUN apt-get update apt-get install -y --no-install-recommends \ gcc default-libmysqlclient-dev pkg-config \ rm -rf /var/lib/apt/lists/* # ── Python 依赖 ────────────────────────────────────── COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt EXPOSE 8000 CMD [uvicorn, app.main:app, --host, 0.0.0.0, --port, 8000, --reload]--reload参数会监听文件变化并自动重启非常适合开发环境。四、上传项目到服务器推荐两种方式首选 Git Clone。方法一Git Clone推荐如果服务器上没有 Git先安装aptupdateaptinstallgit-y然后直接克隆仓库cd/optgitclone https://gitee.com/xcaiqq/warm-isle.gitcdwarm-isle后续代码更新只需git pull配合 Docker 的热挂载机制就能自动生效不需要重新上传。方法二SCP 打包上传适合项目还未推送到 Git 的情况# 本地打包排除 node_modulestar-czfwarm-isle.tar.gz\--excludenode_modules\--exclude__pycache__\--exclude*.pyc\--excludedist.# 传到服务器并解压scpwarm-isle.tar.gz root你的服务器IP:/opt/sshroot你的服务器IPcd /opt tar -xzf warm-isle.tar.gz -C warm-isle推荐方法一后续改代码直接git pull 热更新省时省力。五、一键启动项目进入服务器的项目目录你刚刚上传的项目位置执行dockercompose up-d-d表示后台运行。首次启动会构建镜像并拉取所有依赖耗时较长请耐心等待。如果遇到报错修改好代码后git pull再次执行docker compose up -d即可。Docker 会智能地利用缓存只重新构建变化的部分。常见问题pip 下载慢如果构建时从 PyPI 下载依赖很慢国内服务器常见可以在 Dockerfile 中指定国内 pip 镜像源RUN pip install --no-cache-dir -i https://mirrors.aliyun.com/pypi/simple/ -r requirements.txt六、查看日志确认启动状态dockercompose logs backend如果看到没有报错说明启动成功。七、配置阿里云安全组开放端口服务启动后还需要在阿里云控制台配置安全组规则才能从公网访问。7.1 进入安全组管理登录阿里云控制台 → ECS → 安全组找到你的服务器绑定的安全组。7.2 添加规则点击“添加规则”开放前端所需的80 端口HTTP入方向端口范围80/80授权对象0.0.0.0/0允许所有 IP 访问描述nginx添加完成后浏览器访问http://你的公网IP就能看到你的网站了。以通过公网 IP 访问。后续更新代码只需git pullDocker 会自动热更新非常方便