Skip to content

Shell and files ​

Open a shell in a running service from the dashboard or the CLI, manage the files in a service's volume without a shell at all, or connect to the volume with an SFTP client.

All of them need the member role (viewers can't use them). Every shell session, every change to volume files and every SFTP server start and stop is recorded in the team's activity log.

Terminal ​

The Terminal tab of a service opens a shell in one of its running replicas: bash if the image has it, otherwise sh. It runs in the app's container, as the container's user, with the service's variables in the environment.

  • With more than one replica, pick the one to connect to from the list next to the status.
  • Reconnect opens a new session. If the connection drops (a network blip, a Fjordrun update), the terminal reconnects by itself a few times.
  • A session closes after 30 minutes without input, and after 4 hours in any case.
  • A shell doesn't count as traffic: a service that sleeps when idle can fall asleep, and end the session, while you're in it.

Anything you change outside a volume is lost on the next deployment or restart: each replica starts from the image. Use the terminal to inspect, debug and run one-off tasks (a migration, a script), not to change the app.

From the CLI ​

bash
fjordrun ssh                          # interactive shell in the linked service
fjordrun ssh --service api            # another service of the linked project
fjordrun ssh -- ls -la /data          # run one command
fjordrun ssh --replica web-7d9c-x2k4q # a specific replica
cat dump.sql | fjordrun ssh --service postgres -T -- psql -U postgres

The command's arguments are joined with spaces and run with /bin/sh -c, like ssh does. fjordrun ssh exits with the command's exit code, so it works in scripts and CI (with a team API token in FJORDRUN_TOKEN). When stdin or stdout isn't a terminal, or with -T, no terminal is allocated: input is forwarded until it ends, and stderr stays separate from stdout.

When there is no shell ​

  • No running replica: a stopped service, a service that is asleep (open its URL to wake it), or a cron job between runs. The terminal tells you which.
  • Images without a shell (distroless, scratch): there is no /bin/sh to start, so the terminal shows This image has no shell. Use the file manager for the volume, or build an image that includes a shell (for example a -debug or -slim variant of the base image).
  • Agent services run in a gVisor sandbox. The shell works the same way there.

Files ​

Services with a volume have a Files tab: a file browser for the volume.

  • Click folders to open them; the path at the top takes you back.
  • Upload files, or drag and drop them onto the list. Each file can be up to 100 MB. Uploading over an existing file asks first.
  • Download, rename (type a new name; a name with / moves the entry) and delete (with a confirmation; deleting a folder deletes everything in it) from each row.

Paths are relative to the volume: / is the folder the volume is mounted at (for example /data). You can't leave the volume, also not through symbolic links: links pointing outside the volume are listed but can't be opened.

The file manager works with every image, including images without a shell, and also while the service is stopped or asleep. Files you upload belong to the owner of the folder they are uploaded to, so the app can keep writing them.

Databases

The volume of a database holds its data files. Changing or deleting them while the database runs can corrupt it. Use the database's own tools for backups and restores (see Databases).

From the CLI ​

bash
fjordrun files ls /uploads
fjordrun files get /backups/db.sql ./db.sql
fjordrun files get /config.json -              # to stdout
fjordrun files put ./seed.json /seeds/         # a path ending in / is a folder
fjordrun files put --force ./seed.json /seeds/seed.json
fjordrun files mkdir /exports
fjordrun files mv /exports /archive/exports
fjordrun files rm /tmp-import                  # asks first; --yes to skip

SFTP ​

For bigger transfers, or to use the tools you already have, start an SFTP server for the volume and connect with FileZilla, WinSCP, Cyberduck or the sftp command. It is available on the Hobby plan or higher and needs the member role.

SFTP is key-based only: there are no passwords. Add your public key under Account → SSH keys first (see SSH keys); without one, Start SFTP is disabled and links you there.

Start a server ​

  1. Open the service, then the Files tab, and choose Start SFTP.

  2. After a few seconds the card shows the host, port, user and the server's host key fingerprint, and a ready-made command:

    bash
    sftp -P 20345 fjordrun@tcp.fjordrun.app
  3. Connect. The volume is the /files folder.

The server accepts the keys your account has when you start it. A key you add later works the next time you start a server; deleting a key stops the servers that were started with it. Only the person who started the server can log in: starting one on a shared service doesn't give your teammates access with their keys.

The server stops by itself after 15 minutes without a connection (connected clients keep it running), and after 8 hours at the latest. Choose Stop SFTP to stop it earlier. Starting it again takes a few seconds. The port is different each time, the host key stays the same.

With the CLI:

bash
fjordrun ssh-keys add ~/.ssh/id_ed25519.pub
fjordrun sftp                  # starts the server and prints the sftp command
fjordrun sftp stop

Check the host key ​

On the first connection your client shows the server's host key fingerprint. Compare it with the one in the dashboard (or fjordrun sftp) before you accept it: it is the same for every session of the service, so a different one means you are not talking to your volume.

text
$ sftp -P 20345 fjordrun@tcp.fjordrun.app
The authenticity of host '[tcp.fjordrun.app]:20345' can't be established.
ED25519 key fingerprint is SHA256:Qm2…   <- must match the dashboard

Clients ​

  • sftp — sftp -P <port> fjordrun@tcp.fjordrun.app. Use -i ~/.ssh/other_key for a key that is not one of your default ones. Recent scp versions transfer over SFTP too (scp -P <port> file fjordrun@tcp.fjordrun.app:/files/); the server has no shell, so ssh and rsync over SSH don't work.
  • FileZilla — File → Site Manager → New site. Protocol SFTP - SSH File Transfer Protocol, the host tcp.fjordrun.app, the port from the dashboard, logon type Key file, user fjordrun, and your private key file (FileZilla converts OpenSSH keys to its own format the first time).
  • WinSCP — File protocol SFTP, host name tcp.fjordrun.app, the port, user name fjordrun, then Advanced → SSH → Authentication → Private key file.
  • Cyberduck — Open Connection, SFTP (SSH File Transfer Protocol), the server, port and user, and choose your private key under SSH Private Key; leave the password empty.

What the server allows ​

Only file transfer. There is no shell or terminal, no port forwarding, no agent or X11 forwarding and no way out of the volume: the session is confined to a folder that contains nothing but your volume, so other files of the container, the cluster and other services are not reachable. Files you upload belong to the same user and group that own the volume, and uploaded files get group write permission within about 30 seconds (SFTP clients usually create files as 644), so the app can keep writing them. Run chmod from your client to change a file's mode afterwards.

Deploys stop SFTP

A volume can only be attached to one server at a time, so deploying the service, or removing its volume, stops its SFTP server. Start it again afterwards.

How it works ​

The shell is a kubectl exec-style session into the running container: nothing is installed in your image, and no SSH server or port is opened.

The file manager doesn't need anything in your image either. It adds a small helper container (BusyBox) to a running replica, which mounts the same volume. When nothing runs, a short-lived helper pod mounts the volume instead. It stops after 15 minutes, and as soon as the service is deployed or started. A volume can only be attached to one server at a time: a service woken from sleep while the helper pod holds its volume may wait until the helper stops.

The SFTP server is a small separate pod (OpenSSH with only the internal-sftp subsystem, 0.1 vCPU and 128 MB at most) that mounts the volume, on the same server as your running replicas, because a volume can only be attached to one server at a time. It has no internet access and is reached through the same public TCP host as database ports, on a port of the same range; the port is released when the server stops.

Pricing ​

The terminal, the file manager and SFTP cost nothing extra. Commands you run in a replica use its CPU and memory, which are billed as usual. The helper pod used while a service is stopped and the SFTP server are not billed (the volume itself is, as always).

API ​

The API reference lists the file manager endpoints (/services/{id}/files…), the SFTP endpoints (POST, GET and DELETE /services/{id}/sftp, returning an SFTP server) and POST /services/{id}/shell/ticket. Your SSH keys are managed with /auth/ssh-keys (SSH key). The shell itself is a WebSocket:

  1. POST /api/v1/services/{id}/shell/ticket with a bearer token returns a one-time shell ticket, valid for 30 seconds. Optional body: {"replica": "…", "command": "ls -la", "tty": true}.
  2. Open wss://api.fjordrun.com/api/v1/services/{id}/shell?ticket=…&cols=120&rows=40 (the ticket's url, plus the terminal size). The ticket is the authentication: browsers can't send headers on a WebSocket.

Messages in both directions:

FrameDirectionContent
binaryclient → server0x00 followed by stdin bytes
binaryserver → client0x01 + stdout bytes, or 0x02 + stderr bytes (with a terminal, all output is stdout)
textclient → server{"type": "resize", "cols": 120, "rows": 40}, {"type": "stdin", "data": "ls\r"}, {"type": "eof"}
textserver → client{"type": "ready", "replica": "…", "replicas": […]}, {"type": "exit", "code": 0}, {"type": "error", "message": "…"}

The server closes the connection after exit (code 1000) or error: 4401 for an invalid, expired or used ticket, 4404 when the replica is gone, 4408 after the idle or maximum session time, 4429 with too many open sessions (10 per user), 4500 when the shell could not start or the connection to the replica ended without an exit code (for example, the replica was replaced mid-command).

Fjordrun is hosted in the EU (Hetzner, Nuremberg, Germany). Private beta.