Documentation menuDocker and Railway

Running on Docker and Railway

bipanel runs on Docker and Railway as one container: Apache, PHP-FPM, MariaDB and the panel ship in the same image, and persistent data lives in the /data volume. It suits websites, databases and apps; email, a DNS server, FTP and system-level tools exist only on a server installation.

Last updated:

On this page
  1. What container mode is
  2. Docker Compose with Caddy
    1. What Caddy does
  3. Deploying on Railway
  4. Environment variables
  5. Persistent data: /data
  6. What is different in container mode
  7. Updating
  8. Resetting the admin password

#What container mode is

In a container installation bipanel is a single Debian-based image. It contains Apache 2.4 (mpm_event), PHP-FPM for PHP 8.2, 8.3 and 8.4, an embedded MariaDB, Node.js 22, Python 3, phpMyAdmin, git, rclone and certbot. The panel process starts Apache, PHP-FPM and MariaDB itself. Apache listens on the port in the PORT variable (8080 by default), and the panel and phpMyAdmin are reached through that port.

Unlike a server installation there are no separate admin and user ports. On the same address:

  • Server Admin: https://<panel address>/admin (first user admin)
  • User panel: https://<panel address>/panel

System users, Apache virtual hosts and PHP-FPM pools are not kept inside the container; they are rebuilt from the panel database in /data on every start. As long as the volume is attached, deleting and recreating the container or redeploying it is safe.

Licensing works the same way: without a license key the Community edition runs up to 3 hosting accounts, and Pro features need a Pro license. See Licensing and Pricing.

#Docker Compose with Caddy

On your own VPS you need Docker Engine 24 or later and Docker Compose v2. 2 GB of RAM works, 4 GB is recommended. You need a domain for the panel with an A record pointing at the server, and ports 80 and 443 open.

The release package includes Dockerfile, docker-compose.yml and deploy/caddy/Caddyfile. Get the package and the current commands from the Download page. After unpacking it, create a .env file in the folder with BIPANEL_PANEL_HOST, BIPANEL_ADMIN_PASSWORD and ACME_EMAIL, then run:

docker compose up -d --build
docker compose logs -f bipanel

The first start prepares the MariaDB data directory, so the panel can take a few minutes to come up. The image health check polls /api/health and allows 180 seconds for startup.

#What Caddy does

The compose file defines two services: bipanel, which publishes no ports, and caddy in front of it (80, 443 and 443/UDP). Caddy obtains a Let's Encrypt certificate for each domain on its first request, but only for domains registered in bipanel: before requesting a certificate it asks the panel's internal check endpoint. Plain HTTP is redirected to HTTPS. This setup sets BIPANEL_SSL_MODE=edge and BIPANEL_TRUST_PROXY_HOPS=2 (Caddy plus Apache), so brute-force protection sees the real client IP.

If you use another reverse proxy instead of Caddy, forward the X-Forwarded-For and X-Forwarded-Proto headers, leave the Host header unchanged, allow WebSocket upgrades (for the web terminal and live logs) and set BIPANEL_TRUST_PROXY_HOPS to the number of proxies plus one.

#Deploying on Railway

On Railway bipanel runs as a single service, and Railway's edge terminates TLS.

  1. Create a new project and pick the Docker image shown on the Download page, or your repository with the bipanel source code. The repository's railway.json sets /api/health as the health check with a 300-second timeout.
  2. Attach a volume mounted at /data. This is required; without it every deploy wipes all data.
  3. Set the BIPANEL_ADMIN_PASSWORD variable. Optionally add RAILWAY_API_TOKEN.
  4. Generate a public domain for the service and open Server Admin at /admin.

Railway only routes traffic to domains attached to the service. With RAILWAY_API_TOKEN set, bipanel attaches the domains you add in the panel to the Railway service itself and shows the DNS records you need to create; without it you add them in the Railway dashboard. Your Railway plan decides how many domains a service can have. Because Railway only accepts HTTP(S) traffic, services such as email, DNS and FTP cannot run there.

#Environment variables

VariableDefaultDescription
BIPANEL_ADMIN_PASSWORDrandomFirst admin password. If unset, a random one is generated, printed once in the log and saved to /data/initial-admin.txt. Used only on the first start.
BIPANEL_ADMIN_USERadminFirst admin's username.
BIPANEL_ADMIN_EMAILnoneFirst admin's email address.
BIPANEL_PANEL_HOSTRAILWAY_PUBLIC_DOMAIN on RailwayThe panel's domain. In a container the hostname cannot be changed from the panel; this variable sets it.
BIPANEL_SSL_MODEedge on Railway, acme on Dockeredge: an outer layer terminates TLS. acme: the panel obtains Let's Encrypt certificates itself with certbot. off: no certificate management.
BIPANEL_TRUST_PROXY_HOPS2 on Railway, 1 on DockerNumber of trusted proxies, Apache included.
PORT8080The port Apache listens on; Railway sets it for you.
BIPANEL_MYSQL_URL or MYSQL_URLnoneAn external MySQL/MariaDB server instead of the embedded MariaDB (e.g. mysql://root:password@mysql:3306).
BIPANEL_MYSQL_BUFFER_POOL128MInnoDB buffer pool of the embedded MariaDB; lower it on small plans.
BIPANEL_MAX_UPLOAD_MB1024File Manager upload limit in MB.
RAILWAY_API_TOKENnoneLets bipanel attach domains to the Railway service and update itself from the panel.
BIPANEL_SECRET/data/secret.keyThe panel's secret key (at least 32 characters). If unset, it is generated on first start and stored in the volume.

#Persistent data: /data

The only persistent directory in the container is the /data volume:

PathContents
/data/bipanel.dbPanel database: accounts, domains, settings
/data/home/<account>Account files
/data/mysqlEmbedded MariaDB data directory
/data/backups, /data/logs, /data/ssl, /data/jobsBackups, logs, certificates, job records

The installation identity and license settings live in this volume too. If the volume is lost, the installation starts from scratch and you have to enter the license key again. Sending account backups to a remote target with rclone is recommended (see Backups and migration).

#What is different in container mode

The following are not available in a container; the panel shows these screens as disabled, with the reason:

FeatureIn a container
Mail server and webmailNot available; email needs a server installation
Authoritative DNS serverNot available; the DNS zone editor gives record suggestions and the Cloudflare integration can be used
FTP, SSH and SFTPNot available; use the File Manager, the web terminal and Git deployment
Firewall and nftables DDoS protectionNot available; the platform manages networking. In-panel brute-force protection works
Disk quotasNot enforced; disk usage is only monitored
Per-account CPU and memory limits, account isolationNot available (no systemd); apps only get a process count limit
Disk ManagerNot available; the platform manages disks and volumes
Automatic OS security updatesNot available; packages come with the image
Server reboot, root password, DNS resolversNot available; managed from the platform dashboard
Remote desktop (Pro) and Podman containersNot available

What works: accounts and packages, domains, PHP 8.2–8.4, MySQL/MariaDB and phpMyAdmin, Node.js and Python apps, Git deployment, the App Installer, cron (through the panel's own scheduler), backups, the File Manager, the web terminal and the API. The installation report is always on in containers as well; what is sent is shown under Server Admin → Installation Report.

#Updating

A container installation does not update the panel in place the way a server installation does:

  • Docker: pull the new release's image, or rebuild from the new release package, and recreate the container. Data stays in the volume.
  • Railway: with RAILWAY_API_TOKEN set, an update started from Server Admin → Updates switches the service to the new release's image and starts a redeploy. Without it, redeploy from the Railway dashboard.

See Updates for release channels.

#Resetting the admin password

Changing BIPANEL_ADMIN_PASSWORD later does not reset the password. Run the reset tool inside the container (add --disable-2fa to also turn off two-factor authentication):

docker compose exec bipanel node /opt/bipanel/deploy/tools/reset-admin.mjs admin 'NewPassword123!'

The command-line tool is in the image too: docker compose exec bipanel bipanel account list (the token is read from /data/cli.token).

Something missing or wrong on this page? Let us know.