剪藏#IT老菜鸟#剪藏

Seafile 私有云盘 + Cloudflare 内网穿透

2026 年 5 月 23 日1 分钟
分享Twitter / XTelegram微博
Seafile 私有云盘 + Cloudflare 内网穿透 封面

Notion image

🚀公众号后台复【布道者】查看最新AI技术学习路线🚀

Seafile 私有云盘 + Cloudflare 内网穿透

基于 Docker Compose,一键部署 Seafile 私有云。

版本: 2026.03.29

Notion image

Notion image

Notion image

Notion image

快速开始

1. 环境检查

JAVASCRIPT
docker --version
docker compose version

2. 配置修改

编辑 config/.env,设置:

  • PUBLIC_DOMAIN - 你的域名

  • SEAFILE_ADMIN_EMAIL - 管理员邮箱

  • SEAFILE_ADMIN_PASSWORD - 管理员密码

  • MYSQL_ROOT_PASSWORD - 数据库 root 密码

  • MYSQL_PASSWORD - 数据库用户密码

密码生成工具

JAVASCRIPT
generate_password() { tr -dc 'A-Za-z0-9' </dev/urandom | head -c 16; }
echo "密码: $(generate_password)"

3. 一键部署

JAVASCRIPT
chmod +x deploy.sh
./deploy.sh

访问:http://IP:10080

架构

JAVASCRIPT
┌─────────┐     ┌──────────┐     ┌────────────┐
│  Caddy  │────▶│  Seafile │────▶│  MariaDB   │
│  :10080 │     │   :80    │     │   :3306    │
└─────────┘     └──────────┘     └────────────┘
                              └────────────┐
                                         ▼
                                   ┌──────────┐
                                   │Memcached │
                                   │  :11211  │
                                   └──────────┘

流量路径

JAVASCRIPT
用户 → Cloudflare HTTPS → cloudflared → Caddy:10080 → seafile-app:80
                                                              ↓
                                                      容器内 Nginx
                                                      /           \
                                                Gunicorn     Fileserver
                                                 :8000         :8082

目录结构

JAVASCRIPT
seafile-deploy/
├── deploy.sh              # 主部署脚本
├── config/                # 配置文件
│   ├── .env# 环境变量
│   ├── docker-compose.yml # 服务配置
│   └── Caddyfile         # 反向代理
├── scripts/               # 辅助脚本
│   └── config_seafile.sh # 应用配置
└── data/                  # 数据存储
    ├── seafile/          # 应用数据
    ├── mariadb/          # 数据库
    └── caddy/            # Caddy 数据和日志

服务管理

JAVASCRIPT
docker compose -p seafile -f config/docker-compose.yml up -d    # 启动
docker compose -p seafile -f config/docker-compose.yml down    # 停止
docker compose -p seafile -f config/docker-compose.yml restart # 重启
docker compose -p seafile -f config/docker-compose.yml logs -f # 日志

数据备份

JAVASCRIPT
# 备份
docker compose -p seafile -f config/docker-compose.yml down
tar -czvf seafile-backup-$(date +%Y%m%d).tar.gz data/
docker compose -p seafile -f config/docker-compose.yml up -d

# 恢复
docker compose -p seafile -f config/docker-compose.yml down
rm -rf data/
tar -xzf seafile-backup-20240101.tar.gz
docker compose -p seafile -f config/docker-compose.yml up -d

配置说明

环境变量 (.env)

  • 服务器:SERVER_IP, HTTP_PORT

  • 管理员:SEAFILE_ADMIN_EMAIL, SEAFILE_ADMIN_PASSWORD

  • 数据库:MYSQL_PASSWORD, MYSQL_ROOT_PASSWORD

  • 时区:TZ

Docker Compose (docker-compose.yml)

  • 服务:MariaDB、Memcached、Seafile、Caddy

  • 数据:本地目录挂载

  • 资源:树莓派优化配置

  • 健康:服务状态检查

💡 缓存建议:Seafile 镜像默认使用 Memcached,零配置即可工作。如使用 Redis 需要额外配置 seahub_settings.py,复杂度较高,建议保持默认的 Memcached。

重要说明

本部署使用 Cloudflare Tunnel (cloudflared) 暴露服务,HTTPS 由 Cloudflare 处理,Caddy 只接收 HTTP 请求。

无需修改 Caddyfile 配置,当前的 HTTP 配置已经正确工作。

极简主义 · UNIX哲学 · 一键部署

目录结构

JAVASCRIPT
pi@pi: /DATA/AppData/seafile $ tree -L 2
├── config
│   ├── Caddyfile
│   └── docker-compose.yml
├── data
│   ├── caddy
│   ├── mariadb
│   └── seafile
├── deploy.sh
├── README.md
└── scripts
    └── config_seafile.sh

7 directories, 5 files
pi@pi: /DATA/AppData/seafile $ 

config/.env

JAVASCRIPT
# Seafile 极简部署配置
# 版本: 2026.03.27
# 遵循UNIX哲学:Just Enough

# ------------------------------
# 基础配置(必须)
# ------------------------------
PUBLIC_DOMAIN="seafile.example.com"# ✅ 取消注释,统一域名
SERVER_IP="192.168.1.10"
HTTP_PORT="10082"
SEAFILE_ADMIN_EMAIL="admin@seafile.local"
SEAFILE_ADMIN_PASSWORD="8tL1YAJS1j3fJ9iJ"

# ------------------------------
# 数据库配置(必须)
# ------------------------------
MYSQL_PASSWORD="TuYgDlXtCM87SwUd"
MYSQL_ROOT_PASSWORD="bVoPKKGjZA6g9RRR"

# ------------------------------
# 时区配置(必须)
# ------------------------------
TZ="Asia/Shanghai"

# ------------------------------
# 信任域配置(自动生成)
# ------------------------------
TRUSTED_DOMAINS="127.0.0.1,localhost,${SERVER_IP},${PUBLIC_DOMAIN}"# ✅ 用变量
SEAFILE_TRUSTED_DOMAINS="${TRUSTED_DOMAINS}"

# ------------------------------
# 性能优化配置
# ------------------------------
MAX_UPLOAD_SIZE="10737418240"# 10GB
MEMORY_LIMIT="1G"

config/Caddyfile

JAVASCRIPT
# Seafile 极简部署配置
# 版本: 2026.03.27
# 遵循UNIX哲学:Just Enough

:80 {
    request_body {
        max_size 10GB
    }

    reverse_proxy seafile-app:80 {
        transport http {
            keepalive 300s
            read_timeout 3600s
            write_timeout 3600s
            dial_timeout 10s
        }
    }

    header {
        X-Content-Type-Options nosniff
        X-Frame-Options SAMEORIGIN
        X-XSS-Protection "1; mode=block"
        X-Robots-Tag "none"
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        Referrer-Policy "strict-origin-when-cross-origin"
        -Server
    }

    encode gzip zstd

    log {
        level INFO
        output file /var/log/caddy/access.log {
            roll_size 10MB
            roll_keep 5
            roll_keep_for 720h
        }
    }
}

config/docker-compose.yml

JAVASCRIPT
# Seafile 极简部署配置
# 版本: 2026.03.27
# 遵循UNIX哲学:Just Enough

# 环境变量配置
x-seafile-env: &seafile-env
  DB_HOST: mariadb
  DB_ROOT_PASSWD${MYSQL_ROOT_PASSWORD}
  DB_NAME: seafile
  DB_USER: seafile
  DB_PASSWD${MYSQL_PASSWORD}
  SEAFILE_ADMIN_EMAIL${SEAFILE_ADMIN_EMAIL}
  SEAFILE_ADMIN_PASSWORD${SEAFILE_ADMIN_PASSWORD}
  SEAFILE_SERVER_HOSTNAME${PUBLIC_DOMAIN}# ✅ 关键:改成域名,不要IP+端口
  SEAFILE_TIME_ZONE${TZ}
  SEAFILE_SERVER_LETSENCRYPT"false"
  SEAFILE_SERVER_PROTOCOL"http"# ✅ 容器内使用HTTP,外部由代理处理HTTPS
  SEAFILE_SERVICE_URL"http://${PUBLIC_DOMAIN}"# ✅ 内部通信使用HTTP
  SEAFILE_FILE_SERVER_ROOT"http://${PUBLIC_DOMAIN}/seafhttp"# ✅ 内部文件服务使用HTTP

# 目录挂载配置
volumes:
  seafile_data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: ../data/seafile
  mariadb_data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: ../data/mariadb
  caddy_data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: ../data/caddy
  caddy_config:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: ../data/caddy/config
  caddy_log:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: ../data/caddy/log

# 网络配置
networks:
  default:
    driver: bridge
    ipam:
      config:
        - subnet: 172.32.0.0/16
      
# 服务配置
services:
# 数据库服务
  mariadb:
    image: m.daocloud.io/docker.io/library/mariadb:latest
    container_name: seafile-db
    restart: always
    volumes: [mariadb_data:/var/lib/mysql]
    environment:
      MYSQL_ROOT_PASSWORD${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: seafile
      MYSQL_USER: seafile
      MYSQL_PASSWORD${MYSQL_PASSWORD}
      TZ${TZ}
    command: >
      --transaction-isolation=READ-COMMITTED
      --binlog-format=ROW
      --innodb_buffer_pool_size=256M
      --innodb_log_file_size=64M
      --max_connections=100
      --skip-name-resolve
    networks: [default]
    healthcheck:
      test: ["CMD""mariadb-admin""pi
JAVASCRIPT
ng", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 60s
    deploy:
      resources:
        limits:
          cpus'2.0'
          memory: 2G
        reservations:
          cpus'1.0'
          memory: 1G
    logging:
      driver"json-file"
      options:
        max-size"10m"
        max-file"3"

# Memcached 缓存服务
  memcached:
    image: m.daocloud.io/docker.io/library/memcached:alpine
    container_name: seafile-cache
    restart: always
    command: memcached -m 256
    networks: [default]
    healthcheck:
      test: ["CMD""echo""flush_all""|""nc""localhost""11211"]
      interval: 10s
      timeout: 5s
      retries: 3
    deploy:
      resources:
        limits:
          cpus'0.5'
          memory: 512M
        reservations:
          cpus'0.25'
          memory: 256M
    logging:
      driver"json-file"
      options:
        max-size"5m"
        max-file"2"

# Seafile 应用服务
  seafile:
    image: m.daocloud.io/docker.io/seafileltd/seafile-mc:latest
    container_name: seafile-app
    restart: always
    dns:
      - 223.5.5.5  # 阿里云DNS(国内首选,解析速度快、稳定)
      - 114.114.114.114  # 备用DNS,避免单DNS故障
      - 8.8.8.8      # 谷歌DNS(备用)
    volumes:
      - seafile_data:/shared
      - type: tmpfs
        target: /tmp
        tmpfs:
          size: 256M
    environment:
      <<: *seafile-env
      MAX_UPLOAD_SIZE${MAX_UPLOAD_SIZE}
      MEMORY_LIMIT${MEMORY_LIMIT}
    networks: [default]
    healthcheck:
      test: ["CMD-SHELL""curl -f http://localhost || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 180s
    deploy:
      resources:
        limits:
          cpus'1.0'
          memory${MEMORY_LIMIT}
        reservations:
          cpus'0.5'
          memory: 512M
    logging:
      driver"json-file"
      options:
        max-size"20m"
        max-file"5"
    depends_on:
      mariadb: {conditi
JAVASCRIPT
on: service_healthy}
      memcached: {condition: service_healthy}

# Caddy 反向代理服务
  caddy:
    image: m.daocloud.io/docker.io/library/caddy:alpine
    container_name: seafile-proxy
    restart: always
    ports: ["${HTTP_PORT}:80"]
    dns:
      - 223.5.5.5  # 阿里云DNS(国内首选,解析速度快、稳定)
      - 114.114.114.114  # 备用DNS,避免单DNS故障
      - 8.8.8.8      # 谷歌DNS(备用)
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
      - caddy_log:/var/log/caddy
    networks: [default]
    environment:
      - SERVER_IP=${SERVER_IP}
      - HTTP_PORT=${HTTP_PORT}
      - CADDY_ADMIN=0.0.0.0:2019
      - TZ=${TZ}
    command: sh -"caddy run --config /etc/caddy/Caddyfile --adapter caddyfile"
    healthcheck:
      test: ["CMD-SHELL""wget --no-verbose --tries=1 --spider http://localhost:2019/config || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    deploy:
      resources:
        limits:
          cpus'0.5'
          memory: 512M
        reservations:
          cpus'0.25'
          memory: 256M
    logging:
      driver"json-file"
      options:
        max-size"10m"
        max-file"3"
    depends_on:
      seafile: {condition: service_healthy}

scripts/config_seafile.sh

JAVASCRIPT
# Seafile 极简部署配置
# 版本: 2026.03.27
# 遵循UNIX哲学:Just Enough

#!/bin/bash
set -euo pipefail

# 路径定义
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CONFIG_DIR="$PROJECT_DIR/config"

# 检查环境文件
[[ -"$CONFIG_DIR/.env" ]] || { echo "错误: 缺少 $CONFIG_DIR/.env" >&2; exit 1; }

# 加载环境变量
set -a
source "$CONFIG_DIR/.env"
set +a

# Docker Compose 命令
DOCKER_COMPOSE_CMD=$(command -v docker-compose || echo "docker compose")

# 在 Seafile 容器内执行命令
seafile_exec() {
    $DOCKER_COMPOSE_CMD -p seafile -f "$CONFIG_DIR/docker-compose.yml" exec -T seafile bash -c "$1"
}

# 安全添加配置(覆盖已存在的配置)
add_config() {
    local conf="$1"
    local value="$2"
    local key="${value%%=*}"
    key="${key%"${key##*[![:space:]]}"}"

    seafile_exec "touch ${conf}"
    if grep -qE "^${key}[[:space:]]*=" ${conf} 2>/dev/null; then
        seafile_exec "sed -i \"s#^${key}[[:space:]]*=.*#${value}#\" ${conf}"
    else
        seafile_exec "echo '${value}' >> ${conf}"
    fi
}

# 检查服务是否就绪
check_seafile_ready() {
    echo "→ 检查 Seafile 服务状态"
    local attempts=0
    local max_attempts=10
    
    while [ $attempts -lt $max_attempts ]; do
        if seafile_exec "curl -s -L http://localhost >/dev/null 2>&1"; then
            echo "✅ 服务正常"
            return 0
        fi
        
        attempts=$((attempts + 1))
        echo "⏳ 等待服务启动... (尝试 $attempts/$max_attempts)"
        sleep 5
    done
    
    echo "❌ 服务异常" >&2
    return 1
}

# 配置 Gunicorn
configure_gunicorn() {
    echo "→ 配置 Gunicorn 监听"
    seafile_exec "sed -i 's/bind = \"127.0.0.1:8000\"/bind = \"0.0.0.0:8000\"/' /opt/seafile/conf/gunicorn.conf.py"
    echo "✅ 完成"
}

# 配置 Seahub(从 .env 读取域名,无硬编码)
configure_seahub() {
    echo "→ 配置 seahub_settings.py"
    local conf="/opt/seafile/conf/seahub_settings.py"

    add_config "$conf" 'MAX_UPLOAD_SIZE = "10737418240"'
    add_config "$conf" 'TIME_ZONE = "Asia/Shanghai"'
    add_config "$conf" 'CSRF_TRUSTED_ORIGINS = ["https://seafile.example.com", "http://192.168.1.10:10082", "http://localhost", "
JAVASCRIPT
http://127.0.0.1"]'
    add_config "$conf" 'ALLOWED_HOSTS = ["*"]'
    
    # 动态协议配置,支持HTTP和HTTPS
    add_config "$conf" 'SERVICE_URL = "https://seafile.example.com"'
    add_config "$conf" 'FILE_SERVER_ROOT = "https://seafile.example.com/seafhttp"'
    
    # 代理 HTTPS 关键配置
    add_config "$conf" 'USE_X_FORWARDED_HOST = True'
    add_config "$conf" 'SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")'

    # 信任代理配置(允许 Caddy/Cloudflared 作为代理)
    add_config "$conf" 'TRUSTED_PROXIES = ["172.32.0.0/16", "127.0.0.1"]'

    # Cookie 安全配置(内部是 HTTP,反向代理已传递 X-Forwarded-Proto)
    add_config "$conf" 'CSRF_COOKIE_SECURE = False'
    add_config "$conf" 'SESSION_COOKIE_SECURE = False'
    add_config "$conf" 'CSRF_COOKIE_SAMESITE = "Lax"'
    add_config "$conf" 'SESSION_COOKIE_SAMESITE = "Lax"'

    echo "✅ 完成"
}

# 配置文件服务器(从 .env 读取域名)
configure_fileserver() {
    echo "→ 配置 seafile.conf 文件服务"
    local conf="/opt/seafile/conf/seafile.conf"

    seafile_exec "touch '$conf'"
    seafile_exec "grep -q '\[fileserver\]' '$conf' || echo -e '\n[fileserver]' >> '$conf'"
    seafile_exec "sed -i '/^\[fileserver\]/,/^$/ s/^host =.*/host = 0.0.0.0/' '$conf'"
    seafile_exec "sed -i '/^\[fileserver\]/,/^$/ s/^port =.*/port = 8082/' '$conf'"
    seafile_exec "sed -i '/^\[fileserver\]/,/^$/ s/^web_root =.*/web_root = \/seafhttp/' '$conf'"

    echo "✅ 完成"
}

# 主流程
main() {
    echo "🚀 开始配置 Seafile..."
    echo "=================================="
    
    check_seafile_ready   || { echo "❌ 配置失败:服务未就绪" >&2; exit 1; }
    configure_gunicorn    || { echo "❌ 配置失败:Gunicorn 配置错误" >&2; exit 1; }
    configure_seahub      || { echo "❌ 配置失败:Seahub 配置错误" >&2; exit 1; }
    configure_fileserver  || { echo "❌ 配置失败:文件服务器配置错误" >&2; exit 1; }

    echo -e "\n✅ Seafile 配置已完成"
}

main

deploy.sh

JAVASCRIPT
# Seafile 极简部署配置
# 版本: 2026.03.27
# 遵循UNIX哲学:Just Enough

#!/bin/bash
set -euo pipefail

# 目录定义
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_DIR="$PROJECT_DIR/config"
SCRIPTS_DIR="$PROJECT_DIR/scripts"

# 检查环境文件
if [ ! -"$CONFIG_DIR/.env" ]; then
    echo "错误: 环境配置文件 $CONFIG_DIR/.env 不存在" >&2
    exit 1
fi

# 安全加载环境变量
set -a
source "$CONFIG_DIR/.env"
set +a

# 确定 Docker Compose 命令
DOCKER_COMPOSE_CMD=$(command -v docker-compose || echo "docker compose")

# 创建数据目录并设置权限
create_data_dir() {
    echo "→ 创建数据目录"
    
    # 清理旧数据(防止权限问题)
    if [ -"./data" ] &&"$(ls -A ./data 2>/dev/null)" ]; then
        echo "⚠️  清理旧数据目录..."
        rm -rf ./data/*
    fi
    
    local dirs=(
        "./data/seafile"
        "./data/mariadb"
        "./data/caddy/data"
        "./data/caddy/config"
        "./data/caddy/log"
    )
    for dir in "${dirs[@]}"; do
        mkdir -p "$dir"
        chmod -R 755 "$dir"
    done
    echo "✅ 数据目录创建完成"
}

# 启动服务
start_services() {
    echo "→ 启动 Docker 服务"
    $DOCKER_COMPOSE_CMD -p seafile -f "$CONFIG_DIR/docker-compose.yml" up -d --wait || exit 1
}

# 验证部署
verify_deployment() {
    echo "→ 验证服务可用性"
    
    # 检查内网地址(确保容器正常)
    if curl -s -m 5 "http://${SERVER_IP}:${HTTP_PORT}" >/dev/null 2>&1; then
        echo "✅ 部署成功!"
    else
        echo "❌ 部署失败,请检查容器日志" >&2
        exit 1
    fi
}

# 主流程
main() {
    echo "============================================="
    echo "      Seafile 极简部署 (最终完美版)"
    echo "============================================="

    # 按顺序执行部署
    create_data_dir    || exit 1
    start_services     || exit 1

    # 等待初始化(必须)
    echo -e "\n→ 等待 Seafile 初始化完成(60秒)..."
    sleep 60
    


    # 执行自动配置(关键)
    echo -e "\n→ 执行最终配置(域名/HTTPS/内网IP修复)..."
    bash "$SCRIPTS_DIR/config_seafile.sh" || exit 1

    # 重启使配置全部生效
    echo -e "\n→ 重启服务以应用配置..."
    $DOCKER_COMPOSE_CMD -p seafile -f "$CONFIG_DIR/docker-compose.yml" restart

    # 验证
    verify_deployment  || exit 1

    # 输出信息(显示外网域名 + 内网地址)
JAVASCRIPT

    echo -"\n============================================="
    echo " 🎉 Seafile 部署完成!"
    echo -" 🌍 外网访问: \033[32mhttps://${PUBLIC_DOMAIN}\033[0m"
    echo -" 🏠 内网访问: \033[32mhttp://${SERVER_IP}:${HTTP_PORT}\033[0m"
    echo -" 📧 管理员邮箱: \033[32m${SEAFILE_ADMIN_EMAIL}\033[0m"
    echo -" 🔑 管理员密码: \033[32m${SEAFILE_ADMIN_PASSWORD}\033[0m"
    echo "============================================="
}

# 执行主流程
main

原文地址: https://mp.weixin.qq.com/s?__biz=MzkyOTI1NjA5MQ==&mid=2247503857&idx=1&sn=f98ea6ded12b8d7e0cb249f5b6bf49ae&chksm=c3cec3d8c0b6ec5f41d5a7c591946477cd5aadfcf7b65b443127a151a2e49bd0f5469f41783f&mpshare=1&scene=1&srcid=0523ISWIxgIrPWPrZgUvz13V&sharer_shareinfo=29cb6324493b473d2d89cddd7e584116&sharer_shareinfo_first=29cb6324493b473d2d89cddd7e584116#rd

相关文章