[Blog](https://deploywithox.com/blog) [Guides](https://deploywithox.com/blog#c-guides) # How to self-host phpMyAdmin on your own VPS, no Docker Run phpMyAdmin 5.2.3 on your own Ubuntu server with ox: FrankenPHP, a private MariaDB database and one variable, from the config that passed its test. Saurav Sharma Oct 17, 2026 9 min read On this page - [What you need](https://deploywithox.com/blog/self-host-phpmyadmin#what-you-need) - [The steps](https://deploywithox.com/blog/self-host-phpmyadmin#steps) - [The ox.toml, line by line](https://deploywithox.com/blog/self-host-phpmyadmin#config) - [MariaDB for this project only](https://deploywithox.com/blog/self-host-phpmyadmin#services) - [Updates and backups](https://deploywithox.com/blog/self-host-phpmyadmin#updates) - [Frequently asked questions](https://deploywithox.com/blog/self-host-phpmyadmin#faq) To self-host phpMyAdmin you need an Ubuntu server, a fork of the phpMyAdmin repo with one `ox.toml` file added, and one variable. In our run the first deploy took about 3 minutes, and ox set up a MariaDB database for it to manage. **How we tested** On Oct 17, 2026, ox deployed phpMyAdmin 5.2.3 from commit [`962857e4`](https://github.com/phpmyadmin/phpmyadmin/commit/962857e4f63d42e38f11ff4d63f5e722018add76) on a fresh DigitalOcean server with 8 vCPUs and 16 GB of memory. The run then redeployed it, backed it up and rebooted the server. Then a separate test agent, one that did not write the config, signed in, created a table, inserted a row, and saw the row when browsing the table, and checked the app's services and its backup. [phpMyAdmin](https://github.com/phpmyadmin/phpmyadmin) is a web interface for MySQL and MariaDB. In the browser you look through tables, edit rows, run SQL, and import or export data. It is written in PHP and released under the GNU General Public License, version 2 only. It has no user accounts of its own. You sign in with the name and password of a database user, and phpMyAdmin works as that user. ox deployed phpMyAdmin 5.2.3 (commit 962857e4) on Oct 17, 2026 on a fresh DigitalOcean server with 8 vCPUs and 16 GB of memory; the first deploy took 3 minutes and a redeploy took 72 seconds. - **First deploy:** 3 minutes, from adding the project until the app passed the run's first checks. - **Redeploy of the same commit:** 72 seconds, until the app passed the checks again. - **Server:** DigitalOcean, 8 vCPUs and 16 GB of memory (`s-8vcpu-16gb`), with this app alone on it. Every one of the 85 apps we deployed ran on this one size, so it was not picked for this app. - **Memory in use after the reboot:** 757 MB of 15986 MB, for the whole server: Ubuntu, the app, its services, Caddy and the ox agent. On a server with no apps, ox's tests on real servers hold the agent to 40 MB or less and Caddy to 50 MB or less. - **Services ox runs for it:** `mysql`. - **Source:** [github.com/phpmyadmin/phpmyadmin](https://github.com/phpmyadmin/phpmyadmin) at 5.2.3, commit [`962857e4`](https://github.com/phpmyadmin/phpmyadmin/commit/962857e4f63d42e38f11ff4d63f5e722018add76). The phpMyAdmin log-in page The phpMyAdmin home after logging in, connected to the local MariaDB The verify_notes table with the row the test agent inserted ## What you need - An Ubuntu LTS server. The run used the size in the facts above and measured the memory there. The database runs on it too. - A GitHub account to fork `phpmyadmin/phpmyadmin`, and an ox account, which you open by signing in with GitHub. - A long random string for `PMA_BLOWFISH_SECRET`. No mail server and no outside API key are part of this setup. - Not tested: importing or exporting files, and connecting phpMyAdmin to any database server other than the project's own. ## The steps Open the ox dashboard and choose Add a server. It shows an install command with a fresh token. Run it as root on your server. It adds only the ox agent and Caddy. Fork `phpmyadmin/phpmyadmin` and check out the tag `RELEASE_5_2_3`, the name phpMyAdmin gives release 5.2.3, which is what the run deployed. Add the `ox.toml` shown below at the root of the repo, then commit and push. Next, on your laptop, write one line in a file named `phpmyadmin.env`: `PMA_BLOWFISH_SECRET=` followed by your random string. The config below hashes whatever it gets down to the 32 bytes phpMyAdmin wants, so the output of `openssl rand -hex 32` will do. With the [ox CLI](https://deploywithox.com/docs/cli) signed in, run: Shell ```bash ox new /phpmyadmin ox review phpmyadmin --from-file phpmyadmin.env --wait ``` ox names the project after the repo, so it is `phpmyadmin`. The review saves the value and starts the first deploy, and `--wait` prints the run until it ends. In the browser the same two steps are New project and the review screen, and the [quickstart](https://deploywithox.com/docs/quickstart) walks through both. When the deploy is green you still need a login, since phpMyAdmin has no sign-up. ox made a database user and password along with the MariaDB and put them in the key `MYSQL_URL`. Print them with: Shell ```bash ox services phpmyadmin --reveal ``` The URL has the form `mysql://app:@127.0.0.1:/app`, so the user is `app` and so is the database. A reveal goes into your audit log. Open the address ox shows for the project and sign in as `app`. A wrong password is refused with MariaDB's own access denied message. After sign-in, click the database `app` in the left panel. The test agent made a table with an `id` column and a `body` column, added a row on the Insert tab, and saw it under Browse, then saw it again after a reload. The run served phpMyAdmin on its preview address only. A domain of your own was not part of it, and the [domains page](https://deploywithox.com/docs/operate/domains) covers how ox adds one. The home page may say the configuration storage is not completely configured. That storage is a set of optional tables behind bookmarks and SQL history. The run did not set them up, and the table work did not need them. ## The ox.toml, line by line TOML ```toml # phpMyAdmin 5.2 from a git checkout (doc/setup.rst, Installing from Git): # FrankenPHP serves the repo root, and the composer and yarn installs are # detected. It manages the project's own MariaDB: sign in with the user and # password of MYSQL_URL (`ox services --reveal`). # # config.inc.php is git-ignored, so the build writes it; it reads its values # from the environment as each request runs, so no secret lands in the release. packages = ["gettext"] required_variables = ["PMA_BLOWFISH_SECRET"] [build] # The detected yarn install runs package.json's postinstall, `yarn run build`, # so the list leaves that step out. Then the release recipe # (scripts/create-release.sh): compile the translations, drop the incomplete. commands = [ "./scripts/generate-mo --quiet", "./scripts/remove-incomplete-mo", ''' cat > config.inc.php <<'PHP'