docker-vps-2026

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Docker + VPS 2026 — Best Practices

2026年Docker + VPS 最佳实践

Docker Compose v2 (2026 Standard)

Docker Compose v2(2026年标准)

bash
undefined
bash
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
undefined
docker-compose up # 带连字符 — 切勿使用
undefined

Python Container (uv-based, 2026)

Python容器(基于uv,2026年标准)

dockerfile
FROM python:3.12-slim-bookworm
dockerfile
FROM python:3.12-slim-bookworm

Copy 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"]
undefined
RUN useradd -m appuser && chown -R appuser:appuser /app USER appuser
CMD ["python", "-m", "api.main"]
undefined

Browser Automation Container (Xvfb + Camoufox)

浏览器自动化容器(Xvfb + Camoufox)

dockerfile
FROM python:3.12-slim-bookworm

COPY --from=ghcr.io/astral-sh/uv:0.10.7 /uv /uvx /bin/
dockerfile
FROM python:3.12-slim-bookworm

COPY --from=ghcr.io/astral-sh/uv:0.10.7 /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/*
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/*
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"]
undefined
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"]
undefined

Docker Compose — Full Stack

Docker Compose — 全栈配置

yaml
undefined
yaml
undefined

docker-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
undefined
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 — 仅绑定到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
undefined

Security Rules (2026)

安全规则(2026)

yaml
undefined
yaml
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.

```bash
ports:
  • "8000:8000" # 暴露到所有网络接口

> [!CAUTION]
> 以下命令**会修改主机级防火墙规则**,需要root权限。切勿在CI或自动化脚本中无人值守运行这些命令。仅在目标VPS上手动审核后执行。

```bash

UFW 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
undefined
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 # 首次使用后禁止外部访问VNC sudo ufw enable
undefined

Volume Strategy

卷管理策略

yaml
volumes:
  - ./sessions:/sessions      # named bind mount — survives container rebuild
  - /dev/shm:/dev/shm         # shared memory — required for Firefox stability
bash
undefined
yaml
volumes:
  - ./sessions:/sessions      # 命名绑定挂载 — 容器重建后数据仍保留
  - /dev/shm:/dev/shm         # 共享内存 — 保障Firefox稳定性所需
bash
undefined

Never lose sessions: backup before any docker operations

永远不要丢失会话数据:执行任何Docker操作前先备份

tar -czf sessions-backup-$(date +%Y%m%d).tar.gz ./sessions/
undefined
tar -czf sessions-backup-$(date +%Y%m%d).tar.gz ./sessions/
undefined

Useful Commands (2026)

常用命令(2026)

bash
undefined
bash
undefined

Build 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
undefined
docker compose down -v
undefined

Health Checks

健康检查

yaml
services:
  api:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s
yaml
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/
*.log

Anti-Patterns

反模式

dockerfile
undefined
dockerfile
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
undefined
COPY . . RUN uv sync # 每次代码变更都会使依赖缓存失效
undefined

References

参考资料