diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..cff4bcc --- /dev/null +++ b/.dockerignore @@ -0,0 +1,26 @@ +# Dependencies +web/node_modules/ + +# Build artifacts +server/bin/ +web/dist/ + +# Data & logs +data/ +*.db +*.log + +# IDE & OS +.idea/ +.vscode/ +*.swp +*.swo +.DS_Store + +# Git +.git/ +.github/ + +# Docker +Dockerfile +docker-compose*.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9dc2617 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,62 @@ +# ---- Stage 1: Build frontend ---- +FROM node:20-alpine AS web-builder + +WORKDIR /build/web +COPY web/package.json web/package-lock.json ./ +RUN npm ci +COPY web/ ./ +RUN npm run build + + +# ---- Stage 2: Build backend ---- +FROM golang:1.25-alpine AS server-builder + +WORKDIR /build/server +COPY server/go.mod server/go.sum ./ +RUN go mod download +COPY server/ ./ +RUN go build -trimpath -ldflags="-s -w" -o backupx ./cmd/backupx + + +# ---- Stage 3: Production image ---- +FROM alpine:3.21 + +RUN apk add --no-cache \ + nginx \ + tzdata \ + ca-certificates \ + # Required by mysql/postgresql backup tasks + mysql-client \ + postgresql16-client \ + && rm -rf /var/cache/apk/* + +# Create app user +RUN addgroup -S backupx && adduser -S -G backupx -h /app backupx + +# Copy backend binary +COPY --from=server-builder /build/server/backupx /app/bin/backupx + +# Copy frontend static files +COPY --from=web-builder /build/web/dist /app/web + +# Copy nginx config +COPY deploy/docker/nginx.conf /etc/nginx/http.d/default.conf + +# Copy entrypoint +COPY deploy/docker/entrypoint.sh /app/entrypoint.sh +RUN chmod +x /app/entrypoint.sh + +# Create data directories +RUN mkdir -p /app/data /tmp/backupx && \ + chown -R backupx:backupx /app /tmp/backupx + +# Nginx needs to write to these dirs +RUN mkdir -p /var/lib/nginx/tmp /var/log/nginx && \ + chown -R backupx:backupx /var/lib/nginx /var/log/nginx /run/nginx + +WORKDIR /app +EXPOSE 8340 + +VOLUME ["/app/data"] + +ENTRYPOINT ["/app/entrypoint.sh"] diff --git a/README.md b/README.md index 682987b..e3c51cc 100644 --- a/README.md +++ b/README.md @@ -112,10 +112,30 @@ BackupX 是一个面向 **Linux / macOS 服务器**的自托管备份管理平 ### 🌐 其他 - 中英文国际化 (i18n) - 零外部依赖(内嵌 SQLite,单二进制部署) +- Docker / Docker Compose 一键部署 - systemd 服务支持 ## Quick Start +### Docker 部署 (推荐) + +```bash +# 克隆项目 +git clone https://github.com/Awuqing/BackupX.git +cd BackupX + +# 一键启动 +docker compose up -d +``` + +如需备份宿主机上的目录,在 `docker-compose.yml` 中挂载对应路径: + +```yaml +volumes: + - backupx-data:/app/data + - /path/to/backup/source:/mnt/source:ro +``` + ### 从源码构建 ```bash @@ -302,11 +322,16 @@ BackupX/ ├── deploy/ # 部署配置 │ ├── nginx.conf # Nginx 参考配置 │ ├── backupx.service # systemd 服务单元 -│ └── install.sh # 一键安装脚本 +│ ├── install.sh # 一键安装脚本 +│ └── docker/ # Docker 部署配置 +│ ├── nginx.conf # 容器内 Nginx 配置 +│ └── entrypoint.sh # 容器启动脚本 ├── .github/ # GitHub 配置 │ ├── workflows/ci.yml # CI 工作流 │ ├── workflows/release.yml # Release 工作流 │ └── ISSUE_TEMPLATE/ # Issue 模板 +├── Dockerfile # Docker 多阶段构建 +├── docker-compose.yml # Docker Compose 配置 └── Makefile # 构建命令 ``` @@ -371,6 +396,29 @@ sudo ./deploy/install.sh 5. 注册并启动 systemd 服务 6. 配置 Nginx 反向代理(如已安装) +### Docker 部署 + +```bash +# 使用 docker compose +docker compose up -d + +# 或手动构建镜像 +docker build -t backupx . +docker run -d --name backupx -p 8340:8340 -v backupx-data:/app/data backupx +``` + +通过环境变量覆盖配置: + +```bash +docker run -d --name backupx \ + -p 8340:8340 \ + -v backupx-data:/app/data \ + -e TZ=Asia/Shanghai \ + -e BACKUPX_LOG_LEVEL=debug \ + -e BACKUPX_BACKUP_MAX_CONCURRENT=4 \ + backupx +``` + ### 手动部署 ```bash diff --git a/README_EN.md b/README_EN.md index bb82bdb..39e663d 100644 --- a/README_EN.md +++ b/README_EN.md @@ -112,10 +112,30 @@ Supports **multi-node cluster management** for unified control of backup tasks a ### 🌐 Other - Chinese & English i18n - Zero external dependencies (embedded SQLite, single binary deployment) +- Docker / Docker Compose one-click deployment - systemd service support ## Quick Start +### Docker Deployment (Recommended) + +```bash +# Clone the project +git clone https://github.com/Awuqing/BackupX.git +cd BackupX + +# Start with one command +docker compose up -d +``` + +To back up host directories, mount them in `docker-compose.yml`: + +```yaml +volumes: + - backupx-data:/app/data + - /path/to/backup/source:/mnt/source:ro +``` + ### Build from Source ```bash @@ -303,11 +323,16 @@ BackupX/ ├── deploy/ # Deployment configs │ ├── nginx.conf # Nginx reference config │ ├── backupx.service # systemd service unit -│ └── install.sh # One-click install script +│ ├── install.sh # One-click install script +│ └── docker/ # Docker deployment configs +│ ├── nginx.conf # In-container Nginx config +│ └── entrypoint.sh # Container entrypoint script ├── .github/ # GitHub configuration │ ├── workflows/ci.yml # CI workflow │ ├── workflows/release.yml # Release workflow │ └── ISSUE_TEMPLATE/ # Issue templates +├── Dockerfile # Docker multi-stage build +├── docker-compose.yml # Docker Compose config └── Makefile # Build commands ``` @@ -372,6 +397,29 @@ The install script will automatically: 5. Register and start the systemd service 6. Configure Nginx reverse proxy (if installed) +### Docker Deployment + +```bash +# Using docker compose +docker compose up -d + +# Or build and run manually +docker build -t backupx . +docker run -d --name backupx -p 8340:8340 -v backupx-data:/app/data backupx +``` + +Override configuration via environment variables: + +```bash +docker run -d --name backupx \ + -p 8340:8340 \ + -v backupx-data:/app/data \ + -e TZ=Asia/Shanghai \ + -e BACKUPX_LOG_LEVEL=debug \ + -e BACKUPX_BACKUP_MAX_CONCURRENT=4 \ + backupx +``` + ### Manual Deployment ```bash diff --git a/deploy/docker/entrypoint.sh b/deploy/docker/entrypoint.sh new file mode 100644 index 0000000..fd92b64 --- /dev/null +++ b/deploy/docker/entrypoint.sh @@ -0,0 +1,23 @@ +#!/bin/sh +set -e + +# Backend listens on internal port 8341, Nginx exposes 8340 +export BACKUPX_SERVER_PORT="${BACKUPX_SERVER_PORT_INTERNAL:-8341}" + +# Start Nginx in background +nginx -g "daemon off;" & +NGINX_PID=$! + +# Start BackupX backend +/app/bin/backupx & +APP_PID=$! + +# Trap signals for graceful shutdown +trap 'kill $APP_PID $NGINX_PID 2>/dev/null; wait $APP_PID $NGINX_PID 2>/dev/null' SIGTERM SIGINT + +echo "BackupX started — Nginx :8340 -> Backend :8341" + +# Wait for either process to exit +wait -n $APP_PID $NGINX_PID 2>/dev/null || true +kill $APP_PID $NGINX_PID 2>/dev/null || true +wait $APP_PID $NGINX_PID 2>/dev/null || true diff --git a/deploy/docker/nginx.conf b/deploy/docker/nginx.conf new file mode 100644 index 0000000..e13c2aa --- /dev/null +++ b/deploy/docker/nginx.conf @@ -0,0 +1,32 @@ +server { + listen 8340; + server_name _; + + root /app/web; + index index.html; + + # API reverse proxy to backend + location /api/ { + proxy_pass http://127.0.0.1:8341/api/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Connection ""; + proxy_buffering off; + proxy_cache off; + proxy_read_timeout 3600s; + } + + # SPA fallback + location / { + try_files $uri $uri/ /index.html; + } + + # Static assets cache + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ { + expires 30d; + add_header Cache-Control "public, immutable"; + } +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..2ccd869 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +services: + backupx: + build: . + image: backupx:latest + container_name: backupx + restart: unless-stopped + ports: + - "8340:8340" + volumes: + - backupx-data:/app/data + # Mount host directories that need to be backed up (example): + # - /path/to/backup/source:/mnt/source:ro + environment: + - TZ=Asia/Shanghai + # Override any config via BACKUPX_ prefixed env vars: + # - BACKUPX_SERVER_PORT=8340 + # - BACKUPX_LOG_LEVEL=info + # - BACKUPX_BACKUP_MAX_CONCURRENT=2 + +volumes: + backupx-data: