PricingGet started

← Docs

Going further

SSH into a Node or Next.js app

Every full-stack app comes with a real SSH login into its own container — a shell in your app's directory with its environment loaded, plus everything that rides on SSH: scp, rsync, SFTP, VS Code and Cursor Remote-SSH, and a tunnel to your database. Set it up once, and every tool after that just uses a short alias.

SSH comes with full-stack apps — the ones with their own database or Redis. A front-end app or a static site deploys from git only: there's no server process worth logging into, so there's no login to secure either. Attach a database and the app becomes full-stack, and its SSH tab appears. (WordPress sites get SSH on every plan — see SSH and WP-CLI on a WordPress site.) Access follows your team: anyone who can open the app in the panel can connect with their own key, and a developer whose access is limited to other sites can't.

  1. Add your public key
    Go to Account → SSH keys and paste your public key — the one-line contents of ~/.ssh/id_ed25519.pub. Ed25519, ECDSA and RSA keys of 2048 bits or more work. A key belongs to you, not to an app, so one key covers every app you have access to. Never paste the private key — the panel refuses it.
  2. Copy the config block
    Open the app and go to its SSH tab. Add the block it shows to ~/.ssh/config: it gives the app a short alias, so ssh, scp, rsync and your editor all just use that name.
  3. Connect
    Run ssh followed by the alias. You land in /app — your code as deployed — with the app's environment variables loaded, as the same unprivileged user your app runs as.
  4. Check the host key once
    On the first connection your SSH client shows the server's fingerprint and asks whether to trust it. The SSH tab shows the same fingerprint — compare the two before you answer yes.
~/.ssh/config — the SSH tab shows this filled in with your app's values
Host my-app
  HostName my-app.p.belov.cloud
  Port 2222
  User a1b2c3d4e5f6
Everyday use
ssh my-app                                   # a shell in /app, env loaded
ssh my-app 'node scripts/fix.mjs'            # run one command
scp ./dump.csv my-app:/data/                 # copy files in and out
rsync -av ./uploads/ my-app:/data/uploads/   # sync a folder
sftp my-app                                  # or any SFTP client

VS Code and Cursor connect the same way: Remote-SSH → Connect to Host → pick the alias. The first time, the editor installs its server into your home directory; after that it opens the container like a local folder, terminal included.

To work with your database from your own machine, open a tunnel and point TablePlus, DBeaver or psql at localhost. The tunnel starts inside your app's container, so it reaches exactly what your app can — nothing more. The username and password are in the app's own connection string.

Database tunnel
ssh -N -L 5432:belov-pg:5432 my-app          # Postgres → localhost:5432
ssh -N -L 3306:belov-db:3306 my-app          # MySQL → localhost:3306
ssh my-app 'echo $DATABASE_URL'              # the credentials

Your environment variables are reachable over SSH too — the same store as the Env vars tab, so the panel and the terminal can never disagree. A push merges: keys in the file are added or updated, and everything else stays. To also delete keys the file doesn't have, add --prune --yes (without --yes it only lists what would go). Platform-managed values — PORT and injected service URLs like DATABASE_URL — are skipped with a note, never overwritten, and the output names keys only, never values. Changes go live exactly like Save & apply in the panel: a health-checked restart, or a rebuild when a Next.js NEXT_PUBLIC_* value changed. Add --no-apply to hold them for your next deploy, or --dry-run to preview.

Environment variables over SSH
ssh my-app belov env pull > .env.production     # download
ssh my-app belov env push < .env.production     # add or change keys
ssh -t my-app belov env edit                    # edit in place, review the diff, apply
What persists — and what doesn't
/app is rebuilt from git on every deploy, so an edit there lasts only until your next push — commit real changes. /data is persistent: uploads, generated files and your home directory live there, and /data is in the daily backups (editor servers and package caches in your home are skipped — they reinstall themselves). When you disconnect, what you started in that session gets a hangup signal, as on any SSH server; for recurring work, use the app's Schedule tab instead.
When SSH says no
Connect to a front-end app, a static site, a paused app or one that hasn't deployed yet, and the login tells you why instead of failing silently. If you're not on the app's team, the connection is simply refused. Remove a key or a teammate and new connections stop within half a minute. Every session is recorded in the app's Activity.
OpenSSH 10 and post-quantum key exchange
Recent OpenSSH may print a notice that the connection doesn't use post-quantum key exchange. That's accurate — the gateway uses curve25519 for now, like most SSH servers today. To hide the notice, add the line WarnWeakCrypto no-pq-kex to the Host block.

SSH, a managed database and daily backups come with every full-stack app — one flat price, no usage meter.

Node & Next.js pricing →

← All guides