---
title: "Deploy Ubuntu Dev Box (SSH + Claude Code)"
description: "Persistent Ubuntu 24.04 dev box: SSH + browser terminal, Claude Code"
category: "Other"
url: https://railway.com/deploy/kit-ubuntu-ssh-skeleton-0919
---

# Deploy Ubuntu Dev Box (SSH + Claude Code)

Persistent Ubuntu 24.04 dev box: SSH + browser terminal, Claude Code

**[Deploy Ubuntu Dev Box (SSH + Claude Code) on Railway](https://railway.com/template/kit-ubuntu-ssh-skeleton-0919)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/kit-ubuntu-ssh-skeleton-0919/manifest.json

- **Creator:** Will
- **Category:** Other
- **Total deploys:** 5

## Template content

### Ubuntu https://devicons.railway.com/i/ubuntu.svg

- **Image:** ghcr.io/will-bogusz/railway-ubuntu-ssh:24.04-20261003@sha256:f7231f540d36c0148d154bb43a4c46e924eb4a49a01b97dbffb94cce81e69b7c
- **Health check:** /healthz
- **Public domain:** Yes

## Documentation

# Deploy and Host an Ubuntu Dev Box (SSH + Claude Code) on Railway

![Claude Code starting in tmux on the Dev Box, with the same session attached over SSH and in the browser terminal on desktop and phone](https://bogusz.co/external/ubuntu-dev-box-banner-v1.png)

Your own always-on Ubuntu 24.04 box with Claude Code: SSH in from any client or open it in a browser, and your projects, dotfiles and Claude login survive every redeploy.

**Get started**

1. **Deploy.** Nothing to fill in; the SSH port is already exposed through a TCP proxy. Idle, it uses about 23 MB of RAM. Free and Trial volumes hold only 0.5 GB, so use Hobby for real projects.
2. **Connect.** The deploy log prints the exact `ssh dev@… -p …` line; the password is `SSH_PASSWORD` in the service's **Variables** tab. Or open the service URL for a browser terminal (user `dev`, same password).
3. **Run `claude`.** Sign in once with your Claude subscription, or set `ANTHROPIC_API_KEY`; the login is stored on the volume.

## About Hosting an Ubuntu Dev Box

A persistent Ubuntu 24.04 LTS dev box you reach over **SSH** (from Termius, Blink, VS Code Remote or any client) or a **browser terminal**, with **Claude Code** preinstalled and your home directory on a **volume** that survives every redeploy. The service runs three small processes: `sshd` on port 22 behind a Railway TCP proxy, `ttyd` (a terminal in your browser) behind `nginx` with basic auth on the public HTTPS domain, and a supervisor that restarts any of them within seconds if it dies (say, after running out of memory), so the box stays up. Login is user `dev` with the generated `SSH_PASSWORD` or your public key; root login is disabled, sshd allows four tries per connection and throttles repeated failures per source address. `/home/dev` is a Railway volume, so projects, dotfiles, Claude Code's own state (`~/.claude`), tools you install and even the SSH host keys persist across redeploys. Railway's healthcheck (`/healthz`) only passes once the terminal actually answers.

## Common Use Cases

- **Claude Code from anywhere.** SSH in from a laptop, or open the browser terminal from a phone or a locked-down machine, and keep an agent session running in tmux while you are away.
- **A persistent Linux scratch box.** Clone a repo, install what you need, leave it for a week, come back to the same shell.
- **A lightweight always-on dev environment.** Point VS Code Remote-SSH or JetBrains Gateway at it; idle, the box uses about 23 MB of RAM.
- **Long-running jobs without a laptop.** Data pulls, builds and scripts that outlive a local terminal session.

## Dependencies for Ubuntu Dev Box Hosting

None. A single service with one volume. Claude Code needs an Anthropic account: an API key or a Claude subscription login, both optional at deploy time.

### Deployment Dependencies

- [Image source and runtime contract](https://github.com/will-bogusz/railway-ubuntu-ssh)
- [Claude Code documentation](https://docs.claude.com/en/docs/claude-code)
- [ttyd](https://github.com/tsl0922/ttyd) (browser terminal)
- [Railway TCP proxying](https://docs.railway.com/networking/tcp-proxy)
- [Railway volumes](https://docs.railway.com/volumes)

### Implementation Details

**Plan requirements.** Idle, the box uses about **23 MB** of RAM (measured on this image: 23 MB after five idle minutes, 31 MB peak at boot) and is well under Railway's Free and Trial memory limits. Claude Code sessions add a few hundred MB while they run; builds and language servers add whatever they need. Free and Trial volumes hold 0.5 GB (Hobby: 5 GB), so Hobby is the comfortable fit for daily use. One click, no inputs: the password is generated for you. Node.js 24 LTS, Python 3, git, GitHub CLI, build-essential, tmux and the usual tools are included; `dev` has passwordless `sudo`. The image is pinned by digest, so what you deploy today is what you get on every redeploy.

**Connecting over SSH.** Open the service, then **Settings → Networking → TCP Proxy**: it shows a host and port. Connect with

```bash
ssh dev@your-service.proxy.rlwy.net -p 12345
```

The password is `SSH_PASSWORD` in the service's **Variables** tab (Railway generated it at deploy). The deploy log also prints the exact `ssh` line once at boot. Host keys are stored on the volume, so a redeploy will not trigger a host-key-changed warning.

**Connecting from the browser.** Open the service's public URL. Sign in with user `dev` and the same `SSH_PASSWORD`. You land in a tmux session named `main`: close the tab and reopen it later and the session, and anything running in it, is still there. Works from a phone.

**Adding SSH keys.** Either paste public keys into the `AUTHORIZED_KEYS` variable (one per line) and redeploy, or append them to `~/.ssh/authorized_keys` on the persistent home volume. Verify that your key works before disabling password login. To require keys for SSH, add `SSH_PASSWORD_AUTH=no` in Railway's Variables tab and redeploy. The startup script applies it on every boot, including after redeploys; if no authorized key is present, it logs a warning and leaves SSH password login enabled to avoid locking you out. The browser terminal continues to use `SSH_PASSWORD`. Remove `SSH_PASSWORD_AUTH` or set it to `yes` and redeploy to restore SSH password login.

**Claude Code.** Run `claude`. With no key set it offers the Claude subscription login: open the link it prints on any device, paste the code back. The login is stored in `~/.claude` on the volume, so you do it once. To use an API key instead, set `ANTHROPIC_API_KEY` in the Variables tab and redeploy. The pinned copy in the image is Claude Code 2.1.278; to move to the latest, run `curl -fsSL https://claude.ai/install.sh | bash` — it installs into `~/.local/bin` on your volume, which is first on `PATH`.

**Codex, opencode and other tools.** `npm install -g @openai/codex` or `npm install -g opencode-ai` install into `~/.npm-global` on the volume without `sudo`. `pip`, `pipx`, `uv`, `cargo` and anything under `~/.local` persist the same way. For apt packages use `sudo apt-get install`; those live in the container layer and are gone after a redeploy, so put the command in a script on the volume if you rely on them.

**GitHub.** Set `GITHUB_TOKEN` and both `git` (HTTPS clone/push to github.com) and `gh` authenticate with it. Or run `gh auth login` interactively; its state persists on the volume too.

**Environment variables.** Every variable you add in the Variables tab is exported into your SSH and browser sessions after the next deploy, except `SSH_PASSWORD`. That is how `ANTHROPIC_API_KEY`, `GITHUB_TOKEN`, `TZ` and anything else of your own reach the shell.

**What persists and what does not.** Persists: everything under `/home/dev` (projects, dotfiles, `~/.claude`, `~/.local`, `~/.npm-global`, `~/.ssh`), and the SSH host keys. Does not persist: apt packages, files outside `/home/dev`, and running processes (a redeploy restarts the container, so tmux sessions end). Redeploying a service with a volume involves a few seconds of downtime; that is a Railway volume property, not a template setting.

**Rotating the password.** Change `SSH_PASSWORD` in the Variables tab; the next deploy applies it to SSH and the browser terminal together.

**Resource use.** Measured on this image: about 23 MB of RAM idle. Claude Code and builds add memory and CPU while active. There is nothing here that keeps the box busy on its own.

**Security notes.** The box is a real Linux machine on the public internet: SSH is exposed through Railway's TCP proxy (with a 24-character generated password, root login disabled, four tries per connection) and the browser terminal through HTTPS basic auth. Keys are better than passwords; add yours. `dev` has passwordless `sudo` inside the container, which is the point of a dev box, not a hole in one. This template is for personal development use; running it as a shared shell service or reselling access is outside Railway's Fair Use policy.

### Why Deploy an Ubuntu Dev Box on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying an Ubuntu Dev Box on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.


## Similar templates

- [Rocky Linux](https://railway.com/deploy/rocky-linux) — Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀
- [Foundry Virtual Tabletop](https://railway.com/deploy/X5tR6G) — A Self-Hosted & Modern Roleplaying Platform
- [Letta Code Remote](https://railway.com/deploy/letta-code-remote) — Run a Letta Code agent 24/7. No inbound ports, just deploy.

Open this page in a browser: https://railway.com/deploy/kit-ubuntu-ssh-skeleton-0919
