Potions - deploy and manage Phoenix apps on your own VPS

Hi everyone!

I’m Alekx, some of you may know me from ElixirCasts. I always wished there were a simple, affordable way to get Phoenix apps onto servers I control, so I built Potions: https://potions.io

Think Laravel Forge or Hatchbox, but for Elixir. Connect DigitalOcean or Hetzner and a GitHub repo, and Potions provisions and hardens the server, then gives you push-to-deploy with Mix releases: zero-downtime deploys, one-click rollback, automatic migrations, auto SSL, per-app Postgres, scheduled tasks, monitoring, backups, live logs, and a browser IEx console. There’s also no limit to the number of apps you can run on your servers.

It all runs on your own servers with full SSH access, so if you ever cancel, your apps keep running.

I’d love your feedback and I’m happy to answer any questions!

7 Likes

Congratulations Alekx :tada:

Potions looks great - I’m sure lots of people will find it useful, and I’m glad you support Hetzner as some of our servers are with them.

Be cool to have a Potions giveaway one day if you fancy it :003:

1 Like

How do you handle migrations in a Elixir cluster?

2 Likes

Thanks Aston!

1 Like

Right now Potions doesn’t support clustering (each app lives on one server today), but it’s on the roadmap.

For current deploys, migrations run automatically on every deploy, with zero configuration for a standard Phoenix app: Potions calls your MyApp.Release.migrate() (with an Ecto.Migrator fallback if your app doesn’t define one). Migrations run before the new version takes traffic, while the old version is still serving, so deploys stay zero-downtime. If a migration fails, the deploy stops and your live app is untouched.

1 Like

How is it handling the zero-downtime deploys on the server?

1 Like

Each app runs as blue/green slots on your server, each with its own port and systemd service. On a deploy, the new version starts in the inactive slot, while the old one keeps serving traffic. Once the new slot passes health checks, Caddy is updated to switch traffic over, and the old slot drains in-flight requests before stopping. If the new version doesn’t pass health checks, the deploy fails and traffic is never switched over.

1 Like