
本文详解如何在 Azure App Service 的自定义 PHP/Apache 容器中安全启用 SSH,解决因 CMD 与 ENTRYPOINT 冲突导致容器启动失败、SSH 不可用的核心问题,并提供可直接复用的 init.sh 启动脚本与权限配置要点。
本文详解如何在 azure app service 的自定义 php/apache 容器中安全启用 ssh,解决因 `cmd` 与 `entrypoint` 冲突导致容器启动失败、ssh 不可用的核心问题,并提供可直接复用的 `init.sh` 启动脚本与权限配置要点。
在 Azure App Service 中为自定义 Docker 容器(如基于 php:7.4-apache-bullseye 构建的 PHP 应用)启用 SSH 是诊断运行时问题(如静态资源 400 错误、挂载存储权限异常、符号链接失效等)的关键手段。但实践中,直接在 Dockerfile 中安装 OpenSSH 并调用 service ssh start 常导致容器启动失败——错误日志中典型表现为 Container xxx has exited, failing site start 和 didn't respond to HTTP pings on port: 80。根本原因并非 SSH 配置错误,而是 App Service 容器生命周期模型与传统 Linux 容器启动逻辑的冲突:App Service 要求容器主进程(PID 1)必须是前台长期运行的守护进程;一旦 CMD 或 ENTRYPOINT 执行完毕且无前台进程驻留,容器即被判定为“崩溃”。
? 正确启用 SSH 的核心原则
-
禁止独立启动 SSH 作为后台服务
service ssh start仅启动 daemon 并立即返回,不阻塞进程,违反 App Service 对 PID 1 的要求。 -
必须保留应用主进程(如 Apache/Supervisor)作为前台任务
任何ENTRYPOINT脚本最终必须exec或直接运行主服务(如supervisord -n),确保其接管 PID 1。 -
SSH 必须与主服务共存,而非竞争
利用 App Service 内置的 SSH 网关机制(端口 2222),无需在容器内暴露 SSHD——但若需容器内调试(如检查挂载卷权限),则需在满足前台约束前提下集成。
✅ 推荐解决方案:轻量级 init.sh 启动脚本
将原 Dockerfile 中的 CMD [ "/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/supervisord.conf" ] 替换为 ENTRYPOINT ["init.sh"],并创建以下 init.sh(务必使用 #!/bin/sh,避免 bash 特性兼容性问题):
#!/bin/sh set -e # 生成 SSH 主机密钥(必需,否则 sshd 启动失败) ssh-keygen -A # 确保运行目录存在 mkdir -p /var/run/sshd # 启动 SSHD(作为后台服务,非前台) /usr/sbin/sshd -D & # 启动主应用服务(必须前台运行!) exec /usr/bin/supervisord -n -c /etc/supervisor/supervisord.conf
⚠️ 注意事项:
- 删除原 Dockerfile 中所有
CMD指令,仅保留ENTRYPOINT ["init.sh"];sshd -D以调试模式前台运行 SSHD(推荐),或使用service ssh start+sleep infinity(不推荐,增加不确定性);exec关键字确保supervisord接管 PID 1,避免产生僵尸进程;- 若使用
supervisord管理多个进程(Apache + cron),请确认其配置中apache进程设置为autostart=true且startsecs=1,避免因启动超时被 kill。
? 验证与连接方式
部署后,通过 Azure CLI 建立隧道并连接:
开发者平台元数据——GitHub、Docker Hub、crates.io 等生态系统注册表。使用此技能的时机:1. 解析 GitHub 仓库或获取其...
# 创建远程连接隧道(替换为你的实际参数)
az webapp create-remote-connection \
--subscription "your-sub-id" \
--resource-group "rg-name" \
--name "app-name" \
--port 2222
# 输出示例:
# Opening tunnel on port: 2222
# SSH is available { username: root, password: Docker! }新开终端连接容器:
ssh -p 2222 root@127.0.0.1 # 输入密码:Docker!
进入容器后,即可排查 .png 400 问题根源:
- 检查挂载存储路径权限:
ls -la /var/www/data_persistent/maps - 验证符号链接有效性:
ls -la /var/www/api/public/maps - 查看 Apache 错误日志:
tail -f /var/log/apache2/error.log - 测试文件读取:
curl -I http://localhost/public/maps/test.png
? 补充建议:提升生产环境安全性
-
禁用 root 密码登录:在
sshd_config中设置PermitRootLogin no,改用密钥认证(需配合 App Service 的托管身份或密钥注入); - 精简 SSH 配置:仅开放必要端口(2222),禁用密码认证(若使用密钥);
-
日志审计:将 SSH 登录日志重定向至
/home/Log并挂载到持久化存储; -
权限最小化:避免
chmod 777,改用chown www-data:www-data+chmod 755/644。
通过以上配置,你将获得一个既满足 App Service 生命周期要求、又支持深度运维诊断的稳定自定义容器环境。SSH 不再是部署障碍,而是排查静态资源、挂载卷、权限链路等问题的可靠入口。
















