Install Cloudron on a VPS
Install Cloudron on a fresh Ubuntu VPS: the wildcard DNS record, the setup script, first boot, sizing for 2 to 10 apps, mail, certificates and backups.
Install Cloudron on a VPS: the short version
To install Cloudron on a VPS you need a fresh Ubuntu server, at least 2 GB of RAM, and a domain whose DNS records you can edit. The install itself is three commands and one reboot. Nearly everything that goes wrong goes wrong before that step (wrong base image, wrong virtualisation type) or after it (DNS, mail, backups).
wget https://cloudron.io/cloudron-setup
chmod +x cloudron-setup
sudo ./cloudron-setupCloudron installs, updates, backs up and issues TLS (transport layer security) certificates for self-hosted apps. Every app runs in Docker, nginx sits in front of all of them, and each app gets its own subdomain of your domain. That last detail is why the DNS work comes first here.
Why Cloudron is fussy about the base OS
The setup script checks the server before it installs anything, and failing a check means ordering a new server. Read them before you pick an image.
- Ubuntu only, and only three releases. Anything else exits with
Cloudron requires Ubuntu 20.04, 22.04, 24.04. Debian, Rocky and Alpine are not supported. Ubuntu 24.04 needs Cloudron 8 or newer, and the script checks that for you. - 64-bit Intel or AMD only:
Error: Cloudron only supports amd64/x86_64. An ARM VPS cannot run it. - Full hardware virtualisation only. On a container-based VPS the script stops with
Error: Cloudron does not support lxc, only runs on bare metal or with full hardware virtualization, because it detects the container withsystemd-detect-virt --container. KVM is fine. OpenVZ and LXC are not. - The root filesystem has to be
ext4orxfs. On anything else you getError: Cloudron requires '/' to be ext4 or xfs, which is how btrfs and zfs images fail. - At least 941 MB of RAM and 20 GB on
/, measured withfree -mand the size of the root filesystem. - A genuinely fresh server. If
nginx,dockerornodeis already installed the script refuses withError: Some packages like nginx/docker/nodejs are already installed.
That last check is the one people argue with, so here is the reason behind it. Cloudron installs pinned versions of Docker, nginx, Node.js and MySQL, writes the nginx configuration for every app it hosts, and manages the iptables firewall rules itself. A Docker you installed yesterday is the wrong version, and your existing nginx site files get replaced. Cloudron owns the whole machine, so give it a dedicated VPS.
One more check is easy to miss. On an older CPU with no AVX (advanced vector extensions) the script prints CPU has no AVX support. MongoDB will be disabled, and every app that needs MongoDB becomes uninstallable. Check the CPU before you commit with grep -m1 -o avx /proc/cpuinfo, which prints avx on a capable host and nothing on an old one.
How much RAM does Cloudron need?
The script refuses to run under 941 MB, with Error: Cloudron requires atleast 1GB physical memory, and the documentation asks for 2 GB of RAM and 20 GB of disk. Both numbers are the floor for the platform, not for the platform plus your apps. Before you install a single app, Cloudron is already running Docker, nginx, its own box service, the database containers it lends to apps (MySQL, PostgreSQL, MongoDB), Redis and the mail stack. Run docker ps on a fresh install and count them.
App memory limits sit on top of that base. Each app package ships a low default limit and you raise it with the slider in the app's Resources view. When an app crosses its limit it restarts and sends you an OOM (out of memory) notification, so a box that keeps restarting one app is usually a limit problem rather than a bug.
Here is the sizing I would order. These are recommendations for a server you will not have to rebuild next month. They are not measured benchmark results.
The data behind this chart
[
{
"label": "2 apps (free tier)",
"vcpu": 2,
"ram_gb": 4,
"disk_gb": 60
},
{
"label": "5 apps",
"vcpu": 4,
"ram_gb": 8,
"disk_gb": 120
},
{
"label": "10 apps",
"vcpu": 6,
"ram_gb": 16,
"disk_gb": 240
}
]Two apps are comfortable on 4 GB of RAM and 60 GB of disk. Around ten apps want 16 GB and 240 GB, because the platform base never shrinks and each app adds a Docker image, a database and its own data. Disk fills faster than people expect: images, app data and local backups share one volume until you move backups off the box.
Cloudron gives every app unlimited swap, so the memory limit you set applies to RAM only. On a VPS image with no swap file, swapon --show prints nothing at all, and memory pressure turns straight into OOM restarts instead of a slow app. Adding 2 GB of swap is cheap insurance, though it does not replace real memory. The gap between VPS plans is small next to the hours you will spend tuning limits, so see what a VPS actually costs and buy the next size up.
DNS: the wildcard record that makes app subdomains work
Cloudron puts the dashboard on my.example.com and every app on its own subdomain, so DNS is a prerequisite rather than a later step. Point these records at the server's public IP address before you open the dashboard for the first time:
my.example.comas an A record. This is the dashboard.*.example.comas an A record. This is the one that makes app subdomains work, sowiki.example.comandgit.example.comresolve the moment you install those apps.example.comas an A record, only if you want an app on the bare domain.
A wildcard record has lower precedence than an explicit record, so an existing www.example.com pointing somewhere else keeps working.
During setup you choose how Cloudron handles DNS from then on:
- An API provider. Cloudron stores a token for Cloudflare, DigitalOcean, Route53, Hetzner, Porkbun, Linode, deSEC, Gandi, Namecheap and around twenty others, then writes every record itself, mail records included.
- Wildcard. You add the
*record by hand and Cloudron writes nothing. - Manual. Cloudron shows you each record and waits while you add it, before every single app install.
A wildcard DNS record is not a wildcard certificate. The default certificate provider is Let's Encrypt Prod - Wildcard, which proves ownership over DNS, so it only works with an API provider. On the Wildcard or Manual backends you fall back to one certificate per app validated over HTTP, which means inbound port 80 has to stay open forever. If your registrar or DNS host is on the API list, use it: mail records and certificates both stop being your job.
Verify before you go further. dig +short my.example.com and dig +short anything.example.com should both print your server's IP address. If the wildcard query prints nothing, apps will fail later while the dashboard works fine.
If the domain sits behind Cloudflare, set the records to DNS only. The proxy forwards HTTP and HTTPS alone, so the mail ports break, and every app sees a Cloudflare address instead of the visitor's.
Run the setup script
wget https://cloudron.io/cloudron-setup
chmod +x cloudron-setup
sudo ./cloudron-setupRun it as root or through sudo, because the first thing it prints otherwise is This script should be run as root.. The install takes several minutes and is quiet while it works, since apt output and Docker pulls go to a log file. Watch it from a second SSH session:
tail -f /var/log/cloudron-setup.logAt the end it prints After reboot, visit one of the following URLs and accept the self-signed certificate to finish setup. followed by your server's address, then asks The server has to be rebooted to apply all the settings. Reboot now ? [Y/n]. Answer yes. The --skip-reboot flag exists if you need to schedule the restart, but Cloudron is not usable until the box has come back.
First boot: domain, DNS backend and the admin account
Open https://<server-ip> and accept the browser warning. The certificate is self-signed because Cloudron does not know your domain yet, so it has nothing to ask a certificate authority for. In Chrome click Advanced, then Proceed to <ip> (unsafe). In Firefox click Advanced, then Accept the Risk and Continue.
The first screen asks for your domain. Enter example.com and the dashboard settles at my.example.com. You can use a subdomain such as cloudron.example.com instead, and then the dashboard is at my.cloudron.example.com. Pick the DNS backend, paste the API token if you have one, and create the admin account with an email address you really read: Let's Encrypt registration and every platform alert use it.
When you save, Cloudron requests certificates and moves the dashboard to https://my.example.com. The IP address URL stops working at that point, so bookmark the new one.
Certificates: what renews, and when it stops
Certificate renewal is automatic and follows ACME Renewal Information (ARI), the schedule the certificate authority publishes, which in practice renews about a month before expiry. A failed renewal emails the admin account, and an expired certificate falls back to the built-in self-signed one. That fallback is what a browser warning on a site that worked yesterday actually means.
Two causes account for most of it. HTTP validation needs inbound port 80, so closing 80 because "everything is HTTPS anyway" breaks renewal for every app on a Wildcard or Manual DNS backend. DNS validation needs an API token that still has write access, so rotating or narrowing that token breaks renewal silently until the warning email arrives.
The Domains view has a Renew All button to force the attempt immediately, and a Let's Encrypt Staging provider for testing. Staging certificates are untrusted by browsers on purpose, which is the point: you can retry as often as you like without spending production rate limit.
Should you use the built-in mail server?
Cloudron ships a complete mail stack with IMAP mailboxes, submission, sieve filters and DKIM (domainkeys identified mail) signing. You enable it per domain under Email in the dashboard. Getting mail delivered is the hard part, and none of the difficulty is Cloudron's.
- Outbound port 25 is blocked by most VPS providers as a spam control. Some unblock it after a support ticket. Test from the server with
nc -zv aspmx.l.google.com 25(installnetcat-openbsdif the command is missing). Open ports reportsucceeded, and a blocked port hangs until it times out. - The PTR record (reverse DNS) is set by your VPS provider, not by your DNS host, and it has to match the mail hostname. Mail from an address with a generic PTR lands in spam folders.
- SPF, DKIM and DMARC records are written for you on an API DNS backend. On the Wildcard or Manual backends you add them by hand, and a missing DKIM record means every message you sign is unverifiable.
The setup that works for most people is receiving mail on Cloudron and sending through a relay such as SendGrid, Postmark, Mailgun or Amazon SES, configured in the Email view. The relay has to allow sending as any address on your domain, otherwise app notifications from different senders get rejected. If mail is the main reason you are buying the server, run a dedicated mail server such as Mailcow on its own box with its own IP reputation.
If you do not use Cloudron Email at all, block ports 25, 465, 587, 993 and 4190 in your provider's firewall. Do it there and not on the server, because Cloudron writes the iptables rules itself and expects to own them. That is the opposite of a plain VPS, where you manage ufw rules yourself.
Configure the backup target before you need it
Backups default to the local filesystem at /var/backups, on the same disk as everything else. The documentation is blunt about it: "Having backups reside in the same physical disk as the platform server is dangerous." One failed disk takes the apps and the backups together.
Open Backups, then Backup Sites, and point it somewhere else on day one. S3-compatible object storage is the usual answer (Backblaze B2, Wasabi, Cloudflare R2, DigitalOcean Spaces, or a MinIO bucket on a second server), and SSHFS, NFS, CIFS and plain filesystem targets are supported too.
Three settings decide whether that backup is worth having:
- Format.
tgzwrites one compressed archive per app and re-uploads the whole thing every run.rsyncuploads changed files only, which is far cheaper for a large Nextcloud, at the cost of many more requests against the storage API. - Encryption. Optional AES-256 covering both file contents and filenames. Cloudron does not keep a copy of the password, so losing it means the backups cannot be decrypted by anyone, including you. Store it in a self-hosted password manager before you click save.
- Retention. Written as counts such as 7 daily and 4 weekly. Long retention on object storage bills you every month, so choose a number you are willing to keep paying for.
Then test a restore. Install a small app, restore it from the dashboard, and watch it come back with its data. A backup nobody has ever restored is a guess.
What the free tier limits
As of August 2026 the free plan is capped at two installed apps. Everything else comes with it: app updates, per-app backups, the firewall, the mail server and single sign-on. The third app is the point where you need a licence. The paid plans lift the app limit, and the higher one adds user groups and roles, a directory server and multiple backup sites. Prices change, so check the Cloudron pricing page rather than a number in a tutorial.
A licence covers one Cloudron install, so two small servers cost twice what one larger server costs. That pricing pushes most people onto a single bigger VPS, which runs against the usual advice to spread services across machines. Size the box with that in mind, since splitting later means paying twice.
When something breaks
Start with the built-in check. It walks through DNS, certificates, disk, memory and each service in turn, and tells you which test failed:
sudo cloudron-support --troubleshootAfter that, use the ordinary systemd (system and service manager) tools. systemctl status box reports on the Cloudron service itself, journalctl -u box -n 100 gives its recent logs, and journalctl -u docker covers the container runtime underneath. Anything that went wrong during install stays in /var/log/cloudron-setup.log.
A dashboard that will not load is usually DNS or the provider firewall rather than Cloudron. Run dig +short my.example.com from your laptop and confirm that ports 80 and 443 are open in the provider's network firewall, which is a separate control from the server's own rules. If you are starting over, the script refuses a second run with Error: Cloudron is already installed. To reinstall, start afresh, and a rebuilt server is the clean answer.
When Cloudron is the wrong shape
Cloudron fits when you want applications and not infrastructure. It fits badly when you want to run your own containers your own way, because it owns nginx, Docker and the firewall, and it will overwrite what you put there. If your plan is a folder of compose files, Traefik in front of your own Docker Compose stacks gives you the same automatic TLS and subdomain routing with no platform on top. If you have not chosen yet, Cloudron, CasaOS and Coolify compared puts them side by side, and the wider list of what to self-host is a better place to start than an install guide.
FAQ
How much RAM does Cloudron need on a VPS?
The setup script refuses to run under 941 MB and the documentation asks for 2 GB, but that is the floor for the platform with no apps on it. Cloudron runs Docker, nginx, its own box service, database containers and the mail stack from first boot. Budget 4 GB for two apps and 16 GB for around ten, and add a swap file, because Cloudron gives apps unlimited swap and a box with none turns memory pressure into restarts.
Can I install Cloudron on Debian, or on a server that already runs Docker?
Neither works. The script checks the release and stops with Cloudron requires Ubuntu 20.04, 22.04, 24.04, so Debian, Rocky and Alpine are out. It also stops when nginx, docker or node is already present, because it installs pinned versions of all of them and writes the nginx configuration and iptables rules itself. Start from a fresh Ubuntu image on a KVM VPS.
Why do my app subdomains fail while the dashboard works?
The wildcard DNS record is missing. Setup creates or requires an A record for my.example.com, so the dashboard resolves, while wiki.example.com returns NXDOMAIN and the browser reports that the site cannot be found. Add an A record for *.example.com pointing at the server IP, then confirm with dig +short wiki.example.com before you install the app.
Do I have to use the Cloudron mail server?
No. You can leave incoming email off and send through an external relay such as Postmark, Mailgun or Amazon SES, which is the safer choice when your provider blocks outbound port 25 or the IP address has no mail reputation. If you skip Cloudron Email entirely, close ports 25, 465, 587, 993 and 4190 in the provider firewall rather than on the server.
What happens when I reach the two-app limit on the free plan?
The dashboard blocks the third install and asks for a licence key. Apps you already run are untouched: they keep updating, keep getting backed up and keep their certificates. Adding a licence lifts the limit without reinstalling anything, so the free plan is a fair way to test the platform on a real domain first.