SquirrelMail 1.4.22 Docker Compose 部署指南

SquirrelMail 1.4.22 Docker Compose 双服务栈部署实测:自建 webmail(php:7.4-apache)与 Postfix/Dovecot 后端镜像、栈内协同机制、display_errors 打断登录的排障实录与生产化改造建议。

SquirrelMailSquirrelMail邮件服务2026/10/27

SquirrelMail 1.4.22 Docker Compose 部署指南

目标:用 Docker Compose 一键部署 SquirrelMail 1.4.22 + Postfix/Dovecot 邮件后端的双服务栈,完成登录与收信端到端验证。官方未提供任何官方镜像,本篇使用自建 Dockerfile(应用本体来自官方发布包,构建上下文内自带,离线可复现),并在文中明确标注;全部命令与回显来自 2026-10-27 在 Ubuntu 22.04 + Docker 实测。

一、环境信息

  • 宿主机:Ubuntu 22.04(jammy),x86_64
  • Docker:Compose v2(docker compose 子命令,项目名规范化为 squirrelmail-1422-stack)
  • 栈内镜像(均为自建,非官方镜像):
    • squirrelmail-1.4.22-webmail:local(基座 php:7.4-apache,实测构建后 657 MB)
    • squirrelmail-1.4.22-mail:local(基座 debian:12-slim,实测构建后 207 MB)
  • 应用本体:SquirrelMail 1.4.22 官方发布包(sha256 校验值同系列安装篇:286453c7aac6...b2d0b847)
  • 对外端口:宿主 8130 → webmail 服务 80(2026-10-27 实测宿主 8128–8152 段中 8130 空闲)
  • 栈内网络:squirrelmail-1422-stack_smnet,子网 10.89.61.0/24(实测已验证连通的槽位复用)
  • 演示账号:admin / q1w2e3r4(由 mail 服务入口脚本创建)
  • 目录约定:部署目录 squirrelmail-compose/,结构如下(本篇第二节逐一给出全部文件):
squirrelmail-compose/
├── docker-compose.yml
├── webmail/
│   ├── Dockerfile
│   └── squirrelmail-webmail-1.4.22.tar.gz   # 官方发布包
└── mail/
    ├── Dockerfile
    └── entrypoint.sh

二、部署文件详解(自建镜像标注)

2.1 docker-compose.yml

name: squirrelmail-1.4.22-stack

services:
  mail:
    build: ./mail
    image: squirrelmail-1.4.22-mail:local
    container_name: squirrelmail-1.4.22-mail
    hostname: mail.example.com
    restart: unless-stopped
    networks: [smnet]

  webmail:
    build: ./webmail
    image: squirrelmail-1.4.22-webmail:local
    container_name: squirrelmail-1.4.22-webmail
    depends_on: [mail]
    ports:
      - "8130:80"
    restart: unless-stopped
    networks: [smnet]

networks:
  smnet:
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.61.0/24

要点说明:

  • name: 显式声明 Compose 项目名为 squirrelmail-1.4.22-stack(Compose v2 会把项目名规范化为 squirrelmail-1422-stack,网络名即 squirrelmail-1422-stack_smnet,实测回显见第四章)。
  • 两个服务均为 自建镜像:SquirrelMail 官方从未发布 Docker 镜像(官网与 SourceForge 均无容器产物,2026-10-27 实查),image: 只是给本地构建结果命名;build: 才是镜像的真实来源。
  • 子网显式固定为 10.89.61.0/24,避免与其他在跑环境网段冲突;8130 为宿主 Web 入口。

2.2 webmail/Dockerfile(SquirrelMail 应用服务)

FROM php:7.4-apache

# 启用生产级 php.ini(镜像默认无 php.ini,display_errors=On 的 Warning 会打断 SquirrelMail 重定向流程)
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"

# 应用本体:SquirrelMail 1.4.22 官方发布包(构建上下文内自带,离线可复现)
ADD squirrelmail-webmail-1.4.22.tar.gz /usr/share/

# 数据与附件缓存目录(config.php 默认即指向 /var/local/squirrelmail/,无需改路径)
RUN mkdir -p /var/local/squirrelmail/data /var/local/squirrelmail/attach \
    && chown -R www-data:www-data /var/local/squirrelmail

# 生成 config.php:仅把 IMAP/SMTP 服务器从 localhost 指到栈内 mail 服务
RUN cp /usr/share/squirrelmail-webmail-1.4.22/config/config_default.php \
       /usr/share/squirrelmail-webmail-1.4.22/config/config.php \
    && sed -i "s/\$smtpServerAddress = 'localhost';/\$smtpServerAddress = 'mail';/" \
         /usr/share/squirrelmail-webmail-1.4.22/config/config.php \
    && sed -i "s/\$imapServerAddress = 'localhost';/\$imapServerAddress = 'mail';/" \
         /usr/share/squirrelmail-webmail-1.4.22/config/config.php \
    && chown -R www-data:www-data /usr/share/squirrelmail-webmail-1.4.22

# Apache:站点根直接指向 SquirrelMail 应用目录
ENV APACHE_DOCUMENT_ROOT=/usr/share/squirrelmail-webmail-1.4.22
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf \
    && sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf

EXPOSE 80

⚠️ 自建镜像标注与 PHP 版本依据:php:7.4-apache 基座是刻意选择——1.4.22 是 PHP 5 时代代码,实测在 PHP 8.x 下 Fatal error 不可运行(一票否决取证见《SquirrelMail 1.4.22 介绍与选型指南》第五章),PHP 7.4 为可用上限。官方发布包以 ADD 方式进入镜像,整个构建过程不需要访问外网(离线可复现)。

2.3 mail/Dockerfile 与 entrypoint.sh(Postfix + Dovecot 后端)

mail 服务 Dockerfile:

FROM debian:12-slim

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update \
    && apt-get install -y --no-install-recommends postfix dovecot-imapd \
    && rm -rf /var/lib/apt/lists/*

# SquirrelMail 1.4.22 走明文 PLAIN 认证,放开 Dovecot 明文限制(内网栈)
RUN sed -i 's/^#disable_plaintext_auth = yes/disable_plaintext_auth = no/' \
    /etc/dovecot/conf.d/10-auth.conf

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

EXPOSE 25 143

CMD ["/entrypoint.sh"]

entrypoint.sh:

#!/bin/sh
set -e

# 演示邮箱账号(与文档演示口径一致)
id admin >/dev/null 2>&1 || useradd -m -s /bin/bash admin
echo 'admin:q1w2e3r4' | chpasswd

# Postfix 本域投递配置
postconf -e "myhostname=mail.example.com"
postconf -e "mydestination=example.com, mail.example.com, localhost.localdomain, localhost"
postconf -e "mynetworks=127.0.0.0/8 [::1]/128"

service postfix start
service dovecot start

# 栈启动即投递一封验证邮件,便于首次登录即可见
printf "Subject: Welcome from compose stack\nFrom: root@example.com\nTo: admin@example.com\n\nThis is a smoke-test mail delivered inside the compose stack.\n" \
  | sendmail admin@example.com || true

exec tail -F /var/log/mail.log 2>/dev/null || tail -f /dev/null

要点说明:disable_plaintext_auth = no 与系列安装篇第八章同理(SquirrelMail 1.4.22 默认明文 PLAIN 认证,内网栈放开限制);演示账号与测试邮件在入口脚本一次性就位,栈起即用;末行 tail -F 让服务保持前台。

三、一键部署与验证步骤

3.1 准备文件与构建

把 2.1–2.3 的文件按第一章目录树落盘,并将官方发布包放入 webmail/ 目录(下载与校验方式见系列安装篇 10.1)。然后构建:

cd squirrelmail-compose
docker compose build

实测输出(节选,两个镜像均构建成功):

[+] Building 1.4s (12/12) FINISHED
 => => naming to docker.io/library/squirrelmail-1.4.22-webmail:local
[+] Building 41.4s (13/13) FINISHED
 => => naming to docker.io/library/squirrelmail-1.4.22-mail:local

构建后的镜像清单(实测):

docker images 'squirrelmail-1.4.22*' --format '{{.Repository}}:{{.Tag}} {{.Size}}'

实测输出:

squirrelmail-1.4.22-webmail:local 657MB
squirrelmail-1.4.22-mail:local 207MB

3.2 启动栈

docker compose up -d

实测输出:

[+] Running 3/3
 ✔ Network squirrelmail-1422-stack_smnet      Created
 ✔ Container squirrelmail-1.4.22-mail         Started
 ✔ Container squirrelmail-1.4.22-webmail      Started

核对运行状态与网络(注意网络名是项目名规范化后的 squirrelmail-1422-stack_smnet):

docker compose ps --format '{{.Name}} {{.Image}} {{.Status}}'
docker network inspect squirrelmail-1422-stack_smnet --format '{{.Name}} {{range .IPAM.Config}}{{.Subnet}}{{end}}'

实测输出:

squirrelmail-1.4.22-mail squirrelmail-1.4.22-mail:local Up 2 minutes
squirrelmail-1.4.22-webmail squirrelmail-1.4.22-webmail:local Up 14 seconds
squirrelmail-1422-stack_smnet 10.89.61.0/24

3.3 登录与收信端到端验证

入口:http://<宿主地址>:8130/src/login.php。命令行验证(与浏览器路径一致):

rm -f /tmp/sm_cookie
curl -s -c /tmp/sm_cookie -o /tmp/rd.html -w 'login POST HTTP:%{http_code}\n' \
  -d 'login_username=admin' -d 'secretkey=q1w2e3r4' \
  -d 'js_autodetect_results=0' -d 'just_logged_in=1' \
  http://127.0.0.1:8130/src/redirect.php
curl -s -b /tmp/sm_cookie -o /tmp/in.html -w 'right_main HTTP:%{http_code} SIZE:%{size_download}\n' \
  http://127.0.0.1:8130/src/right_main.php
grep -oE '<title>[^<]*</title>' /tmp/in.html

实测输出(302 为登录成功跳转;收件箱 200 且标题带版本号):

login POST HTTP:302
right_main HTTP:200 SIZE:5741
<title>SquirrelMail 1.4.22</title>

确认入口脚本投递的验证邮件出现在收件箱(主题 Welcome from compose stack,页面内空格转义为 &#32;):

grep -oE 'Welcome(&#32;|\s)from(&#32;|\s)compose(&#32;|\s)stack' /tmp/in.html

实测输出:

Welcome&#32;from&#32;compose&#32;stack

至此栈级端到端打通:webmail 服务(Apache+PHP+SquirrelMail)经栈内网络调用 mail 服务的 IMAP 认证成功、SMTP 收件正常。

四、栈内服务协同机制说明

  • 服务发现:webmail 的 config.php 把 IMAP/SMTP 服务器指向 mail(Compose 服务名),栈内网络自动提供 DNS 解析(实测从 webmail 侧 getent hosts mail 可解析到栈内地址,fsockopen('mail',143) 直接 LOGIN 成功)。
  • 依赖顺序:depends_on: [mail] 只保证启动顺序,不等待 mail 服务内 Postfix/Dovecot 就绪;mail 服务入口脚本在数秒内完成配置与启动,实测无竞态问题(webmail 首次登录即成功)。若后端就绪过慢出现登录失败,等几秒重试即可。
  • 配置生效方式:SquirrelMail 配置在 webmail 镜像构建时固化(config.php 写死栈内服务名);mail 侧配置在入口脚本启动时执行(postconf -e、dovecot 明文开关)。改配置 = 改文件 → docker compose up -d --build 重建对应服务。
  • 数据持久化:本栈为演示形态,用户偏好(.pref/.abook)与邮箱数据都落在服务实例内部,未挂数据卷;销毁栈即丢数据。生产化改造见第五章。

五、生产化改造建议

  • 挂载数据卷:mail 服务把 /var/mail(邮箱)与 /var/lib/postfix 挂 named volume;webmail 服务把 /var/local/squirrelmail(偏好与附件缓存)挂 named volume,避免栈重建丢数据。
  • 改密码与账号管理:演示账号在 entrypoint.sh 内明文建号,生产应改为 IMAP 虚拟域(SQL/LDAP 用户库)或至少把凭据移出镜像(环境变量/挂载文件注入)。
  • TLS:SquirrelMail 1.4.22 与明文 IMAP/PLAIN 均应置于反向代理(TLS 终止)之后,Dovecot 若对外暴露需启用 STARTTLS 并恢复 disable_plaintext_auth = yes。
  • 升级路径:无官方镜像意味着升级即换发布包重 build;但 1.4.22 之后上游再无版本(2011-07 至今),"升级"实际不存在,应把精力放在边界防护与迁移评估(迁移选型见《SquirrelMail 1.4.22 介绍与选型指南》第七章)。

六、常见问题(FAQ)

Q1:登录后浏览器显示 "Unknown user or password incorrect.",但凭据正确?

先看 Apache 响应/页面顶部是否有多行 Warning: session_set_cookie_params(): Cannot change session cookie parameters...。本篇实测时即遇到该问题:php:7.4-apache 基座默认未放置 php.ini(只有 development/production 模板),display_errors 为 On,SquirrelMail 1.4.22 的 functions/global.php:472 在 PHP 7.4 下触发该 Warning 并输出到页面,随后 "headers already sent" 打断 src/redirect.php 的重定向,登录失败。修复即在 webmail Dockerfile 构建阶段启用生产级 php.ini(见 2.2 第一段 RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"),重建后实测登录 302 恢复正常。

Q2:docker compose up 报网段子网冲突?

把 docker-compose.yml 中 10.89.61.0/24 换成宿主上未占用且不与其他 Compose 网络重叠的私有网段(用 docker network ls -q | xargs docker network inspect --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' 排查既有占用)。

Q3:webmail 页面能开,但登录一直转圈后失败?

用栈内直连分段定位:在 webmail 服务侧实测 fsockopen('mail',143) 是否 LOGIN 成功(本篇实测该路径正常),再测 mail 侧 doveadm auth test admin q1w2e3r4;两端通过而页面失败时,多半是 webmail config.php 的 imapServerAddress 未指向 mail(构建时 sed 未生效,回看 build 日志)。

Q4:宿主 8130 端口被占用想换端口?

只改 docker-compose.yml 的 "8130:80" 左侧宿主端口即可,栈内不变;改后 docker compose up -d 增量生效。

七、卸载与清理

cd squirrelmail-compose
docker compose down -v            # 移除栈与网络
docker rmi squirrelmail-1.4.22-webmail:local squirrelmail-1.4.22-mail:local   # 移除自建镜像

实测输出(down 阶段):

[+] Running 3/3
 ✔ Container squirrelmail-1.4.22-webmail  Removed
 ✔ Container squirrelmail-1.4.22-mail     Removed
 ✔ Network squirrelmail-1422-stack_smnet  Removed

清理后核对(应无输出):

docker images 'squirrelmail-1.4.22*' --format '{{.Repository}}'
docker ps -a --format '{{.Names}}' | grep squirrelmail

八、参考链接