Back to Overview

Admin Setup & Self-Hosted Settings

Promote your first admin, run the /admin UI, and toggle runtime settings without editing environment variables or restarting the container.

Luka Breitig — Technical Product Builder & AI Developer
Luka Breitig

Technical Product Builder & AI Developer

🛠️ What Admin Access Gives You

Admins are regular Tymeslot users with one extra flag — is_admin = true. Once promoted, a user gains access to /admin, where they can:

  • Toggle registration, password auth, and other operator-controlled settings without editing environment variables or restarting the container.
  • Promote or demote other users, with built-in guards that prevent demoting yourself or removing the last admin.
  • See the current source of each setting at a glance — whether it's coming from the database override, an environment variable, or the built-in default.

Admin is Core-Only

The admin UI ships with the open-source Core app, not the managed SaaS. Hosted tymeslot.app accounts have no /admin — the route is locked down with a 404 by design, since settings are managed centrally there. This guide applies only to self-hosted deployments.

🚀 The Bootstrap Rule

On a brand-new install, the first user to register is automatically promoted to admin — but only when the users table is empty at the moment of registration. As soon as any user exists (even one created during an earlier deployment), auto-promotion is permanently off.

Fresh install

First user signs up via email or OAuth and becomes admin automatically. No mix task required.

Existing install / upgrade

Auto-promotion never triggers. Use a mix task or release helper (below) to promote an existing user.

Why no “first registration claims admin” on existing installs

On an instance that already had users before the admin feature was introduced, anyone who can sign up could otherwise claim admin by registering before the operator. The rule above closes that gap: existing installs must explicitly nominate their admin via the command line, where only someone with shell access to the server can act.

1 Promote an Existing User to Admin

Pick the snippet that matches how you deployed Tymeslot. Each command takes the email of an already-registered user — the task does not create accounts.

Docker

From the host machine where docker-compose runs:

docker-compose exec tymeslot \
  bin/tymeslot rpc 'Tymeslot.Release.promote_admin("you@example.com")'

Cloudron

Open Apps → Tymeslot → Terminal in the Cloudron dashboard, then:

bin/tymeslot rpc 'Tymeslot.Release.promote_admin("you@example.com")'

From your laptop you can also use the Cloudron CLI: cloudron exec --app tymeslot.yourdomain.com -- bin/tymeslot rpc '...' .

Railway

From the project root (or with the Railway CLI linked to the service):

railway run bin/tymeslot rpc 'Tymeslot.Release.promote_admin("you@example.com")'

Source install / dev environment

Running Tymeslot directly from the source tree (mix phx.server)? The mix task is the most convenient route:

mix tymeslot.promote_admin you@example.com

The mix task and the release helper share an implementation, so they produce identical results.

rpc vs. eval

bin/tymeslot rpc runs the call against the already-running Tymeslot node — fast and recommended for live containers. Use bin/tymeslot eval only when the application is not running (for example, a one-shot maintenance container).

2 Demote an Admin

Symmetric to promotion. The same command pattern works for every deployment target — swap promote_admin for demote_admin:

# Docker / Cloudron / Railway
bin/tymeslot rpc 'Tymeslot.Release.demote_admin("former-admin@example.com")'

# Source install
mix tymeslot.demote_admin former-admin@example.com

Guards in the /admin UI do not apply on the command line

The web UI prevents you from demoting yourself or removing the last admin. The mix task and release helper enforce no such guard — they will happily demote the last admin if you ask them to. Be deliberate. If you do end up with zero admins on a populated install, see Recovering from total admin loss below.

📋 List All Current Admins

Verify which users hold admin status at any time:

# Production / release builds\nbin/tymeslot rpc 'Tymeslot.Release.list_admins()'\n\n# Source install\niex -S mix -e 'IO.inspect(Tymeslot.Release.list_admins())'

Output is a list of %{id: integer, email: string} maps, one per admin user.

⚙️ The Admin Settings UI

Visit /admin/settings while signed in as an admin. Each toggle shows a source badge telling you where the current value is coming from, so you always know whether you're looking at a runtime override or a value baked into your deployment.

database

You (or another admin) set this value from the UI. Survives restarts. Click Reset to drop the override.

config

Coming from an environment variable like REGISTRATION_ENABLED . The UI can still override it.

default

No env var, no override — the built-in default applies.

Precedence model

database override (admin UI)\n  ↓ falls back to\nenvironment variable (e.g. REGISTRATION_ENABLED)\n  ↓ falls back to\nbuilt-in default

Resetting a setting from the UI clears the database override and restores whichever of the lower layers wins — that's usually the env var if one is set, otherwise the built-in default.

Currently togglable from the UI

  • Registration enabled — disable sign-ups without setting REGISTRATION_ENABLED=false .
  • Password auth enabled — hide the email/password form for SSO-only instances, mirroring PASSWORD_AUTH_ENABLED .

The full list of environment variables (including those not exposed in the UI) lives in the Environment Variables Reference .

🆘 Recovering From Total Admin Loss

If every admin has been demoted or deleted on an install that still has users, the mix task is the way back. It does not require an admin — only shell access to the server:

docker-compose exec tymeslot \
  bin/tymeslot rpc 'Tymeslot.Release.promote_admin("you@example.com")'

Last-resort: direct SQL

If the application itself won't start, you can promote an admin directly in PostgreSQL. Reserve this for genuine emergencies — the mix task is preferred because it goes through the same code path the UI uses:

docker-compose exec -T postgres psql -U tymeslot tymeslot <<'SQL'\nUPDATE users SET is_admin = true WHERE email = 'you@example.com';\nSQL

No env-var-based admin escape hatch

There is no ADMIN_EMAIL variable. Admin status lives in the database and is changed only through the mix task, the release helper, the admin UI, or — as above — direct SQL. The deliberate constraint is that anyone who can flip an env var should not be able to silently grant themselves admin in a multi-tenant deployment.

Frequently Asked Questions

Why doesn't /admin appear in my Tymeslot navigation?

Three reasons, in order of likelihood: (1) you are not signed in as an admin user — the route returns a 404 to non-admins by design so the scope is invisible; (2) you're on the managed SaaS, which disables the admin UI entirely; (3) the enable_admin_ui config flag has been set to false for this deployment. On a Core self-hosted instance, sign out and back in once after running the promotion command so the new admin flag is loaded into your session.

Can I make multiple users admin?

Yes — there is no built-in cap. Run the promote command once per email. The /admin/users page lets existing admins promote and demote each other directly from the UI once at least one admin exists.

What happens to my env-variable settings when I toggle something in the UI?

The env var stays where it is — the UI writes a database override that takes precedence at runtime. If you later click Reset on that setting, the override is cleared and the env var (or the built-in default) takes over again on the next read. No .env file is ever edited.

Are admin actions audited?

Admin promotions, demotions, and setting changes are logged via the standard application logger with the actor's user ID. There is no separate audit-log UI today — operators rely on JSON log aggregation. If you need richer audit history, run a log shipper against the application logs and filter on the Admin namespace.

The admin route returns 404 even though I just promoted myself. What now?

The promotion succeeded — but your existing browser session still holds the pre-promotion user record. Sign out, sign back in, and reload /admin. If the 404 persists, confirm the promotion took effect with bin/tymeslot rpc 'Tymeslot.Release.list_admins()' and verify that enable_admin_ui is not set to false in your deployment's configuration.

Verify Your Setup

Confirm each of the following before considering admin bootstrap complete:
  • A user has been promoted to admin. bin/tymeslot rpc 'Tymeslot.Release.list_admins()' returns at least one entry.
  • Signed-in admin sees /admin. The Admin Overview page loads without a 404.
  • Non-admin users do not see /admin. A signed-in regular user hitting /admin gets a 404, not a 403 — that's intentional.
  • Settings UI reflects current sources. Each setting on /admin/settings shows a database, config, or default badge that matches your deployment.
  • Reset restores the lower layer. Toggle a setting, save, then click Reset — the badge should switch back to config or default depending on whether you have the env var set.

🔗 Related Articles

Read Docker Self-Hosting

Docker Self-Hosting

Deploy Tymeslot with Docker Compose on any VPS or home server. Includes reverse proxy setup, file upload volumes, and WebSocket configuration for LiveView.

Read Cloudron Deployment

Cloudron Deployment

Install Tymeslot on Cloudron in minutes. PostgreSQL, SSL certificates, email relay, and automatic updates are all provisioned and managed for you.

Read Railway Deployment

Railway Deployment

Deploy Tymeslot to Railway with one click. PostgreSQL is provisioned and connected automatically — set two environment variables and your instance is live.