This repository builds and publishes Docker images for 1Panel using the DooD (Docker-out-of-Docker) design. It reuses the host Docker engine and uses supervisord to manage 1Panel processes, avoiding running systemd in containers or using --privileged.
- Current latest image version: 2.1.7
- Multi-version support: 2.0.0 ~ 2.1.7 (injected by placeholder replacement)
- Multiple OS: ubuntu, centos, alpine
- Multi-arch: amd64, arm64 (buildx + QEMU)
- Image naming: caijiamx/1panel:dood-{version}-{os}
- Build method: GitHub Actions workflow + local Makefile
Note: This solution targets trusted, single-tenant environments. For production, strictly control access and deploy proper protections (recommend WAF + network firewall).
- DooD: Containers share the host Docker engine and cache for faster builds and smaller footprint.
- Process management: Do not run systemd in the container; instead use supervisord (foreground) to manage 1panel-core and 1panel-agent.
- Version variable injection: Dockerfile contains placeholders, example (ubuntu):
During build, sed replaces {%OnePanel_Version%} with a concrete version (2.0.0~2.1.7).
RUN bash /1panel/quick_start.sh v{%OnePanel_Version%} - Multi-arch: buildx + QEMU produce linux/amd64 and linux/arm64 images; scripts auto-detect archive arch and download the correct package.
- OS: ubuntu, centos, alpine
- Versions: 2.0.0 ~ 2.1.7
- Architectures: amd64, arm64 (auto-match download)
- Tag format:
- caijiamx/1panel:dood-{version}-{os}
- Example: caijiamx/1panel:dood-2.1.7-ubuntu
Username, password, and port are auto-generated at image build; you can adjust them after the container starts. Assume the panel port is 8888. Example:
docker run -d --name 1panel --restart unless-stopped \
-p 8888:8888 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /var/lib/docker/volumes:/var/lib/docker/volumes \
-v /1panel_app/data/:/opt/ \
caijiamx/1panel:dood-2.1.7-ubuntuInitialization (inside container):
Important reminder x3:
Change username/password/entry on first deployment!
Change username/password/entry on first deployment!
Change username/password/entry on first deployment!
docker exec -it 1panel bash
# Check security entry and current settings
1panel user-info
# Change port/user/password
1panel update port
1panel update username
1panel update passwordAn example docker-compose.yml is provided (with required DooD mounts):
services:
one_panel:
image: caijiamx/1panel:dood-2.1.7-ubuntu
container_name: 1panel
restart: unless-stopped
ports:
- "8888:8888"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
- /1panel_app/data/:/opt/Key fields in docker-compose.yml:
- image: e.g., caijiamx/1panel:dood-2.1.7-ubuntu
- ports: external port mapping, e.g., 8888:8888
- volumes (required for DooD):
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
- /panel_app/data/:/opt/ # unify this path for data persistence
- healthcheck: simple process check (core/agent present)
- extra_hosts: host-gateway to access the host
- networks: use external network one_panel (create first)
Start:
docker network create one_panel
docker compose up -d
Notes:
- No --privileged, no /sys/fs/cgroup mount, no systemd inside the container.
- Persist /opt/ (default install path /opt/1panel).
# Ubuntu
docker pull caijiamx/1panel:dood-2.1.7-ubuntu
# CentOS
docker pull caijiamx/1panel:dood-2.1.7-centos
# Alpine
docker pull caijiamx/1panel:dood-2.1.7-alpineReplace {version} with 2.0.0~2.1.7 and {os} with ubuntu/centos/alpine.
alpine/ # Alpine Dockerfile template
centos/ # CentOS Dockerfile template
ubuntu/ # Ubuntu Dockerfile template
hack/ # install and systemctl-comment scripts, supervisord config
hack_cn/ # install and systemctl-comment scripts, supervisord config
.github/workflows/main.yml # GitHub Actions: multi-version/os/arch build & push
docker-compose.yml # container run config
Makefile # local build/push/matrix
- Script: hack/fix_systemctl_start_cmd.sh
- Purpose: After extracting the installer and before running install.sh, comment out systemctl-related steps to avoid systemd dependency.
- Impact: Panel checks/operations based on systemctl may not work or display incorrectly; process management is handled by supervisord.
Generated by GitHub Copilot on 2025-09-09
Based on 1Panel-dev/1Panel code, the following services are mainly managed by systemctl. If systemctl is unavailable (e.g., WSL, some containers, minimal distros), start/stop/restart/status will be affected and some panel features will be unavailable or abnormal.
| Service Name | Description | Impact when systemctl unavailable | Code references | Notes |
|---|---|---|---|---|
| 1panel-core.service | 1Panel core service | Cannot start/restart/query; core broken | core/app/service/setting.go, common.go, core/app/service/upgrade.go, RestartService (common.go), UpdateBindInfo/UpdatePort/UpdateSSL (setting.go), UpgradeService.Upgrade | Config, port, SSL, master, upgrade, rollback |
| 1panel-agent.service | 1Panel agent (node) | Cannot start/restart/query; node issues | agent/utils/common.go, common.go, core/app/service/upgrade.go, RestartService (common.go), UpgradeService.Upgrade | Node restart, post-upgrade restart, recovery |
| docker.service, docker.socket | Docker daemon | Container mgmt features unusable | agent/app/service/docker.go | Container services, config changes restart |
| fail2ban.service | Fail2Ban anti-bruteforce | Rules cannot be toggled/reloaded/status | agent/utils/toolbox/fail2ban.go | Enable/disable/reload/status |
| clamav/clamd/freshclam | ClamAV antivirus | AV and DB updates unusable | agent/app/service/clam.go | Start/stop/scan/update |
| ssh/sshd.service | SSH service | Remote mgmt/SSH config issues | agent/app/service/ssh.go | Start/stop/config/hardening |
| supervisor/supervisord | Supervisor process manager | Process guarding unavailable | Frontend copy/scripts | Start/stop tasks, automation, script run |
- All services managed by systemctl depend on systemd.
- Code invokes systemctl (restart, start, stop, status, is-active, is-enabled).
- If systemctl is unavailable, commands fail; panel cannot control services.
- Docker, SSH, Fail2Ban, ClamAV, Supervisor are integrated via systemctl.
- Panel calls systemctl to restart/check status; failures break features.
- Some detection via snap exists (agent/utils/systemctl/systemctl.go) but depends on snap and is not a general replacement.
- Panel self-services (core/agent) are also managed via systemctl.
- The panel cannot self-restart/recover; cannot manage nodes remotely.
- Panel shows services abnormal or not running
- Cannot start/stop Docker, Agent, SSH, Supervisor via panel
- Some config changes won’t take effect automatically (e.g., port, SSL)
See also: Service & Feature Limitations.
- /api/v1/setting/update_port — after change, RestartService uses systemctl to restart core
- /api/v1/setting/update_ssl — triggers systemctl restart core
- /api/v1/upgrade/upgrade — UpgradeService.Upgrade calls systemctl restart core/agent
- /api/v1/upgrade/rollback — handleRollback calls systemctl to restart core/agent
- /api/v1/docker/restart — OperateDocker triggers systemctl restart docker
- /api/v1/agent/restart — restart agent service
- /api/v1/fail2ban/operate — toggle security rules
- /api/v1/clam/operate — toggle antivirus
- /api/v1/ssh/operate — toggle SSH service
- /api/v1/supervisor/operate — toggle supervisor
Upgrade-related systemctl calls:
- In core/app/service/upgrade.go, UpgradeService.Upgrade may call:
- systemctl daemon-reload
- systemctl restart 1panel-agent.service
- systemctl restart 1panel-core.service
- Rollback also restarts related services.
- In other branches/history, functions like handleRollback/handleBackup may call systemctl daemon-reload && systemctl restart 1panel.service.
- Config: hack/supervisord.conf (nodaemon=true, foreground)
- Programs:
- program:1panel-core -> /usr/bin/1panel-core
- program:1panel-agent -> /usr/bin/1panel-agent
- Common commands:
supervisorctl status
supervisorctl restart all
supervisorctl reloadTo run systemd in Docker typically:
docker run -d -it \
--name ubuntu2404-systemd \
--privileged \
--cgroupns=host \
--tmpfs=/run \
--tmpfs=/tmp \
--volume=/sys/fs/cgroup:/sys/fs/cgroup:rw \
trfore/docker-ubuntu2404-systemd:latestKey risks of --privileged + --cgroupns=host + /sys/fs/cgroup mount:
- Host isolation breaks
- --privileged grants all Linux capabilities (cap_sys_admin, cap_net_admin, etc.), effectively root.
- Can operate host devices, network stack, even load kernel modules.
- cgroup leakage
- With --cgroupns=host and /sys/fs/cgroup mounted, the container can manipulate host cgroups, change CPU/mem limits, kill processes of other containers.
- Host privilege escalation/escape
- A privileged container is effectively host root; isolation is compromised.
- If an attacker gets a shell, they effectively get host root.
- Do not use --privileged in production.
- Running systemd in Docker is not feasible in current stage.
- Use supervisord as an alternative for service management.
Reference repos:
- https://github.com/trfore/docker-ubuntu2404-systemd
- https://github.com/antmelekhin/docker-systemd
- Use only for development environments.
This guide provides an “unofficial” 1Panel Docker deployment:
- DooD (Docker Out of Docker) means invoking the external Docker from within a container. The simplest approach is to share the host Docker sock and volumes.
- With DooD, reuse the host Docker engine and manage processes with supervisord, avoiding systemd and --privileged within the container.
- Use cautiously in trusted/single-tenant scenarios. Configure security rules (WAF, firewall).
The container must reuse the host Docker for app install/orchestration; mount:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
- Data persistence (map /1panel_app/data/ to /opt/ in the container)
docker-compose.yml snippet:
# Key configuration
volumes:
# make docker out of docker work
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
- /1panel_app/data/:/opt/- DooD (used in this guide)
- Pros: share host image cache; fast builds, small footprint; simple to implement
- Cons: high security risk (container controls host Docker), not for multi-tenant
- Use cases: local/trusted, personal or single-tenant CI
- DinD
- Pros: isolates engine inside container
- Cons: requires --privileged, escape risk
- Use cases: temporary/non-production security scenarios, use cautiously
- Sysbox
- Safer DinD alternative, but requires specific kernels/distros; ecosystem less mature
Conclusion:
Adopt DooD + supervisord for now; explicitly avoid running systemd with --privileged in production.
| Dimension | DooD (Docker-out-of-Docker) | DinD (Docker-in-Docker) | Sysbox |
|---|---|---|---|
| Principle | Mount host Docker socket; reuse host engine | Run an independent Docker engine inside the container | Use Sysbox runtime; safely run Docker/K8s-like system workloads in containers |
| Pros | - Reuse host cache → fast builds, low disk usage | - Easy to use, official DinD images exist - Engine isolation | - No privileged container - User namespace isolation - Proc/sysfs virtualization - Good for system workloads |
| Cons | - High security risk: container can control host Docker; not for multi-tenant - Bind mount limitations may affect some features | - Needs privileged; root in container ~= root on host; escape risk | - Requires newer kernels/distros; community still evolving |
| Security | High risk | High risk | Relatively lower risk |
| Scenarios | Local dev/testing; single/trusted environment | CI/CD requiring separate Docker env; simple sandbox | Multi-tenant CI runners; secure sandbox; run system workloads |
| Recommendation | Recommended with access control | Use with caution (non-production) | Not recommended (complex setup) |
Reference:
- Docker-in-Docker: Containerized CI Workflows: https://www.docker.com/resources/docker-in-docker-containerized-ci-workflows-dockercon-2023/
Dependencies: Docker Desktop (with buildx), logged in to DockerHub (for push if needed).
List commands:
make helpCommon commands:
- Initialize builder (once): make builder
- Build single image (no push): make build OS=ubuntu VERSION=2.1.7 ONEPANEL_TYPE=cn
- Push single image: make push OS=centos VERSION=2.1.7 ONEPANEL_TYPE=cn
- Local debug (load to local): make load OS=ubuntu VERSION=2.1.7
- Multi-arch build (no push): make buildx OS=centos VERSION=2.1.7
- Multi-arch build and push: make push OS=alpine VERSION=2.1.7
- Matrix push (3 OS × 2.0.0~2.1.7): make matrix-push
Variables:
- OS=ubuntu|centos|alpine
- VERSION=2.0.0~2.1.7 (inject into {%OnePanel_Version%})
- ONEPANEL_TYPE=pro|cn (inject into {%OnePanel_Type%})
- PLATFORMS=linux/amd64,linux/arm64 (can set single)
- IMAGE_REPO=caijiamx/1panel, IMAGE_TAG_PREFIX=dood
Examples
# Dry-run a target
make -n build OS=ubuntu VERSION=2.1.7 ONEPANEL_TYPE=pro
# Build a single image
make build OS=ubuntu VERSION=2.1.7 ONEPANEL_TYPE=proTag convention: caijiamx/1panel:dood-{version}-{os}
Workflow: .github/workflows/main.yml (“Build and Push 1Panel Images”)
- Triggers: push to main/dev or manual workflow_dispatch
- Matrix: OS=[ubuntu, centos, alpine]; VERSION=[2.0.0..2.1.7]
- Multi-arch: linux/amd64, linux/arm64 (setup-qemu + buildx)
- Version replacement: sed replaces v{%OnePanel_Version%} in Dockerfile before build
- Push target: caijiamx/1panel:dood-{version}-{os}
- Secrets required in repo:
- DOCKERHUB_USERNAME
- DOCKERHUB_TOKEN
- Usage: On Actions page, select main workflow, click Run workflow, choose os and version
Upgrade example from v2.0.0 -> v2.1.7. Preparations:
- Backup the original image (e.g., v2.0.0)
- Backup mounted data
- Stop the container
- Build/pull the new image (e.g., 2.1.7)
- Manually update the version number
- Start the new service
Official installs maintain version automatically; this image requires manually syncing the version (sqlite3 example):
sudo apt-get update && apt-get install -y sqlite3
cp /opt/1panel/db/core.db /opt/1panel/db/core.db.bak
cp /opt/1panel/db/agent.db /opt/1panel/db/agent.db.bak
sqlite3 /opt/1panel/db/core.db "UPDATE settings SET value='v2.1.7' WHERE key='SystemVersion';"
sqlite3 /opt/1panel/db/agent.db "UPDATE settings SET value='v2.1.7' WHERE key='SystemVersion';"After updating image, restart the container (preserve /opt/ volume).
- Panel -> bottom-right update -> “Upgrade Now” is unavailable. Official upgrade logic depends on systemctl.
Panel -> container features unavailable. Service liveness check depends on systemctl status; will be optimized to remove dependency.- nginx_status listens on 127.0.0.1 by default; adjust accordingly. See: OpenResty status error.
- Some app install mount paths may be incorrect; fix per actual paths.
- 1panel-core & 1panel-agent run as root. Running under user nobody will make 1panel-agent crash.
- Toolbox -> Process Guard, FTP, Fail2ban unavailable.
- Version v2.1.7 improves the Docker service decision logic, and the Panel->Container function is basically available (the full functionality has not been fully tested).
- Version v2.1.7 adds disk management, which is not recommended.
Panel Unavailable Functions
| Function | Available | Remarks |
|---|---|---|
| Panel -> Upgrade Now (bottom right corner) | ❌ | |
| Website -> Website -> OpenResty Settings -> Current Status Website -> Runtime Environment -> php-fpm container status check |
❌ | |
| Toolbox -> Process Supervisor, FTP, Fail2ban, Disk Management | ❌ | Function not tested |
| Advanced Features | ❌ | Function not tested |
- Cause: host path vs container path mismatch (file/dir)
- Fix: correct the host path and mappings according to the app
Example:
# docker-compose.yml inside container
- ${WEBSITE_DIR}:/www -> /1panel_app/data/1panel/www:/www
# Default 1panel project dir inside container: /opt/1panelCommon variables
# Variables used by 1panel in docker-compose.yml
${CONTAINER_NAME} # custom container name
${IMAGE_NAME} # custom image name
${PANEL_APP_PORT_HTTP} # custom port
${PANEL_WEBSITE_DIR} # defaults to /opt/1panel/www
${WEBSITE_DIR} # defaults to /opt/1panel/www
Error:
服务内部错误: Get "http://127.0.0.1/nginx_status": dial tcp 127.0.0.1:80: connect: connection refused
Cause: health check to 127.0.0.1 fails; inside the container 127.0.0.1:80 points to 1panel, while openresty is a separate container. 1panel -> openresty should use http://openresty.
Fix it with add host alias: server_name 127.0.0.1 openresty; . Correct visit URL: http://openresty/nginx_status.
A complete fix requires code changes:
// agent/app/service/nginx.go
func (n NginxService) GetStatus() (response.NginxStatus, error) {
// bala
url := "http://127.0.0.1/nginx_status"
if httpPort != 80 {
url = fmt.Sprintf("http://127.0.0.1:%v/nginx_status", httpPort)
}
useDoodMode := true
if useDoodMode {
localServerName := "127.0.0.1"
openrestyContainerName := "openresty"
url = strings.ReplaceAll(url, localServerName, openrestyContainerName)
}
// bala
}WebSocket/upgrade headers:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host; # set explicitly if you need a fixed backend Host- After enabling security entry, check inside container: 1pctl user-info
- On first deployment, change username/password/entry
- Recommend WAF + network firewall to control access
- HTTP: 80, 8080, 8880, 2052, 2082, 2086, 2095
- HTTPS: 443, 2053, 2083, 2087, 2096, 8443
Low CPU limits may cause API timeouts (occasional 5xx/timeouts). Recommend 1.0~1.5 core.
- DooD allows the container to control the host Docker; there are security risks. Use only in trusted, single-tenant environments.
- Configure network firewalls to allow only necessary IPs and ports.
- Restrict access to the panel: domain, IP/port, machine isolation.
- GeekWho geekwho_eth@outlook.com