DEV Community

Great Sage
Great Sage

Posted on

Self-hosting AzuraCast? Whoever opens the setup wizard first becomes admin

I've been messing with self-hosted web radio lately — AzuraCast is the obvious pick if you want Icecast streaming, Liquidsoap playlist automation, a browser-based DJ console, podcasts and listener stats without paying for a hosted service. It's been around for about ten years and it's genuinely good software.

If you're setting it up on any platform where the app comes up publicly before you've had a chance to click through the wizard yourself (Railway, Render, a VPS with a slow DNS propagation, whatever), there's a footgun worth knowing about before you hit deploy.

The setup wizard doesn't check who's asking.

SetupController::registerAction serves GET /setup/register and accepts the POST with no authentication at all, for as long as the users table is empty. Whoever's account gets created there gets ensureSuperAdministratorRole() — full admin, no questions asked. I checked this directly against the stock image:

GET  /setup/register            -> 200   (valid CSRF token in the page)
POST /setup/register            -> 302
azuracast_cli azuracast:account:list
  attacker@example.com   Super Administrator
Enter fullscreen mode Exit fullscreen mode

That's not a hypothetical bot-scanning-the-internet scenario either — it's the literal next step in the standard deploy instructions most guides give you: "open your URL and finish the setup wizard." If your app is reachable before you are, whoever gets there first owns your instance — your stream config, your DJ accounts, everything.

The fix, if you're doing this yourself: don't expose the public URL until you've completed the wizard, or front it with something (Cloudflare Access, a temporary firewall rule, whatever you've got) until the first admin account exists. AzuraCast doesn't help you here — this is on the deployer.

Full disclosure: I maintain a Railway template for AzuraCast (kickback applies if you deploy through it) that seeds the admin account server-side before nginx ever starts serving requests, so there's no window where the setup page is live and unclaimed — verified live, /setup/register returns 403 from the first request the domain ever answers. It also pins the version instead of tracking :latest (AzuraCast's DB migrations are one-way, so an unplanned upgrade on redeploy has no way back), and sizes PHP-FPM/MariaDB pool limits from the container's actual memory instead of AzuraCast's fixed defaults, which otherwise assume way more RAM than a small box has.

Link if you want the one-click version: https://railway.com/deploy/azuracast-v0237-or-web-radio-whose-admin?referralCode=Z1xivh&utm_medium=integration&utm_source=template&utm_campaign=inventory

And if you'd rather run it yourself with none of that: upstream repo is https://github.com/AzuraCast/AzuraCast, official Docker install docs are on their site — just make sure you're not leaving /setup/register open to the internet even for five minutes.

Top comments (0)