Hand a developer site-scoped SFTP access in two minutes — a per-site SFTP system user inside the instance, confined to the site root, reached via ProxyJump through the node, with a one-line revoke. Never a panel login.
The Access keys tab on the site workspace gives a developer SFTP access to one site
without giving them a panel account, an instance shell, or access to any other site. Pasting their
SSH public key creates an SFTP-only user inside the instance, confined to that
site's folder and reachable only through the node. Revoke is one click.
An access key is NOT a panel login
A developer access key is an SSH public key for a per-site SFTP user inside the instance. It
grants no panel access at all — the developer role can't do anything in the panel. Operator
credentials and developer credentials are kept separate on purpose, because the damage each could
do is different.
One SFTP user per site. The username is sitedev-<8 hex of the site id> (shown in the tab as
the SFTP user). All of a site's keys live in that one user's authorized_keys.
Confined to the site's own directory. The jail is the site directory itself
(/srv/web/<slug> or /srv/app/<slug>) — not the folder above it, which holds every other site on
the instance. Inside the jail the user can read and write releases/ and shared/, and the session
lands in releases/. Nothing above the site directory is reachable, and no other site's files are
visible. They get SFTP only, never a shell.
Uploads go into a release.releases/<timestamp>/ is the tree that serves, reached through the
current link; shared/ is for anything that must outlive a deploy. A file dropped into a release
goes when that release is eventually pruned.
Public key only. The panel only ever stores the developer's public key. Pasting a
private key is rejected, as is garbage or an unsupported key type. The audit row records only
the fingerprint and username — never the key itself.
Reached through the node. SFTP connects by jumping through the node, which is the only door —
the instance is never exposed directly.
This is the whole loop — create a key, send the connection line, revoke when the work is done.
The developer sends their public key. If they need one:
ssh-keygen -t ed25519 -f ~/.ssh/sitedev # → ~/.ssh/sitedev (private) + ~/.ssh/sitedev.pubcat ~/.ssh/sitedev.pub # this PUBLIC line is what gets sent
Create the key in the panel. Site workspace → Access keys → Add developer key: give
it a Name (e.g. "Alice's laptop"), paste the SSH public key, then Add developer key.
The first key sets up the SFTP user; later keys just get added to it.
Copy the connection line from the Developer handoff card and send it to the developer. It's
the exact sftp command, already filled in:
It jumps through the node (-o ProxyJump=<node-user>@<node-host>), then connects as the confined
SFTP user inside the instance (<sitedev>@<instance>). The developer connects with their private key:
put/get works inside the site folder; a write outside it is permission denied.
Revoke when done. On the key's row, click Revoke and confirm. That key stops working
immediately. Revoking the last active key for the site locks the SFTP user, so
no one can reconnect. The key row stays in the list as revoked, preserving the history.
The snippet appears once the instance is reachable
The Developer handoff card shows the connection line as soon as the site's instance and node are
reachable. If the instance is down, the keys still list — only the snippet is hidden until it
comes back.
Listing keys and seeing the connection snippet needs SITES_ACCESS_KEYS_VIEW (operator and
admin, read-only). Creating and revoking keys needs SITES_ACCESS_KEYS_MANAGE (admin). Without
MANAGE, the Add form and the Revoke action are hidden.