docker-vps-2026
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDocker + VPS 2026 — Best Practices
2026年Docker + VPS 最佳实践
Docker Compose v2 (2026 Standard)
Docker Compose v2(2026年标准)
bash
undefinedbash
undefined✅ 2026 — Docker Compose v2 (built into Docker)
✅ 2026 — Docker Compose v2(Docker内置功能)
docker compose up -d
docker compose build
docker compose logs -f service-name
docker compose up -d
docker compose build
docker compose logs -f service-name
❌ Legacy v1 (deprecated, removed in 2024)
❌ 旧版v1(已弃用,2024年已移除)
docker-compose up # hyphenated — never use
undefineddocker-compose up # 带连字符 — 切勿使用
undefinedPython Container (uv-based, 2026)
Python容器(基于uv,2026年标准)
dockerfile
FROM python:3.12-slim-bookwormdockerfile
FROM python:3.12-slim-bookwormCopy uv from official image — always pin the version tag
从官方镜像复制uv — 务必固定版本标签
COPY --from=ghcr.io/astral-sh/uv:0.10.7 /uv /uvx /bin/
WORKDIR /app
COPY --from=ghcr.io/astral-sh/uv:0.10.7 /uv /uvx /bin/
WORKDIR /app
Layer cache: install deps before copying app code
层缓存:复制应用代码前先安装依赖
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-install-project --no-dev
COPY . .
RUN uv sync --frozen --no-dev
ENV PATH="/app/.venv/bin:$PATH"
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-install-project --no-dev
COPY . .
RUN uv sync --frozen --no-dev
ENV PATH="/app/.venv/bin:$PATH"
Never run as root
切勿以root身份运行
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser
CMD ["python", "-m", "api.main"]
undefinedRUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser
CMD ["python", "-m", "api.main"]
undefinedBrowser Automation Container (Xvfb + Camoufox)
浏览器自动化容器(Xvfb + Camoufox)
dockerfile
FROM python:3.12-slim-bookworm
COPY /uv /uvx /bin/dockerfile
FROM python:3.12-slim-bookworm
COPY /uv /uvx /bin/System deps for Firefox + virtual display
Firefox + 虚拟显示所需的系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends
xvfb x11vnc
libgtk-3-0 libdbus-glib-1-2 libxt6 libx11-xcb1
libxcomposite1 libxdamage1 libxfixes3 libxrandr2
libasound2 libpangocairo-1.0-0 libatk1.0-0
libatk-bridge2.0-0 libcups2 libdrm2 libgbm1
curl procps
&& rm -rf /var/lib/apt/lists/*
xvfb x11vnc
libgtk-3-0 libdbus-glib-1-2 libxt6 libx11-xcb1
libxcomposite1 libxdamage1 libxfixes3 libxrandr2
libasound2 libpangocairo-1.0-0 libatk1.0-0
libatk-bridge2.0-0 libcups2 libdrm2 libgbm1
curl procps
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-install-project --no-dev
RUN apt-get update && apt-get install -y --no-install-recommends
xvfb x11vnc
libgtk-3-0 libdbus-glib-1-2 libxt6 libx11-xcb1
libxcomposite1 libxdamage1 libxfixes3 libxrandr2
libasound2 libpangocairo-1.0-0 libatk1.0-0
libatk-bridge2.0-0 libcups2 libdrm2 libgbm1
curl procps
&& rm -rf /var/lib/apt/lists/*
xvfb x11vnc
libgtk-3-0 libdbus-glib-1-2 libxt6 libx11-xcb1
libxcomposite1 libxdamage1 libxfixes3 libxrandr2
libasound2 libpangocairo-1.0-0 libatk1.0-0
libatk-bridge2.0-0 libcups2 libdrm2 libgbm1
curl procps
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-install-project --no-dev
Download Camoufox Firefox binary
下载Camoufox Firefox二进制文件
⚠️ Verify the expected version in pyproject.toml; camoufox fetch downloads
⚠️ 请核对pyproject.toml中的预期版本;camoufox fetch会下载预编译的Firefox二进制文件
a pre-built Firefox binary — pin the camoufox package version in uv.lock
请在uv.lock中固定camoufox包的版本,尽可能校验下载哈希值。
and validate the download hash when possible.
—
RUN uv run python -m camoufox fetch
COPY . .
RUN uv sync --frozen --no-dev
ENV PATH="/app/.venv/bin:$PATH"
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
undefinedRUN uv run python -m camoufox fetch
COPY . .
RUN uv sync --frozen --no-dev
ENV PATH="/app/.venv/bin:$PATH"
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
undefinedDocker Compose — Full Stack
Docker Compose — 全栈配置
yaml
undefinedyaml
undefineddocker-compose.yml
docker-compose.yml
services:
browser:
build:
context: ./browser
dockerfile: Dockerfile
container_name: threads-browser
restart: unless-stopped
environment:
DISPLAY: ":99"
SCREEN_RES: "1920x1080x24"
ports:
- "127.0.0.1:5900:5900" # VNC — bind to localhost only!
volumes:
- ./sessions:/sessions
- /dev/shm:/dev/shm # shared memory for Firefox
shm_size: "2gb"
api:
build:
context: ./api
container_name: threads-api
restart: unless-stopped
environment:
SESSION_DIR: /sessions
ports:
- "127.0.0.1:8000:8000" # bind to localhost only — Nginx handles external
volumes:
- ./sessions:/sessions
depends_on:
- browser
dashboard:
build:
context: ./dashboard
container_name: threads-dashboard
restart: unless-stopped
environment:
NEXT_PUBLIC_API_URL: http://localhost:8000
ports:
- "127.0.0.1:3000:3000"
nginx:
image: nginx:1.28.2-alpine3.23 # pin stable — never use bare :alpine/:latest
container_name: threads-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/ssl:ro
undefinedservices:
browser:
build:
context: ./browser
dockerfile: Dockerfile
container_name: threads-browser
restart: unless-stopped
environment:
DISPLAY: ":99"
SCREEN_RES: "1920x1080x24"
ports:
- "127.0.0.1:5900:5900" # VNC — 仅绑定到localhost!
volumes:
- ./sessions:/sessions
- /dev/shm:/dev/shm # Firefox所需的共享内存
shm_size: "2gb"
api:
build:
context: ./api
container_name: threads-api
restart: unless-stopped
environment:
SESSION_DIR: /sessions
ports:
- "127.0.0.1:8000:8000" # 仅绑定到localhost — 外部访问由Nginx转发
volumes:
- ./sessions:/sessions
depends_on:
- browser
dashboard:
build:
context: ./dashboard
container_name: threads-dashboard
restart: unless-stopped
environment:
NEXT_PUBLIC_API_URL: http://localhost:8000
ports:
- "127.0.0.1:3000:3000"
nginx:
image: nginx:1.28.2-alpine3.23 # 固定稳定版本 — 切勿使用裸标签:alpine/:latest
container_name: threads-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/ssl:ro
undefinedSecurity Rules (2026)
安全规则(2026)
yaml
undefinedyaml
undefined✅ Never expose internal services directly to internet
✅ 切勿将内部服务直接暴露到公网
ports:
- "127.0.0.1:8000:8000" # only localhost — Nginx proxies externally
ports:
- "127.0.0.1:8000:8000" # 仅本地可访问 — 由Nginx对外代理
❌ Never do this
❌ 切勿这么写
ports:
- "8000:8000" # exposes to all interfaces
> [!CAUTION]
> The commands below **modify host-level firewall rules** and require root
> privileges. Never run them unattended in CI or automated scripts. Review
> and execute manually on the target VPS only.
```bashports:
- "8000:8000" # 暴露到所有网络接口
> [!CAUTION]
> 以下命令**会修改主机级防火墙规则**,需要root权限。切勿在CI或自动化脚本中无人值守运行这些命令。仅在目标VPS上手动审核后执行。
```bashUFW rules on VPS (manual — requires human review)
VPS上的UFW规则(手动执行 — 需要人工审核)
sudo ufw default deny incoming
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw deny 5900 # Block VNC from outside after first use
sudo ufw enable
undefinedsudo ufw default deny incoming
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw deny 5900 # 首次使用后禁止外部访问VNC
sudo ufw enable
undefinedVolume Strategy
卷管理策略
yaml
volumes:
- ./sessions:/sessions # named bind mount — survives container rebuild
- /dev/shm:/dev/shm # shared memory — required for Firefox stabilitybash
undefinedyaml
volumes:
- ./sessions:/sessions # 命名绑定挂载 — 容器重建后数据仍保留
- /dev/shm:/dev/shm # 共享内存 — 保障Firefox稳定性所需bash
undefinedNever lose sessions: backup before any docker operations
永远不要丢失会话数据:执行任何Docker操作前先备份
tar -czf sessions-backup-$(date +%Y%m%d).tar.gz ./sessions/
undefinedtar -czf sessions-backup-$(date +%Y%m%d).tar.gz ./sessions/
undefinedUseful Commands (2026)
常用命令(2026)
bash
undefinedbash
undefinedBuild and start all services
构建并启动所有服务
docker compose up -d --build
docker compose up -d --build
Tail logs for a specific service
查看指定服务的实时日志
docker compose logs -f browser
docker compose logs -f browser
Shell into running container
进入运行中的容器的Shell
docker exec -it threads-browser bash
docker exec -it threads-browser bash
Check resource usage
查看资源占用情况
docker stats
docker stats
Restart single service without rebuilding
重启单个服务无需重新构建
docker compose restart api
docker compose restart api
Full teardown (preserves volumes)
完全销毁服务(保留卷数据)
docker compose down
docker compose down
Full teardown including volumes — DANGER, deletes sessions
完全销毁服务包括卷 — 危险操作,会删除会话数据
docker compose down -v
undefineddocker compose down -v
undefinedHealth Checks
健康检查
yaml
services:
api:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10syaml
services:
api:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s.dockerignore
.dockerignore配置
.venv/
__pycache__/
*.pyc
.env
.git/
node_modules/
sessions/
*.log.venv/
__pycache__/
*.pyc
.env
.git/
node_modules/
sessions/
*.logAnti-Patterns
反模式
dockerfile
undefineddockerfile
undefined❌ Never run as root in production
❌ 生产环境切勿以root身份运行
CMD ["python", "app.py"] # without USER directive — runs as root
CMD ["python", "app.py"] # 没有USER指令 — 以root身份运行
❌ Never use latest tag for base images in production
❌ 生产环境基础镜像切勿使用latest标签
FROM python:latest
FROM python:latest
❌ Never install pip packages globally in 2026 Dockerfiles
❌ 2026年的Dockerfile中切勿全局安装pip包
RUN pip install fastapi # use uv instead
RUN pip install fastapi # 请改用uv
❌ Never copy all files before installing deps (kills layer cache)
❌ 安装依赖前切勿复制所有文件(会破坏层缓存)
COPY . .
RUN uv sync # every code change invalidates dep cache
undefinedCOPY . .
RUN uv sync # 每次代码变更都会使依赖缓存失效
undefinedReferences
参考资料
- Docker Compose v2: https://docs.docker.com/compose/
- uv Docker: https://docs.astral.sh/uv/guides/integration/docker/
- Docker Compose v2: https://docs.docker.com/compose/
- uv Docker: https://docs.astral.sh/uv/guides/integration/docker/