# The admin panel

> Manage a Frame server from the web panel at /admin or from Server admin in the apps: users, reports, invites, settings, two-factor authentication, the audit log and backups.

Source: https://crow.sg/apps/frame/docs/admin-panel/

Every Frame server has a small web dashboard at `https://frame.example.com/admin/` for the person who runs it: invite people, manage accounts, review reports, change a few settings, see how much disk the server uses and download a backup. Admins can do most of the same from **Server admin** in the Frame apps.

> [!NOTE] The panel doesn't show anyone's photos or messages
> It shows accounts, counts and sizes, never moments, captions, chats or reactions. The one exception is an item a member **reported** to you: the report shows that single moment, message or profile, because the member chose to share it with you. (The operator can still read the database directly; see [Security](https://crow.sg/apps/frame/docs/security/). The panel simply doesn't make browsing people's content part of running a server.)

## What you can do

| Page | What it's for |
|---|---|
| **Overview** | Server name, version and uptime, registration mode, open reports, user counts (total, active in the last 7 days, suspended, admins), moments and messages, media and database size, whether the push relay is reachable, the latest sign-ups and admin actions. |
| **Users** | Search, filter and sort accounts. Open a user to see their signed-in devices (and sign them out) and their invite links, and to **reset their password** (a one-time password is shown once), **suspend** or unsuspend them, **make or remove admin**, or **delete** the account (you type the username to confirm). You can also **create an account**, which you need when registration is `closed`. |
| **Reports** | What members reported from the app (a moment, a message or a profile), open reports first. Open a report to see the reported item and **delete it**, **suspend** its author, or **dismiss** the report. |
| **Invites** | Create a **server invite** (one use and 7 days by default, with an optional note), copy it or show it as a QR code, see who joined with it, revoke it. Also lists your members' friend-invite links, so you can revoke any of them. |
| **Settings** | Registration mode, whether members' invite links can bring in new people, server name, maximum video length, maximum upload size, maximum friends. Anything set in `frame.conf` is **locked** ("set in frame.conf"). |
| **Security** | Change your password, turn on two-factor authentication, get recovery codes, and see or sign out your admin sessions. |
| **Audit log** | Every admin action: who, what, on whom, when and from which IP. |
| **Maintenance** | Download a consistent database backup (asks for your password again) and run the orphaned-media cleanup. |

The panel works on a phone, follows your system's light or dark setting, and loads nothing from other websites.

## Reports

Frame never scans anything automatically. Members can report a moment, a message or a person from the app, which asks **you**, the server's admin, to look at one thing. Reports go only to your server, never to Crow Tech or anyone else.

- A report holds who reported, whose content it is, the type, a reason (spam, harassment, nudity, violence, self-harm, other), an optional note of up to 500 characters and the date. Only ids are stored, never a copy of the content.
- Opening a report shows **exactly the reported item** and nothing around it. Opening a reported moment or message is written to the audit log.
- **Delete** removes the moment or message as if its author had. **Suspend** signs the author out everywhere and stops them signing in, until you undo it in Users. **Dismiss** does nothing to anyone. Each action resolves every open report on the same item.
- In the app, reporting a moment also hides it from the reporter's feed, and the reporter can block the author in the same step.

## Server admin in the apps

Admins get a **Server admin** menu in the Frame apps with the overview, users, reports, invites, settings, the audit log and the media cleanup. It goes through the normal app API on the server's main address, so it works wherever the app works, and every check the panel makes applies. `FRAME_ADMIN_APP` decides whether the server offers it:

| Value | Server admin in the apps |
|---|---|
| `auto` (default) | On only when the panel itself is on the main address (`FRAME_ADMIN=on` and no `FRAME_ADMIN_LISTEN`). If you made the panel private, the apps don't open a new way in. |
| `on` | On, also when the panel is `local` or on its own address. The web panel stays where it is. `FRAME_ADMIN=off` still turns all admin access off. |
| `off` | Off. |

The server logs the effective setting when it starts.

- **Unlocking** the menu asks for your password and, with two-factor authentication on, a code, with the same attempt limits as the panel's sign-in. It is written to the audit log. Accounts that only sign in with Apple or Google set a password first.
- **Bound to this app session:** the admin session ends when you leave the menu, after 30 minutes idle or 12 hours at most, and when you sign out, the device is revoked, your password changes, or you lose admin rights. It is listed under **Security** in the panel as "Frame app · *device*".
- **Not in the apps:** the panel's own sign-in and setup, **Security** (password, two-factor authentication, recovery codes) and backups. Those stay in the web panel.

## How the panel is protected

- Only admin accounts can sign in. Every request re-checks that the account is still an admin and not suspended.
- Sessions use an `HttpOnly`, `SameSite=Strict` cookie stored only as a hash, and end after **30 minutes idle** or **12 hours**.
- Sign-in is rate limited like the app's. Two-factor codes are limited to 10 attempts per 15 minutes per account.
- Two-factor authentication uses TOTP with eight single-use recovery codes. Lost both? `sudo frame-admin user reset-2fa <username>`.
- Changes need a same-origin request with a custom header, and a strict Content Security Policy blocks inline scripts, third-party resources and framing.
- Downloading a backup and changing two-factor settings ask for your password again. You can't suspend, demote or delete yourself, and the last admin can't be demoted.

To take the panel off the internet entirely, see [Keep the admin panel private](https://crow.sg/apps/frame/docs/private-admin/). The full design, including the admin API, is in [ADMIN.md](https://github.com/Crow-Tech-Pte-Ltd/frame/blob/main/docs/ADMIN.md).

## From the command line

With the Linux installer, always use `sudo frame-admin …`: it runs the command as the service's own user. With Docker, use `docker compose exec frame frame-server admin …` instead. Commands work directly on the data directory, are safe while the server runs, and are recorded in the audit log as `CLI`.

```sh
sudo frame-admin setup-link                                              # one-time link to create the first admin
sudo frame-admin user list
sudo frame-admin user create --email alice@example.com --name Alice     # prints a one-time password
sudo frame-admin user create --phone +34600111222 --name Bob
sudo frame-admin user create --email you@example.com --name You --admin # an admin for the web panel
sudo frame-admin user promote alice                                      # make an existing user an admin
sudo frame-admin user demote alice                                       # (never the last admin)
sudo frame-admin user reset-2fa alice                                    # admin lost their authenticator
sudo frame-admin user reset-password alice                               # prints a one-time password
sudo frame-admin user unlink alice apple                                 # remove a linked Apple or Google sign-in
sudo frame-admin user delete alice                                       # irreversible
sudo frame-admin invite server --uses 1 --days 7 --note "for Mum"        # server invite link
sudo frame-admin invite create alice                                     # alice's friend-invite link
sudo frame-admin backup /root/frame-backup.db
sudo frame-admin version
```

Password resets by e-mail only work if you configure `FRAME_SMTP_URL` ([Configuration](https://crow.sg/apps/frame/docs/configuration/#email)). Otherwise the app tells people to ask you, and you use **Reset password** in the panel or `reset-password`.
