Bring Your Own Server
Potions can create servers for you at DigitalOcean or Hetzner Cloud, but it can also set up a server you already have: a Hetzner dedicated or auction box, a VPS at OVH, Infomaniak, UpCloud, Vultr, Linode or Scaleway, or a machine of your own. You run one command on it as root, and Potions sets it up exactly like a server it creates and manages it the same way.
A server you bring is an app server: it runs your Phoenix apps with PostgreSQL or SQLite, Caddy and automatic SSL. Database servers, load balancers and clusters still need a server Potions created (see What's Different).
Requirements
Your server must be a fresh installation of Ubuntu 24.04 on x86_64 (amd64) with a public IPv4 address, at least 1 GB of RAM and 10 GB of free disk, and root login over SSH. Other Ubuntu versions, such as 22.04 or 26.04, and other Linux distributions aren't supported yet. Potions doesn't support arm64 servers yet, such as Hetzner's CAX, AWS Graviton or Oracle's Ampere shapes, because it builds your app for x86_64.
Ubuntu has to see at least 800 MB of that RAM. Every 1 GB plan does, though some show less than others: most show about 960 MB, UpCloud's about 850 MB. Below 900 MB the connect script warns that memory is tight: that's fine for a small app, but choose a larger plan for more.
Installed Ubuntu yourself from the ISO? The installer's default layout gives / only part of the disk: half of it on a 55 GB disk, for example. If that leaves less than 10 GB free, grow it before you connect with sudo lvextend -r -l +100%FREE ubuntu-vg/ubuntu-lv.
Connecting a server that already runs a web server, PostgreSQL or another control panel is not supported: the connect script will stop before changing anything, and the fix is to reinstall Ubuntu and connect again. Containers (Docker, LXC, WSL) aren't supported either; Potions needs a full virtual machine or a physical server.
You don't need to connect a cloud provider to bring a server.
What Potions Changes on the Server
Potions runs the same setup on a server you bring as on one it creates. Before you get the command, Potions lists these changes and asks you to confirm them:
- It renames the server to the name you give it in Potions and sets the timezone to UTC.
- It installs security updates automatically and reboots for them at 05:00 UTC when needed.
-
It creates a
deployuser that runs your apps, with passwordless sudo for the commands deploys need, and adds Potions' SSH key toroot. Your existing keys stay. -
It turns on the firewall (ufw), blocks other incoming traffic, and allows SSH (on your server's SSH port), 80 and 443. Any ufw rules you already have stay. If ufw is off, other firewall rules are cleared first, like the iptables rules some images save in
/etc/iptables, so ufw is the server's only firewall. -
It disables password login over SSH for every user. Give each user who logs in over SSH a key first, or that user can only log in at the console; the connect script warns about anyone without one. A key on your Potions account lets you log in as
deploy. - It installs Caddy, PostgreSQL (or SQLite tooling), Litestream, fail2ban and a small metrics agent.
-
It adds a 512 MB swap file at
/swapfileunless the server already has swap.
Adding the Server
On the dashboard, click Add server and choose Your own server as the provider. If you haven't connected a cloud provider, it's already selected, and the setup wizard offers it as its first step.
-
Name - a label like
web-prod-01. Potions also sets it as the server's hostname. -
Public IPv4 address - the address Potions connects to over SSH. Private ranges (
10.x,172.16-31.x,192.168.x), carrier-grade NAT and IPv6-only servers aren't supported yet. -
SSH port -
22unless you changed it. On Ubuntu 24.04, sshd is started byssh.socket, so a newPortinsshd_configonly takes effect aftersystemctl daemon-reload && systemctl restart ssh.socket. - Database - which PostgreSQL to install, or none for SQLite apps. See Creating a Server.
Click Add server. Potions takes you to the server's page, where the server waits for you to connect it.
Connecting the Server
On the server's Overview, read the list of changes, tick I understand Potions will make these changes, and Potions shows the command:
curl -fsSL https://potions.io/connect/<token> | sudo bash
Run it on the server as root. The command works for 60 minutes. The token in it is the only thing that links the server to your account, so treat the command like a password until it has been used.
Prefer to read it first? Click View the script to open the exact script in your browser. It does three things:
-
Checks the server. It runs as root and checks the Ubuntu version, the architecture, that it isn't in a container, that ports 80 and 443 (and 5432 for PostgreSQL) are free, that no web server, database or Docker is installed, that sshd is listening on your SSH port with an Ed25519 host key, the free disk and memory, and that apt isn't busy. It also warns about what's already there, like an existing
deployuser (Potions takes it over), an active ufw (Potions adds its rules and keeps yours), or firewall rules from outside ufw (Potions replaces them with ufw). -
Adds Potions' key to root. Only if every check passed. Potions' public key is appended to
/root/.ssh/authorized_keys, and your existing keys stay. - Reports back. It sends what it found, including the server's SSH host key, to Potions.
If a check fails, the script changes nothing, prints what's wrong, and the server's page lists the same problems. Fix them and run the same command again (it keeps working until it expires), or reinstall Ubuntu 24.04 and connect a fresh server.
If you reload the page, ticking the box again gives you a new command, and the one you copied before stops working.
Provisioning
Once the script reports in, the server's page shows the report, and Potions connects over SSH, checks the server again for itself, and sets it up. That usually takes about 5 minutes, the same as a server Potions creates, and you can follow each step on the page. When it finishes, the server is Active and you can add apps to it.
Potions only connects to a server whose SSH host key matches the one the script reported. See Host Key Changes.
Firewalls and Potions' IP Addresses
Potions connects to your server over SSH from a small set of addresses, listed at potions.io/ips and on the server's page. Build servers in that list push your releases over SSH too.
If nothing filters traffic in front of your server, there's nothing to do. If your provider has a firewall in front of it, allow:
- SSH (TCP 22, or your SSH port) from every address at potions.io/ips
- TCP 80 and 443 and UDP 443 (HTTP/3) from anywhere, for your apps
Where to find that firewall:
- Hetzner dedicated (Robot) - the server's Firewall tab in Robot. It is stateless, so start from one of Hetzner's templates, which let replies to the server's own connections back in, and add the rules above.
- Hetzner Cloud - Firewalls in the Cloud Console, if one is applied to the server.
- OVHcloud - the Network Firewall for the server's IP, if it's enabled.
- AWS - the instance's security group inbound rules.
-
Oracle Cloud - the subnet's security list (or the instance's network security group). Oracle's Ubuntu images also ship host iptables rules in
/etc/iptables/rules.v4that end in a blanketREJECT, which blocks ports 80 and 443 even when the security list allows them. Potions replaces them with ufw when it sets the server up, so only the security list needs changing.
When no build server is available, builds run on Fly.io machines, which have no fixed address. If you allow SSH only from the listed addresses, deploys that fall back to Fly.io can't reach the server.
What's Different
A server you bring works like any other Potions server for apps: deploys, domains and SSL, backups and offsite backups, SQLite and Litestream, scheduled tasks, health checks, monitoring, logs and the console. A few things differ:
- App servers only. It can't be a database server or a load balancer.
- No private networking yet. Potions sets up private networks at DigitalOcean and Hetzner, and a server you bring isn't on one. That means no database servers, load balancers or clusters with it. Apps on it use PostgreSQL or SQLite on the server itself, or an external database.
- No region or size. The server's page shows the CPUs, memory and disk the server reported.
- Renaming changes the name in Potions and the hostname. There's no provider account to update.
- It counts toward your plan like any other server, and your provider bills you for it as before.
- Removing it doesn't delete it. See Removing the Server.
Troubleshooting
Check these in order:
-
The command didn't run. Check that you ran it as root (
sudo bash), that the server can reachpotions.ioover HTTPS, and that the command hasn't expired. If it has, tick the box again or click Generate a new command. - The script refused the server. The page lists the reasons. The usual ones are a different Ubuntu version, something already listening on port 80 or 443, a web server, database or Docker already installed, or a container. All of them mean the server isn't fresh: reinstall Ubuntu 24.04 and connect again.
- The script reported in, but provisioning failed connecting over SSH. Something between Potions and the server blocks SSH, almost always a provider firewall. Allow the addresses above and press Retry on the server's page.
- apt was busy. A server that has just booted often runs its first updates for a minute or two. The script waits for them; if they take longer, wait and run the command again.
-
SSH isn't listening on the port you entered. Check
ss -ltnpon the server. If you changed the port, see the note onssh.socketunder Adding the Server. -
Downloads failed during provisioning. The server needs outbound HTTPS to Ubuntu's mirrors, GitHub,
dl.cloudsmith.io(Caddy) andapt.postgresql.org. The script warns if it can't reach them.
Host Key Changes
Potions remembers your server's SSH host key from the connect script's report and refuses to connect if the server ever presents a different one. The server's page then shows SSH host key changed with the old and new fingerprints.
This usually happens after an OS reinstall. A reinstalled server has lost everything Potions set up on it, so trusting the new key isn't enough: set it up again instead. If the key changed for a reason you know about that left the server as it was, click Trust the new host key. If you don't know why it changed, check the server before trusting anything.
Reinstalling the Server
If you reinstall Ubuntu on a server you connected, everything Potions set up on it is gone, but the server and its apps stay in Potions. To set it up again:
- Reinstall Ubuntu 24.04 on the server, keeping its IP address.
- Open the server's Settings and click Set up again. Type the server's name and tick what happens to your apps' data. Potions first checks that it can no longer log in to the server. If it still can, the server wasn't reinstalled, and nothing changes.
- The server's page shows a new connect command. Run it on the server as root. The script runs the same checks as the first time, and Potions sets the server up from scratch.
-
Once the server is ready, Potions recreates each app's database:
- SQLite apps that replicate with Litestream come back from their replica.
- PostgreSQL databases, and SQLite databases without Litestream, start empty. If the app has offsite backups, restore one from its Database page.
- Apps on an external database need nothing.
- Redeploy each app. The server's page lists the apps that still need it.
Backups kept on the server went with the reinstall; offsite copies stay. Until you run the connect script, you can cancel from the server's page, and the server stays as it was.
Reconnecting
If Potions can no longer reach the server as root, for example because its key was removed from /root/.ssh/authorized_keys, open the server's Settings, expand Potions access and click Generate a reconnect command. Run it on the server as root. It adds Potions' key back to root and changes nothing else. Potions then checks that it can connect, and Settings shows how the reconnect went. For a server you reinstalled, reconnecting isn't enough: set it up again.
Check connection in the same place tells you whether Potions can reach the server as root right now.
Removing the Server
Open the server's Settings. Under Remove <name> from Potions, type the server's name and tick what happens:
- Apps Potions deployed on the server are stopped and removed, and their databases dropped.
- Potions stops managing security updates, backups and monitoring on it.
- The server itself keeps running, and your provider keeps billing you for it.
Then click Remove server. Before you do, you can also tick Also remove Potions' SSH key, sudo rules and metrics agent from the server. Potions then removes its key from root and deploy, the deploy user's sudo rules, its potions-systemctl helper and the metrics agent. Caddy, PostgreSQL, Litestream, fail2ban, the firewall, automatic security updates and the deploy user stay. If you won't use the deploy user, remove it with sudo deluser --remove-home deploy.
Things to Know
- Potions never asks for a password or a private key. The connect script adds Potions' public key, and every connection after that uses it.
- Fresh means fresh. Potions doesn't try to coexist with software already on the server. If the script refuses the server, reinstalling Ubuntu 24.04 is the reliable fix.
- Your provider's console is your way back in. If you lose SSH access yourself, use your provider's web or rescue console, then reconnect Potions if needed.