Browser terminal
A shell on a server in the app's console, as the deploy user or as one site's own account.
What it is
A shell on one of your servers, in a tab of the app’s console, with no SSH key to attach. You open one from the server’s menu, from ⌘K, or from Terminal on… under the console’s +. It is for the ten minutes when something is wrong and you need to look. It does not replace your own SSH client, and it is the wrong tool for anything you want a record of afterwards.
Who can open one
- Admins and owners only. The same trust as revealing an environment file or managing the SSH key pool. A member cannot.
- You must have entered your password within the last two minutes. That is tighter than the five minutes that guards creating an API token. Your role and your session are re-checked on every keystroke batch, so an admin demoted mid-session loses the shell they already hold.
- Never with an access token. No scope grants a terminal, because there is no bounded subset of "arbitrary commands as a user with passwordless sudo". All four of its endpoints are refused to tokens, including the read-shaped ones, since attaching to somebody else's session would be reading their root shell.
- Never by Provisore support. A staff member acting as you is refused a terminal by the same rule that refuses them your secrets.
- Only by the person who opened it, from where they opened it. A session belongs to your sign-in and the console tab that opened it. Another admin of the team, or you signed in from another browser, cannot attach to it, type into it or close it.
Which account the shell runs as
You choose from the Run as list every time. There is no default, because defaulting to the deploy user would hand a root-equivalent shell to anybody who did not read the form.
- The deploy user. Listed as provisore (deploy user · root-equivalent). The account Provisore manages the server with. It holds passwordless sudo, so this is a root shell in everything but name.
- A site’s own account. Listed by domain, as a site account. A real privilege drop into the Unix account that site runs as. That account is not in sudoers and has no login shell of its own, so the resulting shell cannot get back to root.
Every active site on the server is in the list.
How long it lasts
Idle timeout 3 minutes with no traffic in either direction
Session cap 15 minutes, whether or not it is busy
Server backstop 16 minutes, enforced on the server itself
Per server 1 session at a time
Per team 2 sessions across all serversOne session per server is a choice rather than a capacity limit. Two people running apt in the same shell without knowing about each other is worse than one of them waiting.
The server enforces its own 16-minute limit, a little past the 15-minute session cap, so an abandoned shell hangs up on its own even if Provisore is stopped, redeployed or partitioned away mid-session. Losing the connection ends the session too. Closing the tab or signing out reaps the shell within a few seconds, and a dropped network connection reaps it once Provisore’s next keep-alive fails to reach the browser.
What ending a session does to what it started
Everything a session starts runs in a systemd scope named for it, provisore-terminal-<id>.scope, where the id is the terminalId on the session’s audit entries.
Closing a session hangs up every process in that scope still attached to the terminal, as logging out of SSH does. The shell and every command still running under it stop. A command you deliberately detached with nohup or setsid keeps running, the same as after an SSH logout, and stays in the scope: systemctl status provisore-terminal-<id>.scope on the server lists it, and sudo systemctl stop on the same unit ends it. A long build belongs in a recipe or a daemon rather than a terminal you have to hold open.
A site account’s shell can leave behind what that site’s own code can. Files it writes under /tmp or /dev/shm stay until they are deleted or the server restarts, and a crontab it installs with crontab -e keeps running as that account. It cannot schedule anything as another account or keep a systemd user service running.
What is recorded, and what is not
Two entries per session in your audit log, one when it opens and one when it ends. Between them they record who, which server, which Unix account, whether that account was root-equivalent, the IP it came from, how long it lasted, why it ended, and how many bytes went each way. A refused attempt is recorded too.
What was typed and what was printed are not recorded. Terminal echo happens on the server, so what reaches Provisore is raw keystrokes. The password you type at a sudo prompt, at mysql -p, or pasted from a password manager is byte-for-byte indistinguishable from a command. A transcript would be a credential store, held in the same database that already holds every customer's SSH keys. The byte counts are volumes only, enough to tell "opened and closed without touching anything" from "ran a build", and not enough to reconstruct a keystroke.
The record of what was run is on your own server, in /var/log/auth.log, which records the SSH login and the sudo that started the shell, naming the account it ran as. You own that file, and Provisore cannot rewrite it.
Limits
- One connection per session. A session belongs to the console tab that opened it. Anywhere else needs a new session.
- It does not reconnect. A dropped connection ends the session rather than leaving the shell open for whoever attaches next.
- Keystrokes and small pastes, not file transfers. Each input request carries at most 4 KiB; a larger paste is split into several. To move a file, use the site’s deploy or an environment file.
- Links open on a ⌘- or Ctrl-click, and only http and https links. Hovering one shows where it goes.
- Free on every plan, including the cheapest.
A terminal can do anything, and what it does is not recorded. A daemon, a cron entry, a firewall rule, or a recipe is tracked by Provisore, repeatable, and visible to the rest of your team.