Run mybase on one cloud VM (EC2, Compute Engine, Azure VM): sizing, firewall, Cloudflare Tunnel or Tailscale, disks, snapshots.
mybase runs the same on a cloud VM as on a Raspberry Pi: one Linux machine with Docker, the compose stack from Self-hosting, and mybase server setup. Every provider below follows the same shape:
Create one VM (arm64 or amd64, Ubuntu 24.04) with an SSD disk.
Allow only SSH in the cloud firewall (or nothing, with the provider's SSH proxy).
Install Docker, then run the setup wizard.
Reach it through a Cloudflare Tunnel (public) or Tailscale (private).
Managed containers (ECS/Fargate, Cloud Run, Azure Container Apps, App Service): mybase needs persistent volumes, exactly one API instance (cron, queue long polls, realtime, and hosting state live in its memory), and, for hosting and sandboxes, the Docker socket.
Managed Postgres (RDS, Cloud SQL, Azure Database for PostgreSQL): the API needs a real superuser (creating roles and databases, CREATE EXTENSION, writing pg_hba.conf and certificates into PGDATA), plus the extensions and preloads in mybase-postgres. Use the bundled Postgres container.
Managed object storage (S3, GCS, Blob) in place of Garage: buckets and keys are provisioned through Garage's admin API.
A cloud load balancer or your own reverse proxy in front of :4000 without telling mybase: set MYBASE_TRUST_PROXY to the proxy's addresses (e.g. 10.0.0.0/16 for a load balancer's subnet, 127.0.0.1,172.16.0.0/12 for nginx on the VM) and make the proxy overwrite X-Forwarded-For and X-Forwarded-Proto. Without it every visitor looks like the proxy's IP, so login throttling locks everyone out together and session cookies miss Secure. The tunnel is still simpler.
Several VMs or autoscaling: one machine per mybase install.
8 GB+ (each running sandbox gets 1 GB; each site 512 MB by default)
Disk
30 GB SSD
50 GB SSD
100 GB+ (site images, registry)
arm64 instances (AWS Graviton, GCP Tau T2A / Axion, Azure Ampere) are usually the cheapest per GB of RAM, and all mybase images are multi-arch. Burstable types (t4g, e2, B-series) are fine: mybase is idle most of the time.
Compose publishes 4000, 5432, 3900, 6379 (and 80 with hosting) on every interface, and Docker's published ports skip host firewalls like ufw. The cloud firewall (security group, VPC firewall rule, NSG) is the real fence. Open only:
Port
When
22
SSH, from your own IP only. Not needed with AWS Session Manager, GCP IAP, or Azure Bastion
Nothing else. The Cloudflare Tunnel and Tailscale only make outbound connections. When the wizard asks to close the Postgres, S3, and cache ports, say yes (POSTGRES_BIND, GARAGE_S3_BIND, VALKEY_BIND = 127.0.0.1) unless apps reach them over Tailscale.
For amd64, use t3.medium and .../24.04/stable/current/amd64/hvm/ebs-gp3/ami-id.
Public IP: it changes on stop/start. That's fine with the tunnel; for public Postgres either attach an Elastic IP or rely on mybase's DNS updater (it re-points db.<domain> every 5 minutes).
Snapshots: EC2 → Lifecycle Manager → create a policy for the instance's volume (daily, keep 7–14), or add the instance to AWS Backup.
No SSH port: attach an instance profile with AmazonSSMManagedInstanceCore, drop the port 22 rule, and connect with aws ssm start-session --target <instance-id>.
For amd64, use --machine-type=e2-medium --image-family=ubuntu-2404-lts-amd64. T2A is only in some regions (gcloud compute machine-types list --filter="name=t2a-standard-1").
Firewall: the default network's default-allow-ssh rule allows SSH from anywhere. Restrict it to IAP's range and connect with --tunnel-through-iap:
curl -fsSL https://get.docker.com | shsudo usermod -aG docker $USERexit # log out and back in so the docker group appliescurl -fsSL https://raw.githubusercontent.com/LandonHarter/mybase/master/scripts/install.sh | sh -s -- --setup
In the wizard:
Who should reach mybase? Pick the internet, through a Cloudflare Tunnel for public HTTPS on your domain, and/or devices on my network or Tailscale for private access (see below). Don't expose :4000 directly: it's plain HTTP.
Close the Postgres, S3, and cache ports? Yes, unless apps use them over Tailscale.
Start on boot: yes.
Admin account: created here, from the VM itself, so the setup page is never open to the internet.
Then harden .env (~/mybase/.env) and run mybase server update to apply it:
MYBASE_OUTBOUND=public # cron jobs and webhooks may only call the public internetMYBASE_BIND=127.0.0.1 # :4000 only for the tunnel and SSH port forwardsPOSTGRES_BIND=127.0.0.1 # unless you use public Postgres or TailscaleGARAGE_S3_BIND=127.0.0.1VALKEY_BIND=127.0.0.1
Then sign in at https://mybase.<domain>, or without a tunnel through SSH: ssh -L 4000:localhost:4000 <vm> and open http://localhost:4000. Turn on two-factor sign-in before using it publicly.
Scripted (cloud-init, Terraform, CI): mybase server setup --yes --tunnel-token <token> --domain <domain> --admin-password-stdin < password-file. See Self-hosting for every flag.
For private-only access (your apps and laptop on the same tailnet):
curl -fsSL https://tailscale.com/install.sh | shsudo tailscale up
Then in the wizard pick devices on my network or Tailscale and use the VM's MagicDNS name (mybase.<tailnet>.ts.net) as the host. Apps on the tailnet connect to Postgres (:5432), S3 (:3900), and the cache (:6379) directly; keep those ports closed in the cloud firewall, since Tailscale traffic doesn't pass through it. You can combine Tailscale with a tunnel.
Security: follow Security best practices, and run mybase doctor until it shows no critical or warn findings.
Hosting: sites are plain containers on the VM (not gVisor): deploy only code you trust, and put them on a different domain from the dashboard. mybase server hosting --domain <domain> works the same; sites go out through the tunnel. Size the VM for the sites you run.
Sandboxes:mybase server sandbox installs gVisor. Ubuntu 24.04 cloud images have cgroup v2, and gVisor doesn't need nested virtualization.
Public Postgres: open TCP 5432 in the cloud firewall (from anywhere, or only your apps' IPs), then mybase server database-public. No router step: the VM's public IP is detected automatically.
Web search: engines throttle datacenter IPs harder than home connections, so expect more suspended engines than on a home server.
Disk snapshots (above): they capture Postgres, Garage, Valkey, and .env together. Postgres recovers from a crash-consistent snapshot like from a power cut.
A copy of MYBASE_SECRETS_KEY off the VM (password manager, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault). Snapshots of a deleted or broken disk don't help if this is the only copy; without it, stored secrets are gone.
For an extra logical copy, run mybase server backup --encrypt and upload the .mbk file to the provider's object storage. It also moves the instance to another VM or CPU type (mybase server restore). See Self-hosting.
Egress: clouds bill outbound traffic, including traffic through the Cloudflare Tunnel. Large public files or busy sites cost more than the VM.
Public IPv4: AWS bills every public IPv4 address hourly. With the tunnel or Tailscale and SSM, the VM doesn't need one, but it then needs a NAT gateway (more expensive) or an IPv6 egress path to reach the internet; usually simplest to keep the public IP with no inbound rules.
Snapshots and backup vaults are billed by stored size.
One VM per install, with the bundled Postgres, Garage, and Valkey containers. No managed databases, object storage, container services, load balancers, or autoscaling.
Public access goes through the Cloudflare Tunnel (MYBASE_TRUST_PROXY=cloudflare); any other proxy in front of :4000 breaks client IPs, login throttling, first-run protection, and Secure cookies.
Docker's published ports bypass ufw: secure the cloud firewall, and open only 22 (or nothing) plus 5432 for public Postgres.
Install with mybase server setup over SSH; non-interactive with --yes --json.
Back up with scheduled disk snapshots, and keep MYBASE_SECRETS_KEY outside the VM.