# REFERENCE ONLY — install.sh GENERATES the real unit at install time, # substituting the actual PANEL_DIR/ports/user (see write_unit in install.sh). # This static copy assumes the /opt/panel defaults; edit it by hand if you wire # the units up yourself (e.g. via compose) instead of running install.sh. [Unit] Description=Panel controller (HTTP dashboard :8080 + agent gRPC :8443) Documentation=https://github.com/dbledeez/panel After=network-online.target docker.service Wants=network-online.target [Service] Type=simple # install.sh creates this user; change to taste. The controller does NOT # need docker access — only the agent does. User=panel Group=panel # The controller resolves ./data (CA, admin-token, cluster stores) and # ./modules relative to its working directory — keep them together here. WorkingDirectory=/opt/panel # Defaults first; /opt/panel/panel.env (PANEL_DB_URL, PANEL_HTTP_PORT, # PANEL_ADMIN_PASSWORD, ...) overrides them because it is applied later. Environment=PANEL_HTTP_PORT=8080 Environment=PANEL_GRPC_PORT=8443 EnvironmentFile=-/opt/panel/panel.env ExecStart=/opt/panel/bin/controller \ -http :${PANEL_HTTP_PORT} \ -grpc :${PANEL_GRPC_PORT} \ -ca-dir ./data/ca Restart=on-failure RestartSec=3 # Hardening — the controller only needs its own tree + the network. NoNewPrivileges=true ProtectSystem=strict ProtectHome=true ReadWritePaths=/opt/panel PrivateTmp=true ProtectKernelTunables=true ProtectKernelModules=true ProtectControlGroups=true RestrictSUIDSGID=true LockPersonality=true [Install] WantedBy=multi-user.target