{"id":30328841,"url":"https://github.com/sammy-t/ts-term","last_synced_at":"2026-04-03T00:45:43.243Z","repository":{"id":310305056,"uuid":"1035757060","full_name":"Sammy-T/ts-term","owner":"Sammy-T","description":"Browser-based SSH sessions using ephemeral Tailscale nodes.","archived":false,"fork":false,"pushed_at":"2026-02-11T04:10:14.000Z","size":285,"stargazers_count":8,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-02-11T08:54:03.829Z","etag":null,"topics":["bash","cli","command-line","docker","self-hosted","shell","ssh","tailscale","terminal","tsnet","web-app"],"latest_commit_sha":null,"homepage":"https://hub.docker.com/r/sammytd/ts-term","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Sammy-T.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-11T03:40:01.000Z","updated_at":"2026-02-11T04:09:58.000Z","dependencies_parsed_at":"2025-08-17T08:24:33.769Z","dependency_job_id":"64ed2f0d-dbe9-4599-b053-4d8614c48275","html_url":"https://github.com/Sammy-T/ts-term","commit_stats":null,"previous_names":["sammy-t/ts-term"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/Sammy-T/ts-term","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sammy-T%2Fts-term","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sammy-T%2Fts-term/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sammy-T%2Fts-term/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sammy-T%2Fts-term/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Sammy-T","download_url":"https://codeload.github.com/Sammy-T/ts-term/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sammy-T%2Fts-term/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29638772,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T22:32:43.237Z","status":"online","status_checked_at":"2026-02-20T02:00:07.535Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","cli","command-line","docker","self-hosted","shell","ssh","tailscale","terminal","tsnet","web-app"],"created_at":"2025-08-18T02:00:31.237Z","updated_at":"2026-02-20T02:01:37.168Z","avatar_url":"https://github.com/Sammy-T.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ts-term\n\nts-term serves a browser-based terminal interface and provides SSH through ephemeral Tailscale nodes.\n\nts-term is intended to be hosted from inside a [Docker](https://www.docker.com/) container on a machine in your tailnet. This way, you can access the service through your tailnet.\u003cbr\u003eEach session runs through ephemeral Tailscale nodes created under the user's identity.\n\n[Tailscale SSH](https://tailscale.com/kb/1193/tailscale-ssh) and their [SSH Console](https://tailscale.com/kb/1216/tailscale-ssh-console) are great tools for remote access to machines on your tailnet. If they suit your needs, I definitely recommend them.\u003cbr\u003e\nHowever, I wanted something I could self-host and which didn't take over my machine's `ssh` command so I made this project.\n\n\u003cimg width=\"1607\" height=\"832\" alt=\"Screenshot 2025-08-11 073307\" src=\"https://github.com/user-attachments/assets/9fabd24c-9fd6-4fdb-bb6b-c5594eafb78d\" /\u003e\n\n## Getting Started\n\n### Running with Docker run\n\nCreate a container network:\n\n```bash\ndocker network create ts-term-net\n```\n\nPull and run the container with the command:\n\n```bash\ndocker run -d -p 4000:3000 -h ts-term --name ts-term --network=ts-term-net -v ts-term-data:/home/appuser/.ssh sammytd/ts-term\n```\n\nThen visit your host machine's `\u003ctailscale-domain\u003e:4000` from a browser on a device logged in to your tailnet.\n\nClose the window or type `exit` while not using SSH to end the session.\n\n#### Docker run options\n\n| Option | Description |\n| --- | --- |\n| `-d, --detach` | Run the container in the background. |\n| `-p, --publish` | Publish the container's port to the host. The host port can be whichever available port you want.\u003cbr\u003e`\u003chost-port\u003e:\u003ccontainer-port\u003e` |\n| `-h, --hostname` | The container host name. (optional) |\n| `--name` | The container name (optional) |\n| `--network` | The container network to use. (recommended) |\n| `-v, --volume` | The container volume for persistent data. (recommended) |\n| `--env-file` | Read in a file of environment variables. (optional)\u003cbr\u003eSee [environment variables](#environment-variables). |\n\nSee \u003chttps://docs.docker.com/reference/cli/docker/container/run/\u003e for full reference.\n\n### Running with Docker Compose\n\n```yaml\n# compose.yml\n\nname: ts-term\n\nservices:\n  ts-term:\n    image: sammytd/ts-term\n    hostname: ts-term\n    # env_file: .env\n    ports:\n      - \"4000:3000\"\n    networks:\n      - ts-term-net\n    volumes:\n      - ts-term-data:/home/appuser/.ssh\n    restart: unless-stopped\n\nvolumes:\n  ts-term-data:\n\nnetworks:\n  ts-term-net:\n    name: ts-term-net\n```\n\nPull and run the container with the command:\n\n```bash\ndocker compose up -d\n```\n\nThen visit your host machine's `\u003ctailscale-domain\u003e:4000` from a browser on a device logged in to your tailnet.\n\nClose the window or type `exit` while not using SSH to end the session.\n\n### Environment Variables\n\n| Variable | Description | Default |\n| --- | --- | --- |\n| TS_TERM_ADDR | The address the ts-term server runs on. | `:3000` |\n| TS_CONTROL_URL | The coordination server to use. | The default Tailscale server |\n| TS_TERM_KNOWN_HOSTS | The absolute path to the known_hosts file. | `\u003cuser-home\u003e/.ssh/known_hosts` |\n\n## Development\n\n### Run the dev server\n\nRequirements:\n\n- [Node.js](https://nodejs.org/)\n- [pnpm](https://pnpm.io/) (optional)\n- [Go](https://go.dev/)\n\nCreate a `.env` file in the project root if you want to customize ts-term. See [environment variables](#environment-variables).\n\n#### Add Go dependencies\n\n```bash\ngo get ./...\n```\n\n#### Run the dev server\n\n```bash\ngo run . -dev\n```\n\nThen visit `localhost:3000` while logged in to your tailnet.\n\n### Build and run the Docker container\n\n#### Build the image\n\n```bash\ndocker build --platform=linux/amd64 -t my/ts-term .\n```\n\n#### Create and run a container from the image\n\n```bash\ndocker run -d -p 4000:3000 -h ts-term --name my-ts-term -v ts-term-data:/home/appuser/.ssh my/ts-term\n```\n\nThen visit your host machine's `\u003ctailscale-domain\u003e:4000`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsammy-t%2Fts-term","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsammy-t%2Fts-term","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsammy-t%2Fts-term/lists"}