腾讯云 Ubuntu 24.04 + Docker 同时部署多个 Python Web 项目:没有域名也能用 IP 访问

腾讯云 Ubuntu 24.04 + Docker 同时部署多个 Python Web 项目:没有域名也能用 IP 访问

这篇文章整理的是一次真实部署过程。场景很常见:手里有一台腾讯云服务器,系统是 Ubuntu Server 24.04 LTS 64 位,镜像里已经预装了 Docker。暂时没有买域名,只有公网 IP,但又想让多个 Web 项目同时跑起来,并且都能访问。

我这次用的是"一个项目一个端口"的方式,适合课程项目、答辩项目、团队内部演示项目。等后面有域名了,再升级成 Nginx 反向代理、HTTPS、子域名访问。

一、这次要实现什么效果

服务器公网 IP:

text 复制代码
58.87.80.114

最终希望几个项目可以同时访问:

项目 访问地址 说明
health-middle http://58.87.80.114 占用服务器 80 端口
projectdream http://58.87.80.114:8002 占用服务器 8002 端口
ai-manga-2 http://58.87.80.114:8001 预留给另一个项目

注意,这里不是买了多个服务器,而是一台服务器跑多个项目

每个项目一个 Docker Compose,每个项目暴露不同的外部端口,就可以互不影响。

二、先登录服务器,检查 Docker 是否正常

登录服务器后,先不要急着启动项目,先确认自己在哪个目录、Docker 是否可用。

bash 复制代码
pwd
docker -v
docker compose version
ls

我这里看到的结果如下:

可以看到:

text 复制代码
当前目录:/home/ubuntu
Docker version 27.5.1
Docker Compose version v2.32.4

目录里已经有几个项目:

text 复制代码
ai-manga-2
health-middle
projectdream

这一步主要确认两件事:

  1. Docker 能用。
  2. 项目文件确实在服务器上。

如果 docker -vdocker compose version 没有输出版本号,就说明 Docker 环境还没配好,要先解决 Docker 安装问题。

三、统一整理项目目录

项目一多,如果都堆在 /home/ubuntu 下,后面会越来越乱。

我习惯统一放到:

text 复制代码
/opt/projects

先创建目录,并把权限交给当前的 ubuntu 用户:

bash 复制代码
sudo mkdir -p /opt/projects
sudo chown -R ubuntu:ubuntu /opt/projects

然后把项目移动进去:

bash 复制代码
mv ~/ai-manga-2 /opt/projects/
mv ~/health-middle /opt/projects/
mv ~/projectdream /opt/projects/

移动后检查:

bash 复制代码
ls /opt/projects

正常应该能看到:

text 复制代码
ai-manga-2  health-middle  projectdream

这样以后找项目就很清楚:

text 复制代码
/opt/projects/
├── ai-manga-2
├── health-middle
└── projectdream

四、先检查第一个项目 health-middle

进入项目目录:

bash 复制代码
cd /opt/projects/health-middle
ls
docker compose ps

我这里看到 health-middle 已经跑起来了:

重点看 STATUS

text 复制代码
backend   Up ... healthy
frontend  Up ... healthy

只要后端和前端都是 healthy,说明项目本身基本正常。

再看端口:

text 复制代码
0.0.0.0:80->8080/tcp

这句话的意思是:

text 复制代码
服务器的 80 端口  ->  容器内部的 8080 端口

所以浏览器访问:

text 复制代码
http://58.87.80.114

就会进入 health-middle 项目。

五、启动第二个项目 projectdream 时遇到的第一个问题

进入第二个项目:

bash 复制代码
cd /opt/projects/projectdream
ls
docker compose ps

这时候我遇到了一个报错:

text 复制代码
MYSQL_ROOT_PASSWORD is missing a value

大白话解释就是:

text 复制代码
docker-compose.yml 里要用 MYSQL_ROOT_PASSWORD,
但是 Docker Compose 没有读到这个变量。

这个问题非常常见,基本就是环境变量文件没读到。

六、重点讲一下 .env 和 .env.production

很多人第一次部署 Docker Compose 项目,最容易卡在这里。

1. 默认情况下,Docker Compose 会自动读取 .env

如果项目目录里有:

text 复制代码
.env

那通常直接执行:

bash 复制代码
docker compose up -d --build

Docker Compose 就能自动读取 .env 里的变量。

比如 .env 里写:

env 复制代码
MYSQL_ROOT_PASSWORD=换成自己的数据库root密码
MYSQL_DATABASE=projectdream
MYSQL_USER=projectdream
MYSQL_PASSWORD=换成自己的数据库用户密码
HTTP_PORT=8002

docker-compose.yml 里就可以这样用:

yaml 复制代码
environment:
  MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:?MYSQL_ROOT_PASSWORD is required}

2. 但 .env.production 不会被默认读取

我这个项目里不是 .env,而是:

text 复制代码
.env.production

可以通过下面命令查看:

bash 复制代码
ls -a

这里要注意:

text 复制代码
.env             默认会被 Docker Compose 自动读取
.env.production  不会自动读取,需要手动指定

所以如果项目使用 .env.production,启动时要这样写:

bash 复制代码
docker compose --env-file .env.production up -d --build

查看状态也要这样写:

bash 复制代码
docker compose --env-file .env.production ps

如果你嫌每次都写 --env-file .env.production 麻烦,也可以复制一份成 .env

bash 复制代码
cp .env.production .env
docker compose up -d --build

不过我更推荐保留 .env.production,这样一看就知道这是生产环境配置。

3. 怎么判断环境变量有没有配上

比如报错说:

text 复制代码
MYSQL_ROOT_PASSWORD is missing a value

那就检查:

bash 复制代码
grep MYSQL_ROOT_PASSWORD .env

如果你用的是 .env.production,就检查:

bash 复制代码
grep MYSQL_ROOT_PASSWORD .env.production

能看到类似下面这种就说明文件里有:

env 复制代码
MYSQL_ROOT_PASSWORD=换成自己的数据库root密码

如果没有输出,就说明变量没写进去。

4. 一个简单口诀

这块可以直接记住:

text 复制代码
文件叫 .env:docker compose 会自动读
文件不叫 .env:必须加 --env-file 文件名
变量缺失:先 grep 检查环境文件
端口冲突:优先改冒号左边
冒号右边:一般是容器内部端口,不要随便动

七、第二个问题:80 端口被占用了

环境变量解决后,再启动 projectdream

bash 复制代码
docker compose --env-file .env.production up -d --build

又遇到了一个新报错:

text 复制代码
Bind for 0.0.0.0:80 failed: port is already allocated

这个报错其实很好理解:

text 复制代码
health-middle 已经占用了服务器 80 端口,
projectdream 也想占用 80 端口,
一台服务器的同一个端口不能同时给两个项目用。

所以要给第二个项目换一个外部端口,比如:

text 复制代码
8002

八、怎么改项目访问端口

打开 projectdreamdocker-compose.yml

bash 复制代码
nano docker-compose.yml

我这里前端端口配置是这样的:

yaml 复制代码
ports:
  - "${HTTP_PORT:-80}:8080"

这句非常关键,拆开看:

text 复制代码
${HTTP_PORT:-80}  表示读取 HTTP_PORT,如果没配置就默认用 80
8080              表示容器内部前端服务监听 8080

也就是说:

yaml 复制代码
ports:
  - "${HTTP_PORT:-80}:8080"

如果 .env.production 里没有配置 HTTP_PORT,最终就等于:

yaml 复制代码
ports:
  - "80:8080"

这就会和 health-middle 冲突。

解决方法是编辑 .env.production

bash 复制代码
nano .env.production

加一行:

env 复制代码
HTTP_PORT=8002

保存后重新启动:

bash 复制代码
docker compose --env-file .env.production up -d
docker compose --env-file .env.production ps

如果看到类似:

text 复制代码
0.0.0.0:8002->8080/tcp

就说明端口映射成功了。

九、浏览器打不开 8002 是什么原因

项目启动后,我访问:

text 复制代码
http://58.87.80.114:8002

浏览器出现:

text 复制代码
ERR_CONNECTION_TIMED_OUT

这个时候先不要急着怀疑代码。

如果服务器里 docker compose ps 已经显示:

text 复制代码
0.0.0.0:8002->8080/tcp

但浏览器还是访问超时,最常见原因就是:

text 复制代码
腾讯云安全组没有放行 8002 端口。

去腾讯云控制台添加入站规则:

text 复制代码
协议端口:TCP:8002
来源:0.0.0.0/0
策略:允许

保存后再刷新:

text 复制代码
http://58.87.80.114:8002

基本就能访问了。

这里总结一下判断思路:

text 复制代码
浏览器超时
不是项目页面报错
而是浏览器根本没连到服务
优先检查:端口映射 + 云服务器安全组

十、常用 Docker Compose 命令

进入某个项目目录后使用。

1. 查看容器状态

bash 复制代码
docker compose ps

如果使用 .env.production

bash 复制代码
docker compose --env-file .env.production ps

2. 启动并重新构建

bash 复制代码
docker compose up -d --build

如果使用 .env.production

bash 复制代码
docker compose --env-file .env.production up -d --build

3. 停止项目

bash 复制代码
docker compose down

如果使用 .env.production

bash 复制代码
docker compose --env-file .env.production down

4. 查看日志

bash 复制代码
docker compose logs -f

只看前端:

bash 复制代码
docker compose logs -f frontend

只看后端:

bash 复制代码
docker compose logs -f backend

5. 重启项目

bash 复制代码
docker compose restart

十一、多项目部署时,我建议这样分配端口

没有域名时,最简单的方式就是:

text 复制代码
一个项目 = 一个端口

比如:

项目 外部端口 访问地址
health-middle 80 http://58.87.80.114
ai-manga-2 8001 http://58.87.80.114:8001
projectdream 8002 http://58.87.80.114:8002

注意:

text 复制代码
不同项目的外部端口不能重复。

如果两个项目都写:

yaml 复制代码
ports:
  - "80:8080"

一定会冲突。

正确做法是:

yaml 复制代码
ports:
  - "8001:8080"

或者:

yaml 复制代码
ports:
  - "8002:8080"

冒号左边是服务器端口,可以改。

冒号右边是容器内部端口,一般跟项目 Dockerfile 或 Nginx 配置有关,不懂的时候先别乱动。

十二、最后整理一份操作清单

以后成员照着这份顺序来就行。

1. 登录服务器

bash 复制代码
ssh ubuntu@服务器公网IP

2. 检查 Docker

bash 复制代码
docker -v
docker compose version

3. 创建统一项目目录

bash 复制代码
sudo mkdir -p /opt/projects
sudo chown -R ubuntu:ubuntu /opt/projects

4. 移动项目

bash 复制代码
mv ~/项目名 /opt/projects/

5. 进入项目

bash 复制代码
cd /opt/projects/项目名

6. 看有没有环境文件

bash 复制代码
ls -a

如果是 .env

bash 复制代码
docker compose up -d --build

如果是 .env.production

bash 复制代码
docker compose --env-file .env.production up -d --build

7. 如果提示变量缺失

bash 复制代码
grep 变量名 .env

或者:

bash 复制代码
grep 变量名 .env.production

8. 如果提示 80 端口冲突

去环境文件里加:

env 复制代码
HTTP_PORT=8002

然后重新启动:

bash 复制代码
docker compose --env-file .env.production up -d

9. 如果浏览器访问超时

检查两件事:

bash 复制代码
docker compose --env-file .env.production ps

看有没有:

text 复制代码
0.0.0.0:8002->8080/tcp

然后去腾讯云安全组放行:

text 复制代码
TCP:8002

十三、总结

这次部署下来,我感觉没有域名时,最稳的做法就是:

text 复制代码
一台服务器
多个项目目录
每个项目一个 docker-compose.yml
每个项目一个外部端口

不要一开始就上复杂的 Nginx 路径转发,特别是 Vue、React 这类前端项目,路径前缀一不注意就会出静态资源问题。

先用:

text 复制代码
http://服务器IP
http://服务器IP:8001
http://服务器IP:8002

把项目跑通。

等后面有域名了,再升级成:

text 复制代码
demo.xxx.com
api.xxx.com
admin.xxx.com

这样整个部署思路就清楚很多。

参考资料

  • Docker Compose 环境变量与 --env-filehttps://docs.docker.com/compose/how-tos/environment-variables/variable-interpolation/
  • Docker Compose 端口映射配置:https://docs.docker.com/reference/compose-file/services/#ports
相关推荐
Delta-delta3 小时前
win+ubuntu24.04双系统安装
ubuntu
szephyr3 小时前
腾讯云 ADP 智能体的 Skills 版本回滚总是回到旧配置,是缓存没清还是版本管理没开?
java·缓存·腾讯云
JavaPub-rodert3 小时前
我又把自己的 Go 后台管理系统升级了一遍:文件管理、2GB 上传、私有文件预览、Docker 镜像全安排上了
开发语言·docker·golang·shiyuadmin
爱码少年3 小时前
嗯,腾讯云个人小站Docker镜像下载功能已下线,压力给到阿里云镜像站
docker
Zhu7584 小时前
在docker环境部署frp
运维·docker·容器
淮北4946 小时前
ubuntu22 默认输入法调整频率
运维·服务器·git·ubuntu·elasticsearch
承渊政道7 小时前
飞牛NAS部署Immich:搭建家庭相册并实现远程访问
运维·服务器·docker·内网穿透·cpolar·nas·immich
十年磨一剑~7 小时前
CAAM不落盘存储密钥方式处理
linux·ubuntu
zhangrelay7 小时前
ROS 2 Lyrical 第2章 ROS 2系统架构与核心概念
linux·笔记·学习·ubuntu·ros2