# PanelAlpha Engine Tested: Can AI Manage VPS and Replace GitHub Self-hosted Runner?

> Canonical: https://vxi.me/en/posts/panelalpha-engine-vps-hosting-control-plane/
> Locale: en-us
> Published: 2026-10-08
> Updated: 2026-10-08
> Markdown: https://vxi.me/en/posts/panelalpha-engine-vps-hosting-control-plane.md

My production release path is fairly settled: code goes into GitHub, a protected workflow decides when to release it, and a Self-hosted Runner executes reviewed steps on the server. After seeing [PanelAlpha Engine on Show HN](https://news.ycombinator.com/item?id=49991829), my question was less about whether AI could help deploy an application. I wanted to know where an MCP control plane for the entire application lifecycle would fit beside that existing runner.

I tested PanelAlpha Engine v2.1.1 on a separate Ubuntu 24.04.2 VPS. At the time of this article's QA, that version was still the project's [latest GitHub release](https://github.com/panelalpha/panelalpha-engine/releases/tag/v2.1.1). There was no neat one-click success: on a machine with 1 vCPU, 1.9 GiB of RAM and 50 GB of disk, installation was still in the Engine stage after more than two hours. The last recorded progress was 70%, and I stopped the experiment.

That is not proof that PanelAlpha cannot be installed. What it showed me was that this is not a lightweight AI command executor. It is a Hosting Control Plane that reaches into Docker, networking, firewalls, project isolation, backups and monitoring. Even an unfinished installation gave me enough evidence to reconsider whether replacing my runner was the right goal.

## A clean VPS, not the production runner

The test started with a clean VPS. Docker was absent and `docker version` returned 127. Neither `iptables` nor `nft` was available, and the listening-port snapshot was essentially SSH and chrony. That baseline matters: the subsequent Docker and firewall changes could be attributed to installation rather than old configuration left on the host.

PanelAlpha's [installation documentation](https://github.com/panelalpha/panelalpha-engine/blob/1e19bbf22a49c638f9e886fde653e02bbdc4bea5/docs/02-getting-started/install.md) also makes the intended boundary clear: a new, dedicated Debian or Ubuntu VPS. The installer source includes handling for `systemd-resolved`, `/etc/resolv.conf`, Docker networking and host firewalls. I did not put it on the existing blog runner or another production machine.

Before execution, I downloaded the bootstrap script and calculated its SHA-256 rather than piping `curl` straight into a shell:

```console
$ curl -fsSL https://get.panelalpha.com/engine -o panelalpha-installer.sh
$ sha256sum panelalpha-installer.sh
5d3c436269e09f8a813073691f61ad18329c0b87a818cb7fc3481344ac8e2496
```

The tested version was pinned explicitly:

```console
$ bash /root/panelalpha-installer.sh --engine-version v2.1.1 --no-tui
```

The first attempt stopped early. Git was missing; the installer's attempt to install it encountered an unavailable dependency. The actual log was:

```text
git : Depends: liberror-perl but it is not installable
E: Unable to correct problems, you have held broken packages.
[ERROR] Failed to install git (required to fetch the installer).
```

That attempt exited with code 1. I did not classify it as failure of the PanelAlpha core: it was still preparing host dependencies. Later attempts entered a substantial system-package upgrade, with one execution exiting at 141. Continuing from there eventually brought the Engine installation into its image, network and firewall stages.

One detail corrected my initial expectation. The source has paths that modify `systemd-resolved` and `resolv.conf`, but this VPS had no `systemd-resolved.service` to begin with, and its resolver file already used external DNS. I observed no before/after change to that file. What the code can do and what this particular run actually did are different kinds of evidence.

## Installation stopped at 70%; the host had already changed

I collected another host-state snapshot before ending the experiment. Docker Engine was installed, at version 29.8.2, while the PanelAlpha progress file still reported:

```text
step: Installing PanelAlpha engine
progress: 70
```

`docker ps -a` was empty. Describing the result as ten running background containers would have been wrong. What I did verify was six PanelAlpha images, including composer, DNS proxy, Exim, metrics, Pure-FTPd and SFTP. Docker reported 795 MB of disk usage for the largest, composer.

The network changes were more striking. The baseline had no `iptables` or `nft` tools; by the later snapshot, UFW and Docker rules existed, along with PanelAlpha chains such as `PA-BUILD-EGRESS`, `PA-PUBLISHED`, `PA-TENANT-INPUT` and `PA-TENANT-NET`. Yet the listening ports were still only SSH and chrony. The Engine was not ready to serve external requests.

At the end, the cumulative RX counter on `eth1` was 1,508,426,817 bytes. I would not turn that into a claim that PanelAlpha downloaded 1.5 GB: the baseline omitted that counter, so system upgrades, SSH and other traffic could not be subtracted. The supported observation is narrower: during a clean-VPS installation lasting several hours, networking, Docker images and host firewalls changed substantially before application deployment even began.

That felt different from GitHub Runner plus Docker Compose. The runner is an execution channel driven by a GitHub workflow. PanelAlpha is building an application-hosting control plane. Its larger foundation makes sense when it also needs to manage isolation, domains, databases, files, backups and monitoring.

I stopped because spending more time forcing installation to finish would no longer answer my original selection question, not because I had established that PanelAlpha was a bad product. On this 1C2G machine, cold start and host mutation were already costs worth considering. Successful project deployment, whether failed releases retain the previous version, and backup restoration were all beyond the experiment. Official descriptions are not substitutes for those unperformed runtime tests.

## Why the `modify` permission still needs care

I never reached a working MCP server, but retained the earlier pinned-source audit. In v2.1.1, [ToolPolicy](https://github.com/panelalpha/panelalpha-engine/blob/1e19bbf22a49c638f9e886fde653e02bbdc4bea5/core/app/Mcp/ToolPolicy.php) sets an HTTP-method ceiling for three modes:

| Mode | Allowed methods |
| --- | --- |
| `readonly` | GET |
| `modify` | GET, POST, PUT, PATCH |
| `full` | GET, POST, PUT, PATCH, DELETE |

At first glance, `modify` sounds like permission to change things without dangerous deletion. The generated MCP tools make that interpretation too simple.

`project_delete` uses DELETE, so it falls outside the `modify` method ceiling. However, [`backup_restore`](https://github.com/panelalpha/panelalpha-engine/blob/1e19bbf22a49c638f9e886fde653e02bbdc4bea5/core/app/Mcp/Tools/Api/Backups/BackupRestoreTool.php) and [`project_push`](https://github.com/panelalpha/panelalpha-engine/blob/1e19bbf22a49c638f9e886fde653e02bbdc4bea5/core/app/Mcp/Tools/Api/Projects/ProjectPushTool.php) both use POST and both carry an `IsDestructive` marker. At this verb-ceiling layer, they can fall within `modify`.

This is not a finding of an unauthorized-access vulnerability. Before registering tools, the Engine also applies toolsets, denylists and TokenAbilities scopes. Backup restoration requires `confirm=true` as well. I did not finish dynamic rejection tests with real tokens, so I have no runtime evidence of whether those protections can be bypassed.

The engineering lesson is straightforward: banning DELETE does not prevent an agent from overwriting important state. Restoring a backup, pushing staging to live or rebuilding a project may all use POST. I would start an infrastructure agent at `readonly`, then explicitly narrow its toolset and denylist rather than relying on the three mode names.

Backup and telemetry observations also stayed at the source/documentation level. The official [Backups documentation](https://github.com/panelalpha/panelalpha-engine/blob/1e19bbf22a49c638f9e886fde653e02bbdc4bea5/docs/05-capabilities/backups.md) says scheduling is not built in and needs something external such as cron; restoration overwrites current project state. Telemetry documentation distinguishes `pae telemetry:disable` from leaving `PANELALPHA_MONITORING=` empty. The former stops scheduled six-hour health checks; the latter is described as retaining local checks without sending reports to the monitoring endpoint. I did not exercise either behavior dynamically. These are v2.1.1 documentation facts, not results of this VPS test.

## I am keeping the Self-hosted Runner

Comparing this experiment with my existing [ChatGPT Web + GitHub + Self-hosted Runner workflow](/en/posts/chatgpt-web-github-self-hosted-runner/), I now think the replacement question was too narrow.

| | GitHub Self-hosted Runner | PanelAlpha Engine |
| --- | --- | --- |
| Main responsibility | Execute jobs controlled by GitHub workflows | Manage application and server-hosting lifecycles |
| Core state | Git commits, workflows and releases | Projects and hosting state inside the Engine |
| AI integration | An agent edits code/workflows; GitHub executes them | An agent can operate the control plane through MCP/API |
| Host involvement | Depends on what the workflow does | Docker, networking and firewall foundations start during installation |
| Evidence from this test | Existing production chain already in regular use | Installation to 70% and some host changes only |

For my blog, small services and a few self-hosted projects, I am keeping GitHub, Self-hosted Runner and Docker Compose. I have not proved that the runner is safer or faster. It simply already aligns with my source of truth, PR review and release path. A new privileged Hosting Control Plane does not yet offset the extra state and infrastructure it introduces.

The positioning becomes more reasonable when managing dozens of applications, with unified domains, databases, files, backups and isolation, and a real need for a Coding Agent to manage them through a constrained interface. PanelAlpha is not a fancier `docker compose up`; it is trying to turn a traditional hosting panel into infrastructure APIs an agent can call.

Ending at installation was enough for this decision. The test did not tell me what a fully running PanelAlpha deployment feels like, but it answered my practical question: reliably releasing reviewed code to a few servers does not currently justify adding a full VPS control plane merely for the AI interaction.

For another test, I would use a fresh VPS with more resources and begin with the MCP rejection matrix for `readonly`, `modify` and `full`, then failed releases, remote backup restoration and actual telemetry behavior. Those results would support a discussion of a long-term AI operations interface, rather than installation experience alone.
