找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2810

积分

0

好友

368

主题
发表于 昨天 22:05 | 查看: 0| 回复: 0

FreeScout开源客服系统容器化部署

什么是 FreeScout?

FreeScout是一款免费开源的工单与客服系统,其界面设计贴近大家熟悉的Gmail风格,上手门槛低。它支持自主搭建,并且提供了容器化部署方案,无论是单机测试还是生产环境的集群扩展都能胜任。它能帮助团队将客户咨询、支持工单集中管理,实现多人共用一个收件箱协同办公,完全可以替代那些昂贵的商业同类工具。

在客户支持领域,Zendesk和Help Scout是行业标杆,但高昂的成本和潜在的隐私风险让许多中小企业望而却步。而FreeScout作为一款基于PHP(Laravel框架)开发的轻量级开源方案,恰好填补了这一空白——它不仅免费,还能让你完全掌控自己的数据,保障隐私安全。通过容器化部署,可以快速适配企业现有的云环境,简化集群管理,并显著提升部署的一致性。

该项目从一开始就是独立开发的,没有使用任何受版权保护的素材,在合规性和独立性上都有保障。无论对于初创公司还是有一定规模的企业,其功能都能很好地适配,满足日常客户支持的核心需求。

作为一个社区驱动的项目,FreeScout鼓励用户参与开发和提出功能建议,其迭代更新也往往更贴合实际使用场景。综合来看,无论是在控制成本、保护数据隐私,还是在功能拓展与灵活部署方面,它都是一款极具竞争力的开源客户支持工具。

项目特点:

  • 无数量限制:用户、工单、绑定的邮箱数量均无上限,业务增长不受工具限制。
  • 移动适配性强:完美支持各类移动设备,外出时也能随时处理客户咨询。
  • 多语言支持:内置多种语言界面,面向全球客户提供支持毫无压力。
  • 安全有保障:自带完善的安全机制,有效保护用户和客户的数据安全。
  • 部署简单高效:提供Web安装程序和自动更新工具,结合容器化部署,使得跨环境迁移和集群运维更加省心,同时降低兼容性成本。
  • 模块化拓展:支持官方和社区开发的扩展模块,可以根据业务需求灵活增减功能。
  • 多元集成能力:提供API接口,并能轻松对接Zapier等自动化工具,与企业现有系统联动协作。
  • 离线部署+虚拟邮箱适配:支持离线环境使用,可通过虚拟邮箱创建账号,工单全程以虚拟邮箱作为客户信息记录,无需依赖真实的互联网邮箱或内网邮件服务器。

在下文中,我将按照“测试 → 准生产 → 生产级”的逻辑,详细说明三种不同的容器化部署方式。这套方案可以无缝适配从内部测试到轻度生产环境的全部需求。如果你有更复杂的公网访问或域名配置需求,例如内网穿透,可以自行探索和扩展,相关思路可参考这篇公众号文章:Cloudflare隧道:将家庭网络安全地暴露到互联网上

参考链接:

场景一:局域网离线测试部署(HTTP 访问)

这种部署方式最简单快捷,适合在本地或局域网内进行功能测试和体验。

[student@rocky ~]$ cd freescout/
[student@rocky freescout]$ pwd
/home/student/freescout
[student@rocky freescout]$ ls
compose-no-proxy.yml  compose.yml
[student@rocky freescout]$
[student@rocky freescout]$ cat compose-no-proxy.yml
services:

  freescout-app:
    image: tiredofit/freescout
    container_name: freescout-app
    ports:
    - 8080:80
    links:
    - freescout-db
    volumes:
    ### 需自定义修改并访问源代码时,取消该行注释(含模块场景)。
    #- ./data:/www/html
    ### 若仅使用原生FreeScout,且需保留缓存、会话等持久化文件,用下面这行配置。
    - ./data:/data
    ### 若需保留原始源代码,同时添加额外模块,取消下面行注释。
    #- ./modules:/www/html/Modules
    - ./logs/:/www/logs
    environment:
    - CONTAINER_NAME=freescout-app

    - DB_HOST=freescout-db
    - DB_NAME=freescout
    - DB_USER=freescout
    - DB_PASS=freescout

    - SITE_URL=http://192.168.0.115:8080
    - ADMIN_EMAIL=admin@admin.com
    - ADMIN_PASS=freescout
    - ENABLE_SSL_PROXY=FALSE
    - DISPLAY_ERRORS=FALSE
    - TIMEZONE=Asia/Shanghai
    restart: always

  freescout-db:
    #image: tiredofit/mariadb    # 这个mariadb版本太老
    image: docker.io/nfrastack/mariadb
    container_name: freescout-db
    volumes:
      - ./db:/data
    environment:
      - ROOT_PASS=password
      - DB_NAME=freescout
      - DB_USER=freescout
      - DB_PASS=freescout

      - TIMEZONE=Asia/Shanghai    # 指定时区对任何应用都很重要

      - CONTAINER_NAME=freescout-db
    restart: always

  freescout-db-backup:
    container_name: freescout-db-backup
    image: tiredofit/db-backup
    links:
     - freescout-db
    volumes:
      - ./dbbackup:/backup
    environment:
      - CONTAINER_NAME=freescout-db-backup
      - DB_HOST=freescout-db
      - DB_TYPE=mariadb
      - DB_NAME=freescout
      - DB_USER=freescout
      - DB_PASS=freescout
      - DB01_BACKUP_INTERVAL=1440
      - DB01_BACKUP_BEGIN=0000
      - DB_CLEANUP_TIME=8640
      - COMPRESSION=BZ
      - MD5=TRUE

      - TIMEZONE=Asia/Shanghai
    restart: always
[student@rocky freescout]$ docker compose -f compose-no-proxy.yml up -d
[student@rocky freescout]$ docker compose -f compose-no-proxy.yml logs -
[student@rocky freescout]$ curl -vvv http://192.168.0.115:8080

配置文件中的 SITE_URL 需要替换为你服务器的实际内网 IP 地址。部署完成后,即可通过 http://<你的IP>:8080 访问 FreeScout。

FreeScout登录界面截图

场景二:局域网离线测试部署(HTTPS 访问)

在测试环境,我们有时也需要模拟 HTTPS 访问。这里我们使用 Caddy 作为反向代理,它会自动生成自签名证书,实现 HTTPS 加密。

[student@rocky freescout]$
[student@rocky freescout]$ cat compose.yml
services:

  freescout-app:
    image: docker.io/tiredofit/freescout
    container_name: freescout-app
    volumes:
      - ./data:/data
      - ./logs/:/www/logs
    environment:
      - TIMEZONE=Asia/Shanghai
      - CONTAINER_NAME=freescout-app

      - DB_HOST=freescout-db
      - DB_NAME=freescout
      - DB_USER=freescout
      - DB_PASS=freescout

      - SITE_URL=https://192.168.0.115

      - ADMIN_EMAIL=admin@admin.com
      - ADMIN_PASS=freescout

      - DISPLAY_ERRORS=FALSE

      - ENABLE_SSL_PROXY=TRUE
    networks:
      - proxy
      - services
    restart: always

  freescout-db:
    image: docker.io/nfrastack/mariadb
    container_name: freescout-db
    volumes:
      - ./db:/data
    environment:
      - TIMEZONE=Asia/Shanghai
      - CONTAINER_NAME=freescout-db

      - ROOT_PASS=password
      - DB_NAME=freescout
      - DB_USER=freescout
      - DB_PASS=freescout
    networks:
      - services
    restart: always

  freescout-db-backup:
    container_name: freescout-db-backup
    image: docker.io/tiredofit/db-backup
    volumes:
      - ./dbbackup:/backup
    environment:
      - TIMEZONE=Asia/Shanghai
      - CONTAINER_NAME=freescout-db-backup

      - DB01_HOST=freescout-db
      - DB01_TYPE=mariadb
      - DB01_NAME=freescout
      - DB01_USER=freescout
      - DB01_PASS=freescout
      - DB01_BACKUP_INTERVAL=1440
      - DB01_BACKUP_BEGIN=0000
      - DB01_CLEANUP_TIME=8640
    networks:
      - services
    restart: always

networks:
  proxy:
    #external: true    # 注释掉这两行,部署容器时才能自动创建网络
  services:
    #external: true

接下来,我们需要单独部署 Caddy 容器来提供 HTTPS 反向代理。

[student@rocky freescout]$ # 创建Caddy目录+设置权限(仅需执行一次)
[student@rocky freescout]$ mkdir -p ./caddy/{conf,data,logs} && chown -R 1000:1000 ./caddy/{data,logs} && chmod 755 ./caddy/{conf,data,logs}
[student@rocky freescout]$ tree caddy/
caddy/
├── conf
├── data
└── logs
3 directories, 0 files
[student@rocky freescout]$ cat caddy/caddy.yml
services:
  caddy:
    image: caddy:2.10.0-alpine
    container_name: freescout-caddy
    volumes:
      - ./conf/Caddyfile:/etc/caddy/Caddyfile  # 挂载配置文件
      - ./data:/data                           # 证书/数据持久化
      - ./logs:/var/log/caddy                  # 日志持久化
    ports:
      - "80:80"   # HTTP端口
      - "443:443" # HTTPS端口
    networks:
      - freescout_proxy    # 加入Freescout的proxy网络(关键!)
    restart: always  # 开机自启

# 加入Freescout创建的proxy网络(必须和Freescout的网络名一致)
networks:
  freescout_proxy:    # 网络名称可以用 docker network ls 命令查看
    external: true  # 表示该网络已由Freescout创建,直接复用
[student@rocky freescout]$ cat caddy/conf/Caddyfile
# 全局配置
{
    default_sni 192.168.0.115  # 替换为你的服务器内网IP
    servers :443 {
        protocols h1 h2 h3
    }
}

# HTTPS反向代理(指向Freescout)
192.168.0.115:443 {
    tls internal  # 自签名证书 也可以使用 Let’s Encrypt 申请的免费证书

    # 安全头(可选但推荐)
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "SAMEORIGIN"
        -Server
    }

    # 反向代理到Freescout的容器(核心)
    reverse_proxy freescout-app:80 {
        transport http {
            keepalive 3600s
            dial_timeout 10s
        }
        header_up X-Forwarded-Proto {scheme}
        header_up X-Forwarded-For {remote}
        header_up Host {host}
    }

    # 日志配置
    log {
        output file /var/log/caddy/freescout-access.log {
            roll_size 100MB
            roll_keep 5
        }
        format json
    }
}

# HTTP强制跳HTTPS
http://192.168.0.115 {
    redir https://{host}{uri} 301
}
[student@rocky freescout]$ docker compose -f compose.yml up -d
[student@rocky freescout]$ docker compose -f caddy/caddy.yml up -d
[student@rocky freescout]$ docker compose -f caddy/caddy.yml ps
[student@rocky freescout]$ docker compose -p freescout logs -f
[student@rocky freescout]$ docker compose -p caddy logs -f
[student@rocky freescout]$ curl -vvv -k https://192.168.0.115
*   Trying 192.168.0.115:443...
* Connected to 192.168.0.115 (192.168.0.115) port 443 (#0)
# 省略一些输出
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="refresh" content="0;url=https://192.168.0.115/login" />

        <title>Redirecting to https://192.168.0.115/login</title>
    </head>
    <body>
        Redirecting to <a href="https://192.168.0.115/login">https://192.168.0.115/login</a>.
    </body>
* TLSv1.2 (IN), TLS header, Unknown (23):
* Connection #0 to host 192.168.0.115 left intact
</html>
[student@rocky freescout]$ # http方式无法访问
[student@rocky freescout]$ curl -vvv http://192.168.0.115
*   Trying 192.168.0.115:80...
* Connected to 192.168.0.115 (192.168.0.115) port 80 (#0)
> GET / HTTP/1.1
> Host: 192.168.0.115
> User-Agent: curl/7.76.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 301 Moved Permanently
< Location: https://192.168.0.115/
< Server: Caddy
< Date: Wed, 21 Jan 2026 02:13:07 GMT
< Content-Length: 0
<
* Connection #0 to host 192.168.0.115 left intact
[student@rocky freescout]$

注意,此配置中 Caddy 监听了宿主机的 80 和 443 端口。访问 HTTP 地址 (http://192.168.0.115) 会被强制跳转到 HTTPS。

场景三:复杂生产场景:云主机的EIP(HTTPS 访问)

当我们需要将 FreeScout 部署在云服务器上,并通过公网 IP(EIP)访问时,配置会稍复杂一些。其核心在于处理 NAT 地址转换和反向代理的端口映射。请确保云服务器的安全组已放通相应端口。

下面的 Caddyfile 配置参考了另一篇关于 NextCloud 部署的文章,其中的关键配置已被证明是稳定可靠的。

[root@devops freescout]# cat freescout-with-proxy.yml
services:

  freescout-app:
    image: docker.io/tiredofit/freescout
    container_name: freescout-app
    volumes:
      - ./data:/data
      - ./logs/:/www/logs
    environment:
      - TIMEZONE=Asia/Shanghai
      - CONTAINER_NAME=freescout-app

      - DB_HOST=freescout-db
      - DB_NAME=freescout
      - DB_USER=freescout
      - DB_PASS=freescout

      - SITE_URL=https://225.105.121.8:28443  # 替换为你的实际EIP
      #- SITE_URL=http://freescout-app:80
      - TRUSTED_PROXIES=0.0.0.0/0

      - ADMIN_EMAIL=admin@admin.com
      - ADMIN_PASS=freescout

      - DISPLAY_ERRORS=FALSE

      - ENABLE_SSL_PROXY=TRUE
      #- ENABLE_SSL_PROXY=FALSE
    networks:
      - proxy
      - services
    restart: always

  freescout-db:
    image: docker.io/nfrastack/mariadb
    container_name: freescout-db
    volumes:
      - ./db:/data
    environment:
      - TIMEZONE=Asia/Shanghai
      - CONTAINER_NAME=freescout-db

      - ROOT_PASS=password
      - DB_NAME=freescout
      - DB_USER=freescout
      - DB_PASS=freescout
    networks:
      - services
    restart: always

  freescout-db-backup:
    container_name: freescout-db-backup
    image: docker.io/tiredofit/db-backup
    volumes:
      - ./dbbackup:/backup
    environment:
      - TIMEZONE=Asia/Shanghai
      - CONTAINER_NAME=freescout-db-backup

      - DB01_HOST=freescout-db
      - DB01_TYPE=mariadb
      - DB01_NAME=freescout
      - DB01_USER=freescout
      - DB01_PASS=freescout
      - DB01_BACKUP_INTERVAL=1440
      - DB01_BACKUP_BEGIN=0000
      - DB01_CLEANUP_TIME=8640
    networks:
      - services
    restart: always

  caddy:
    image: caddy:2.10.0-alpine
    container_name: freescout-caddy
    environment:
      - TIMEZONE=Asia/Shanghai
    volumes:
      - ./caddy/conf/Caddyfile:/etc/caddy/Caddyfile  # 挂载配置文件
      - ./caddy/data:/data                           # 证书/数据持久化
      - ./caddy/logs:/var/log/caddy                  # 日志持久化
    ports:
      - "28080:80"   # HTTP端口
      - "28443:443" # HTTPS端口
    networks:
      - proxy    # 加入Freescout的proxy网络(关键!)
    restart: always  # 开机自启

networks:
  proxy:
  services:

[root@devops freescout]# docker exec -it freescout-caddy cat /etc/caddy/Caddyfile
{
    # 保留Nextcloud成功的全局配置(解决TLS握手问题的核心)
    default_sni 225.105.121.8  # 替换为你的实际EIP
    servers :443 {
        protocols h1 h2 h3
    }
}

# 核心:监听225.105.121.8:443(容器内),对应宿主机28443端口
225.105.121.8:443 {
    # 保留稳定的TLS配置(复用Nextcloud的成功配置)
    tls internal

    # 保留通用安全头(无需改动)
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "SAMEORIGIN"
        -Server
    }

    # 保留压缩(无需改动)
    encode gzip

    # ========== 仅新增:Freescout反向代理(核心改动) ==========
    reverse_proxy freescout-app:80 {
        # 传递外部访问上下文(解决225.105.121.8:28443→freescout-app:80的地址映射)
        header_up Host {host}:28443
        header_up X-Forwarded-Proto https
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Port 28443

        # 保留长连接支持(复用Nextcloud的可靠配置)
        transport http {
            keepalive 300s
            read_timeout 3600s
            write_timeout 3600s
            dial_timeout 10s
        }
    }

    # 日志配置
    log {
        output file /var/log/caddy/freescout-access.log {
            roll_size 100MB
            roll_keep 5
        }
        format json
    }
}

# HTTP重定向:适配28080端口,重定向到HTTPS的28443
http://225.105.121.8 {  # 替换为你的实际EIP
    redir https://{host}:28443{uri} 301
}
[root@devops freescout]#
[student@rocky freescout]$ docker compose -f freescout-with-proxy.yml up -d
[student@rocky freescout]$ docker compose -f freescout-with-proxy.yml ps
[student@rocky freescout]$ docker compose -f freescout-with-proxy.yml logs -f
[student@rocky freescout]$ curl -vvv -k https://225.105.121.8:28443

在这个配置中,我们使用了非标准的 HTTP/HTTPS 端口(28080 和 28443),并将 Caddy 服务集成到了同一个 docker-compose.yml 文件中,管理起来更加方便。所有配置文件中的 EIP(225.105.121.8)都需要替换为你云服务器的实际公网 IP 地址。通过这套配置,你就可以通过 https://<你的EIP>:28443 从公网安全地访问部署好的 FreeScout 系统了。

总结

本文详细介绍了 FreeScout 开源客服系统三种不同复杂度的容器化部署方案,涵盖了从内网测试到公网生产的完整路径。利用 Docker 和 Docker Compose,我们可以快速、一致地搭建环境,大大简化了运维部署的复杂度。你可以根据实际需求选择合适的方案进行实践。如果在部署过程中遇到问题,欢迎到 云栈社区 的相关板块交流讨论。

在实践中学习




上一篇:AI芯片重塑供应链:台积电HPC营收超智能手机,英伟达订单量挑战苹果地位
下一篇:《明日方舟:终末地》技术研发解析:鹰角如何突破3D工业化与多端适配挑战
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-25 21:13 , Processed in 0.298872 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表