Terminal sessions into instances
This page shows how to open a terminal into a running module from the Fabric Console or the Studio. It also covers production approval, how administrators see and end sessions, and which browser origins to allow. You need a signed-in account with the instance.console permission. The rules behind it are in Identity and authorization, section 7.
Two doors, one broker
The Studio (right-click on a module, or the Monitoring tab) and the Fabric Console open the same sessions through the same API: a single-use ticket from POST /api/v1/applications/{name}/instances/{instance}/sessions, then a websocket to /api/v1/sessions/connect. The browser never talks to Incus. Whichever you use, the same rules apply:
- You need
instance.consoleon the application: the Instance Access role, a project administrator, or an organisation owner. Automation identities and API tokens never get a session. - In production, another person approves first. An approval works once, within 30 minutes, for that one instance.
- The ticket lasts 60 seconds, works once, and only from the page (origin) that asked for it.
- The shell runs as uid 1000 (
APELORA_CONSOLE_UID), not root. It ends after 15 minutes without typing, and after 60 minutes in any case. Your access is checked again every 30 seconds; a removed role ends the session. - The audit trail records who, which instance, when, why it ended and how many bytes moved. What you type or see is never recorded.
Opening a terminal from the Fabric Console
- Find the instance in one of two places:
- Instances (needs
cluster.viewto see the list): Terminal… on any instance Apelora created for an application. - Applications (needs only
application.view): Show details, then Terminal… on an instance. This is the door for people who hold Instance Access but not the infrastructure views.
- Instances (needs
- The dialog asks the control plane what you may open. When nothing can be opened, it shows the reason: no permission, the instance is stopped, or Incus cannot be read.
- Otherwise it lists the rules above and offers Open terminal. Choose it.
The terminal has the focus, and Escape goes to the program. Use End session to close it.
Production: approval
- The dialog shows Approval needed. Write why you need access and choose Request approval.
- The request appears under Identity & Access → Access policies → Approvals for the people who may approve.
- The dialog shows Waiting for approval and checks again every few seconds. You can also choose Check now.
- Once it says Approved, choose Open terminal: it sends the approval with the request.
If you already have an approved, unused request for that instance, the dialog picks it up.
The Sessions page
Identity & Access → Sessions (#/sessions) is offered to people who hold instance.console, instance.desktop or application.operate somewhere.
- Open now lists your own sessions and those on applications you operate: who, which instance, when it started, when they last typed, and how long it has left (the idle limit unless they type, or the absolute limit). It refreshes every 10 seconds.
- End session (after a confirmation) closes the terminal at once. The person sees Ended by an administrator or from the sessions list, and the audit trail records
session.terminate. You may end your own sessions and any session on an application you may operate. - History from the audit trail shows past
session.*events (requested, opened, ended with the reason and duration, refused) for the scopes where you holdaudit.read. It is read-only.
Sessions live in the control plane's memory. A restart ends them all, and with several control plane replicas, each lists only its own.
Browser origins
The websocket accepts a browser page only from the control plane's own host name, or from an origin listed in APELORA_ALLOWED_ORIGINS. There is no wildcard.
Recommended: serve each application on its own host name, and pass
/api/to the control plane with the browser'sHostkept (infra/serve/apelora.conf). Each page's origin is then the host the control plane sees, and nothing needs listing.When the API is reached under another host name (the proxy rewrites
Host, or a load balancer sits in between), list both applications by origin:APELORA_ALLOWED_ORIGINS=https://studio.example.internal,https://console.example.internal
Development: the Vite development servers of the Studio (
http://127.0.0.1:5173) and the Console (http://127.0.0.1:5174) pass/apion (including websockets) with the browser'sHostkept, so they work without configuration. To list them explicitly, as for a proxy that rewritesHost:APELORA_ALLOWED_ORIGINS=http://127.0.0.1:5173,http://127.0.0.1:5174Any other origin (
http://127.0.0.1:5175,http://localhost:5174) is refused with403 origin_not_allowed.
Sessions need sign-in. A control plane in development mode (DATABASE_URL=) checks origins and tickets but never opens a shell.
Remote desktop (Windows modules)
Off unless the control plane runs with APELORA_RDP_GATEWAY=enabled. It needs instance.desktop on the application (and, in production, another person's approval of instance.desktop, as for a terminal).
- Install
apelora-desktop-tunnelon your computer (theapelora-desktop-tunnel-…archive of the release; on other systemscargo build --release -p apelora-desktop-tunnel). - In the Fabric Console choose Terminal… on the Windows instance, pick Remote desktop and Connect with RDP.
- Run the command the dialog shows. When it asks, paste the ticket; it works once, for about a minute.
- Connect your remote desktop client to the address the tunnel prints (a free port on
127.0.0.1). Check the certificate Windows presents before you sign in: the client and Windows encrypt the session between them, and Apelora relays it without decrypting it. If you accept a certificate you have not checked, that protection depends on everything in between being trustworthy.
Do not run the tunnel on a computer other people are signed in to: until your client connects, anyone on that computer could connect to the port first and get your session.
The session ends when you disconnect, after 15 minutes without input or at 60 minutes, like a terminal, and appears on the Sessions page. The module's RDP port is never published; the control plane reaches it from inside the guest. The Studio's right-click menu lists the remote desktop and points here.
Content security policy
The terminal emulator writes <style> elements while it runs, so both sites set $apelora_style_elements to 'unsafe-inline' in infra/serve/apelora.conf. Scripts stay limited to the site's own files.
Troubleshooting
| You see | Why | What to do |
|---|---|---|
| You do not have instance.console on this application | No role with the permission on that application | Ask for Instance Access on its project or application |
| Not allowed: … after Request approval | You lack approval.request on that application | Ask for a role that includes it (Instance Access does) |
| The instance is stopped… | Sessions open only into running instances | Start the application |
| The control plane cannot read Incus… | Incus is unreachable, so the state is unknown | Try again; check Health |
| You already have the most sessions allowed | 3 sessions or unused tickets per person (APELORA_CONSOLE_MAX_SESSIONS) | End one on the Sessions page |
| The terminal never connects | The websocket was refused, usually by the origin check | Check that the proxy passes Upgrade and Host, or list the origin in APELORA_ALLOWED_ORIGINS |
| The tunnel says Apelora refused the session (401 …) | The ticket was used, expired, or issued to another page | Ask for a new one in the Console and paste it within a minute; keep --origin as the dialog shows it |
| The tunnel says --listen must be a loopback address | The tunnel only serves this computer | Use 127.0.0.1:<port> |
| Mock · no real instance | The control plane runs with simulated data (the mock provider used in development) | The shell is a labelled fake; nothing runs on a server |
Before you rely on it
- Terminal sessions have been tested against a simulated Incus, not yet against a real instance, a Windows guest or a live identity provider. Remote desktop has never reached a Windows guest. Open one on a test application before you rely on it.
This page is a copy of docs/guides/terminal-sessions.md in the repository, which is the source of truth. Suggest a change.