diff --git a/lib/core/accounts.ex b/lib/core/accounts.ex
index d783543..fcdf022 100644
--- a/lib/core/accounts.ex
+++ b/lib/core/accounts.ex
@@ -196,4 +196,11 @@ defmodule Core.Accounts do
       {:error, :user, changeset, _} -> {:error, changeset}
     end
   end
+
+  @doc """
+  Returns `true` if any users exist.
+  """
+  def has_registered_user? do
+    Repo.exists?(User.Query.has_users_query())
+  end
 end
diff --git a/lib/core/accounts/user.ex b/lib/core/accounts/user.ex
index ace0216..d91cec5 100644
--- a/lib/core/accounts/user.ex
+++ b/lib/core/accounts/user.ex
@@ -137,4 +137,19 @@ defmodule Core.Accounts.User do
       add_error(changeset, :current_password, "is not valid")
     end
   end
+
+  defmodule Query do
+    @moduledoc false
+    import Ecto.Query
+
+    def base do
+      from _ in Schema.User, as: :users
+    end
+
+    def has_users_query(query \\ base()) do
+      query
+      |> limit(1)
+      |> select([users: _], true)
+    end
+  end
 end
diff --git a/lib/web/router.ex b/lib/web/router.ex
index bcd4def..8f096ae 100644
--- a/lib/web/router.ex
+++ b/lib/web/router.ex
@@ -34,7 +34,7 @@ defmodule Web.Router do
   end
 
   scope "/", Web do
-    pipe_through [:browser]
+    pipe_through [:browser, :require_setup]
 
     get "/", PageController, :home
 
diff --git a/lib/web/user_auth.ex b/lib/web/user_auth.ex
index 0e3a4d4..e194dfd 100644
--- a/lib/web/user_auth.ex
+++ b/lib/web/user_auth.ex
@@ -214,6 +214,17 @@ defmodule Web.UserAuth do
     end
   end
 
+  def require_setup(conn, _opts) do
+    if Core.Accounts.has_registered_user?() do
+      conn
+    else
+      conn
+      |> maybe_store_return_to()
+      |> redirect(to: ~p"/admin/users/register")
+      |> halt()
+    end
+  end
+
   defp put_token_in_session(conn, token) do
     conn
     |> put_session(:user_token, token)