Skip to content

Commit 8d977c2

Browse files
committed
Update server manual: admin panel, API, configuration
1 parent ae586a3 commit 8d977c2

3 files changed

Lines changed: 175 additions & 22 deletions

File tree

docs/manual/server/api.md

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,46 @@ The only supported response format is also JSON, and requests must include
6464
either `Accept: application/json` or `Accept: */*` header.
6565

6666
Successful responses (2xx status) return resource attributes directly (no
67-
envelopes). Error responses (4xx status) typically return error details in the
68-
`error` field.
67+
envelopes). Error responses (4xx status) return a JSON error object — see
68+
[Errors](#errors).
6969

7070
## Errors
7171

72-
Common HTTP status codes used by the API for error cases:
73-
74-
| Status Code | Description |
75-
|-------------|-------------|
76-
| **401** | **Unauthorized** - Missing or invalid auth header |
77-
| **403** | **Forbidden** - Access denied (e.g., streaming disabled) |
78-
| **404** | **Not Found** - Resource not found |
79-
| **422** | **Unprocessable Entity** - Validation errors |
72+
Error responses (4xx status) return a JSON object with:
73+
74+
- `type` — a stable, machine-readable error code. Branch on this, not on the
75+
human-readable message.
76+
- `message` — a human-readable description. This text may change between server
77+
versions and should not be parsed.
78+
- `details` — present only for `validation_failed`: an array of `{"field":
79+
..., "message": ...}` objects describing per-field validation errors.
80+
81+
New `type` values may be added over time, so clients should treat an unknown
82+
`type` as a generic error of its HTTP status.
83+
84+
| `type` | Status | Meaning |
85+
|--------|--------|---------|
86+
| `unauthenticated` | 401 | Missing, malformed, or revoked installation ID. |
87+
| `account_required` | 401 | The installation ID is valid but not linked to an account, and the action requires an account. |
88+
| `access_denied` | 403 | Authenticated, but not allowed to perform the action (e.g. not the owner, or streaming disabled for the account). |
89+
| `not_found` | 404 | The requested resource does not exist. |
90+
| `content_too_large` | 413 | The uploaded recording exceeds the server's size limit. |
91+
| `validation_failed` | 422 | One or more request fields are invalid; see `details`. |
92+
| `upload_limit_reached` | 403 | The anonymous upload limit has been reached. |
93+
| `live_stream_limit_reached` | 422 | The account's concurrent live-stream limit has been reached. |
94+
| `bad_request` | 400 | The request was malformed. |
95+
96+
Example error response:
97+
98+
```json
99+
{
100+
"type": "validation_failed",
101+
"message": "Validation failed",
102+
"details": [
103+
{ "field": "term_cols", "message": "can't be blank" }
104+
]
105+
}
106+
```
80107

81108
## Resources
82109

Lines changed: 116 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1-
---
2-
hide:
3-
- toc
4-
---
5-
61
# Administration
72

8-
asciinema server provides admin panel on port 4002, separate from the main,
9-
user-facing web interface.
3+
asciinema server includes an admin panel - a web interface for managing the
4+
users, recordings, and streams on your instance. From it you can search and
5+
inspect content, change visibility, feature or archive recordings, merge or
6+
delete accounts, grant admin access, and monitor the running system.
7+
8+
## Accessing the admin panel
9+
10+
There are two ways to reach the admin panel.
1011

11-
To be able to access the admin panel when deploying the container make sure
12-
this port is exposed.
12+
### Dedicated admin port
13+
14+
By default the admin panel is served on its own port, **4002**, separate from
15+
the main, user-facing site. When deploying with Docker, expose this port to
16+
reach it:
1317

1418
```yaml title="docker-compose.yml"
1519
services:
@@ -20,6 +24,106 @@ services:
2024
2125
!!! danger
2226
23-
At the moment the admin endpoint doesn't perform any form of
24-
authentication/authorization so do not expose this port directly to the
25-
internet when running a public asciinema server instance.
27+
The dedicated admin endpoint performs **no authentication** - anyone who can
28+
reach port 4002 has full admin access. Never expose it directly to the
29+
internet. Keep it bound to localhost (the default) and reach it through an
30+
SSH tunnel or VPN, or place it behind a reverse proxy that restricts access
31+
by IP address and/or requires authentication.
32+
33+
The admin endpoint's network binding and the URLs it generates can be adjusted
34+
with `ADMIN_PORT`, `ADMIN_BIND_ALL`, and the `ADMIN_URL_*` variables - see
35+
[Configuration](configuration.md#admin-panel).
36+
37+
### On the main web interface
38+
39+
Alternatively, set `ADMIN_PANEL_ON_MAIN_ENDPOINT=1` to also serve the panel at
40+
`/admin` on the main, user-facing site. In this mode access is **login-gated**:
41+
visitors who aren't logged in are redirected to the login page, and logged-in
42+
users without the admin flag get a 404 response, so the panel's existence isn't
43+
revealed to regular users. With this enabled you don't need to expose port 4002.
44+
45+
## Granting admin access
46+
47+
A user is an admin when their account has the admin flag set.
48+
49+
### The first account becomes an admin
50+
51+
On a brand-new instance the **first registered account is automatically made an
52+
admin**, so you can bootstrap a fresh server simply by signing up. All
53+
subsequent accounts are regular users.
54+
55+
### Toggling the admin flag
56+
57+
Admins can grant or revoke the flag on any account from that user's edit page in
58+
the panel (the **admin** checkbox). As a safeguard, you can't remove the admin
59+
flag from your own account this way.
60+
61+
On an existing instance that has no admin yet, use the [dedicated admin
62+
port](#dedicated-admin-port) - which doesn't require logging in - to open a
63+
user's edit page and grant them the flag.
64+
65+
## What you can do
66+
67+
### Dashboard
68+
69+
The landing page shows totals (users, recordings, streams, live streams) and
70+
recent activity - the latest signups, uploads, and stream sessions.
71+
72+
### Users
73+
74+
Search and browse accounts; view a user's recordings, streams, and authorized
75+
CLIs; edit their details; generate a one-time login link; toggle the admin and
76+
streaming flags; merge one account into another; and delete accounts.
77+
78+
### Recordings
79+
80+
Search and browse recordings; view and edit a recording; change its visibility
81+
(public / unlisted / private); feature or unfeature it; archive or unarchive it;
82+
and delete it.
83+
84+
### Streams
85+
86+
Search and browse live streams; view and edit a stream; change its visibility;
87+
forcibly disconnect an active stream; and delete it.
88+
89+
### System dashboards
90+
91+
Under **System** there's a live system dashboard (runtime metrics, processes,
92+
memory), powered by Phoenix LiveDashboard, and an Oban dashboard for inspecting
93+
the background job queues.
94+
95+
## Searching
96+
97+
Each list - Users, Recordings, and Streams - has a search box that accepts a
98+
compact `field:value` syntax. Bare words (without a `field:`) match identity
99+
(users) or title (recordings and streams), and multiple terms are combined with
100+
AND. Beyond text you can filter by things like owner, visibility, dates, counts,
101+
size, and duration - with comparisons (`>`, `>=`, `<`, `<=`) and ranges
102+
(`a..b`). A few examples:
103+
104+
- `admin:no registered:yes created:30d` - regular accounts created in the last 30 days
105+
- `visibility:public featured:no views:>1000` - popular public recordings that aren't featured
106+
- `live:yes peak-viewers:>50` - busy live streams
107+
108+
For the full, always-current list of fields and value formats, click the **Query
109+
syntax help** button next to the search box - it opens a cheat sheet for the list
110+
you're viewing.
111+
112+
### Saved queries
113+
114+
Once you've composed a search you can save it under a name to reuse later. Saved
115+
queries are scoped to their list (Users, Recordings, or Streams) and are shared
116+
by all admins. When the current search matches a saved one, the search box lets
117+
you rename or delete it.
118+
119+
## Security
120+
121+
The two access modes have very different trust models:
122+
123+
- The **dedicated admin port (4002)** is unauthenticated and relies entirely on
124+
the network being restricted - treat anything that can reach it as fully
125+
trusted, and keep it on localhost or behind an IP-restricted reverse proxy or
126+
VPN.
127+
- The **main-endpoint mode** (`ADMIN_PANEL_ON_MAIN_ENDPOINT=1`) is login-gated
128+
and serves only admins; non-admins get a 404 and anonymous visitors are sent
129+
to the login page.

docs/manual/server/self-hosting/configuration.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,13 @@ you when facing issues.
139139

140140
[Here](https://asciinema.org/about) is one on asciinema.org.
141141

142+
### Admin panel
143+
144+
By default the [admin panel](admin.md) is available only on a separate port
145+
(4002). Setting `ADMIN_PANEL_ON_MAIN_ENDPOINT=1` additionally makes it available at
146+
`/admin` on the main, user-facing web interface, for logged-in users with the
147+
admin flag. See [Administration](admin.md) for details.
148+
142149
## Database
143150

144151
asciinema server utilizes a PostgreSQL database for storing recording metadata
@@ -530,6 +537,21 @@ trusted environments, such as private LANs/homelabs. If you run a public
530537
asciinema server instance, or prefer to disable unauthenticated uploads for
531538
other reasons, then set `UPLOAD_AUTH_REQUIRED=true`.
532539

540+
### Unregistered upload limit
541+
542+
Recordings can be uploaded from a CLI that hasn't been authenticated with
543+
`asciinema auth`, in which case they aren't linked to any user account. To cap
544+
how many recordings can be uploaded from such an unregistered CLI, set
545+
`UNREGISTERED_UPLOAD_COUNT_LIMIT` to the maximum number, e.g.
546+
`UNREGISTERED_UPLOAD_COUNT_LIMIT=10`. Once an unregistered CLI reaches the limit,
547+
further uploads are rejected until it's authenticated with an account using
548+
`asciinema auth`.
549+
550+
Setting `UNREGISTERED_UPLOAD_COUNT_LIMIT=0` blocks all uploads from unregistered
551+
CLIs - a stricter variant of `UPLOAD_AUTH_REQUIRED`, which only blocks CLIs the
552+
server hasn't seen before. When unset, the number of unregistered uploads is
553+
unlimited.
554+
533555
### Recording visibility
534556

535557
Recording visibility for newly uploaded recordings is inherited from user-level

0 commit comments

Comments
 (0)