{"id":28956998,"url":"https://github.com/developmentseed/remote-workstation","last_synced_at":"2025-06-23T21:41:21.398Z","repository":{"id":53445424,"uuid":"313697963","full_name":"developmentseed/remote-workstation","owner":"developmentseed","description":"A Dockerised work environment hosted on AWS Fargate which can be SSH'd into ☁️🌎📦","archived":false,"fork":false,"pushed_at":"2021-03-30T13:39:06.000Z","size":442,"stargazers_count":24,"open_issues_count":5,"forks_count":2,"subscribers_count":6,"default_branch":"main","last_synced_at":"2024-04-10T03:11:39.142Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/developmentseed.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}},"created_at":"2020-11-17T17:46:40.000Z","updated_at":"2023-10-25T19:20:06.000Z","dependencies_parsed_at":"2022-08-17T19:40:10.044Z","dependency_job_id":null,"html_url":"https://github.com/developmentseed/remote-workstation","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/developmentseed/remote-workstation","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developmentseed%2Fremote-workstation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developmentseed%2Fremote-workstation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developmentseed%2Fremote-workstation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developmentseed%2Fremote-workstation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/developmentseed","download_url":"https://codeload.github.com/developmentseed/remote-workstation/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developmentseed%2Fremote-workstation/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261561298,"owners_count":23177571,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2025-06-23T21:41:19.965Z","updated_at":"2025-06-23T21:41:21.362Z","avatar_url":"https://github.com/developmentseed.png","language":"Python","readme":"# Remote Workstation ☁️🌎📦 ![CI Status](https://github.com/developmentseed/remote-workstation/actions/workflows/ci.yml/badge.svg)\n\n\nThis project aims to enable the deployment of a dockerised workstation that can be SSH'd into\n\n* [Dependencies](#dependencies)\n* [General usage](#general-usage)\n* [With VS Code Remote SSH](#with-vs-code-remote-ssh)\n* [How this all works](#how-this-all-works)\n* [Customising the container image](#customising-the-container-image)\n* [Make commands](#make-commands)\n* [References](#references)\n\n# Dependencies\n\nTo be able to deploy your own workstation, you will need some prerequisites installed:\n\n* Node 14 (We recommend using NVM [Node Version Manager](https://github.com/nvm-sh/nvm))\n* [AWS CDK](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html) - There is a `package.json` in the repository, it's recommended to run `npm install` in the repository root and make use of `npx \u003ccommand\u003e` rather than globally installing AWS CDK\n* Python 3.8.* (We recommend using [pyenv](https://github.com/pyenv/pyenv))\n* [pipenv](https://github.com/pypa/pipenv)\n* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html)\n* [Docker](https://docs.docker.com/get-docker/)\n\nIf you're developing on MacOS, all of the above (apart from AWS CDK) can be installed using [homebrew](https://brew.sh/)\n\nIf you're developing on Windows, we'd recommend using either [Git BASH](https://gitforwindows.org/) or [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10)\n# General usage\n\n## 1. Install dependencies\n\nIf you only intend on deploying the infrastructure _as is_, you can install only the dependencies required for deployment with:\n\n```bash\n$ make install\n```\n\nHowever, if you intend on developing on this project and making contributions, you can install _all_ deployment and development dependencies with:\n\n```bash\n$ make install-dev\n```\n\n## 2. Create an SSH keypair\n\n```bash\n$ ssh-keygen -b 2048 -t rsa -f \u003ca-path-to-save-the-file-to\u003e -q -N \"\"\n```\n\n## 3. Prepare .env file\n\nTo perform some actions, this project requires a `.env` file to be present in the base of the project with some variables present.\n\nAn example `.env` file is provided: `example.env`, copy and rename this to `.env` and populate it with your own values.\n\nBelow is a table explaining the values we expect (and that can be used additionally) in your `.env` file:\n\n\n| Variable                      \t| Value(s)                                                                         \t| Required \t| Default                                                             \t| Description                                                                                                                                                                     \t|\n|-------------------------------\t|----------------------------------------------------------------------------------\t|----------\t|---------------------------------------------------------------------\t|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\t|\n| `SSH_PRIVATE_KEY_LOCATION`    \t| `\u003cpath/to/the/private/key\u003e`                                                      \t| ✅        \t| N/A                                                                 \t| You created this in Step 3                                                                                                                                                      \t|\n| `SSH_PUBLIC_KEY_LOCATION`         | `\u003cpath/to/the/public/key\u003e`                                              \t| ✅        \t| N/A                                                                 \t| You created this in Step 3                                                                                                                                                      \t|\n| `AWS_PROFILE`                 \t| `\u003cYour named AWS CLI profile\u003e`                                                   \t| 🚫        \t| default                                                             \t| The AWS Profile to deploy to                                                                                                                                                    \t|\n| `IDENTIFIER`                  \t| `\u003cAn identifier for your deployment, e.g. 'my-dev'\u003e`                             \t| 🚫        \t| dev                                                                 \t| This is unique to your deployed stack - If a conflict occurs, your deployment will fail                                                                                                                                          \t|\n| `SSH_CONFIG_LOCATION`         \t| `\u003cpath/to/your/ssh/config/file\u003e`                                                 \t| 🚫        \t| No value will result in a .ssh/config file created in the repo root \t| The SSH Config file to add the remote workstations details to                                                                                                                   \t|\n| `INSTANCE_CPU`                \t| `\u003cA value of 256/512/1024/2048/4096\u003e`                                            \t| 🚫        \t| 256                                                                 \t| See container CPU \u0026 Memory mappings [here](https://docs.aws.amazon.com/cdk/api/latest/python/aws_cdk.aws_ecs/FargateTaskDefinition.html#aws_cdk.aws_ecs.FargateTaskDefinition)  \t|\n| `INSTANCE_MEMORY`             \t| `\u003cA value of 512/1024/2048/...increments of 1024 till 30720\u003e`                    \t| 🚫        \t| 512                                                                 \t| See container CPU \u0026 Memory mappings  [here](https://docs.aws.amazon.com/cdk/api/latest/python/aws_cdk.aws_ecs/FargateTaskDefinition.html#aws_cdk.aws_ecs.FargateTaskDefinition) \t|\n| `CONTAINER_ECR_REPOSITORY`    \t| `\u003cThe value of an ECR repository name, e.g. 'my-magical-repo'\u003e`                  \t| 🚫        \t| N/A                                                                 \t| The name of an ECR repository in the region and account you're deploying into - **Note**: See [Customising the container image](#customising-the-container-image)                                                   \t|\n| `CONTAINER_DOCKER_REPOSITORY` \t| `\u003cThe value of an Dockerhub/other registry repo, e.g. 'docker/whalesay:latest'\u003e` \t| 🚫        \t| N/A                                                                 \t| Must be public - Credentials are currently not supported within this project - **Note** : See [Customising the container image](#customising-the-container-image)                                                   \t|\n| `CONTAINER_LOCAL_PATH`        \t| `\u003cpath/to/your/Dockerfile/folder - not the file itself\u003e`                          \t| 🚫        \t| N/A                                                                 \t| The file used to build the image must be called Dockerfile - **Note** : See [Customising the container image](#customising-the-container-image)                                                                     \t|\n| `TAGS_\u003cAny value\u003e` | `\u003cA value to assign to this tag\u003e` | 🚫 |  N/A  | You can add as many tags as AWS allows. To add a tag, add an entry to your `.env` file like `TAGS_MY_COOL_TAG=\"thisiscool\"` - Your AWS tag will be named with a Pascal case name like: `MyCoolTag` with the value you provided. You can read more about tags for AWS billing and tracking infrastructure [here](https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html)|\n\n## 4. Deploy the instance\n\n```bash\n$ make deploy\n```\n\n## 5. SSH to your instance\n\n```bash\n$ make ssh-to-instance\n```\n\n# With VS Code Remote SSH\n\nVS Code has an extension called [VS Code Remote SSH - Available here](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) - With this extension you can SSH onto a machine and develop on it in VS Code (locally). It also provides other utitilies such as SSH Port Forwarding.\n\nTo use the extension, install it and then make sure you've done Steps 1-4 under [General usage](#General-usage)\n\n## 1. Find Remote SSH command\n\nWith the plugin enabled, either open the actions menu in VS Code (MacOS is `CMD + Shift + P`), or select the little icon to the bottom left, selecting `Remote-SSH: Connect to Host...`\n\n![Remote SSH icon in VS Code](./images/remote-ssh-icon.png)\n\n## 2. Connect to host\n\nYou should now see a prompt with the contents of your SSH Config file (listing the hosts), you should see `remote-workstation-\u003cIDENTIFIER\u003e` - select that.\n\n![Remote SSH hosts](./images/remote-ssh-hosts.png)\n\n_**Note:** You might not see your workstation here, this is usually the case if you A: do not have an SSH Host config file in the default location or B: didn't provide one and the deployment has generated you one in `.ssh/config` in the root of the repository._\n\n_You can remedy this by selecting `Configure SSH Hosts...` and then `Settings` and providing the path to the non standard location_\n\n_The setting name is `remote.SSH.configFile`, if you'd rather search for it_\n\n## 3. Pointers\n\n### Files\nNow that you have established a connection to the instance, you can open files/folders on it like you would normally in VS Code: `File -\u003e Open...`\n\n### Extensions\nBecause VS Code Remote SSH bootstraps an VS Code server on the running instance, we can install any VS Code extension inside it, allowing us access to language support, enhanced debugging, and various other features.\n\n### Port Forwarding\nIf you're running a service that you'd like to access via `localhost` - say a webapp or a Jupyter Notebook, VS Code Remote SSH comes with SSH Port Forwarding built in.\n\n\n#### Simple example\n\nA very easy example you can peform on the `docker/Dockerfile` image is:\n```bash\n# On the instance\n$ echo \"Hello Remote Workspace!\" \u003e index.html\n$ python -m http.server 8181\n```\n\nWhen you then look at the Remote SSH pane, you'll see `Ports` which shows you which ports have services running on them in the instance, you can then select them to forward them on\n\n![Remote SSH Port Forwarding](./images/remote-ssh-port-forwarding.png)\n\nThen you can access it on `localhost:\u003ca-port\u003e`:\n\n![Remote SSH Port Forwarding index.html](./images/remote-ssh-index-html.png)\n\n_**Note:** you might also notice a prompt appear in VS Code asking if you'd like to visit the forwarded application, providing you a link to click on:_\n\n![Remote SSH Port Forwarding prompt](./images/remote-ssh-port-forwarding-prompt.png)\n\n#### Jupyter Example\n\nIf your image has Jupyter Notebook installed (or if you run `pip3 install jupyter` on the provided `docker/Dockerfile`), you\ncan setup port forwarding for a notebook instance:\n```bash\n# On the instance\n$ jupyter-notebook --no-browser --port=\u003ca-port\u003e\n```\n\nSimilarly to the [Simple Example](#simple-example), you will see the port you provided appear in the `Ports` selection, you can then forward it, navigate to `localhost:\u003ca-port\u003e` and access your notebook!\n\n![Remote SSH Port Forwarding Jupyter Notebook](./images/remote-ssh-jupyter.png)\n\n# How this all works\n\nThis project revolves around the ability to add a SSH client to a Docker container that we then serve via [AWS Fargate](https://aws.amazon.com/fargate/)\n\nBelow is a high level diagram of what is happening architecturally:\n\n![High level architecture](./images/remote-ssh-setup.png)\n\nThe user runs `make deploy`, under the hood this does:\n\n1. A CDK deploy which deploys a Fargate instance. This Fargate service is based on a docker image within `docker/`. As part of this, the users public IP is added to a security group to allow SSH access to the instance. The public key the user provided is also added into the instance\n2. The `utils/generate_ssh_config.py` script is called. This first identifies the public IP address of the Fargate instance, then generates an SSH config entry for the host. If a location is provided for the config file, the entry is either added or overwritten. If the location is not provided, the `.ssh/config` file is created and the entry is added\n3. Finally (external to `make deploy`), the user SSH's onto the Fargate instance\n\n# Customising the container image\n\n## The image\n\nTo use this project, the only essential components to ensure a Docker image has are:\n\n* An SSH server ([`openssh-server`](https://ubuntu.com/server/docs/service-openssh))\n* `curl`\n* An entrypoint script (like `docker/docker-entrypoint.sh`) that takes the public key and adds it to the authorised keys area. It should also start the SSH daemon\n\nFrom then on, whatever you do with the container is up to you (Setting up users, workspaces, dependencies, etc.)\n\nYou can remove the `Dockerfile` that is currently in the `docker/` directory and add your own, just make sure it does the same setup steps\n\nIf you have a Docker Image or a `Dockerfile` elsewhere external to this project, we use a heirarchy of values from `.env` to get which image to use, the order is from top to bottom:\n\n* `CONTAINER_ECR_REPOSITORY` - Highest priority\n* `CONTAINER_DOCKER_REPOSITORY`\n* `CONTAINER_LOCAL_PATH`\n* None of the above - uses `docker/` in this repository\n\n## The instance\n\nBy default, the project deploys a container with `0.25 vCPU` and `0.5GB RAM` - These can be altered by using `INSTANCE_CPU` and `INSTANCE_MEMORY` in your `.env` file. **NOTE**: CPU and Memory are tied, you can get more information about these mappings [here](https://docs.aws.amazon.com/cdk/api/latest/python/aws_cdk.aws_ecs/FargateTaskDefinition.html#aws_cdk.aws_ecs.FargateTaskDefinition)\n\n# Make commands\n\nA `Makefile` is provided to abstract commonly used commands away for ease of use, a breakdown of the commands is:\n\n**`make install`**\n\n\u003e This will run `npm install` and `pipenv install` on the repo root, installing only the dependencies needed for a production deployment\n\n**`make install-dev`**\n\n\u003e This will run `npm install` and `pipenv install --dev` on the repo root, installing the dependencies needed for development of this project\n\n**`make lint`**\n\n\u003e This will perform a dry run of `flake8`, `isort`, and `black` and let you know what issues were found\n\n**`make format`**\n\n\u003e This will peform a run of `isort` and `black`, this **will** modify files if issues were found\n\n**`make diff`**\n\n\u003e This will run a `cdk diff` using the contents of your `.env` file\n\n**`make deploy`**\n\n\u003e This will run a `cdk deploy` using the contents of your `.env` file. The deployment is auto-approved, so **make sure** you know what you're changing with your deployment first! (Best to run `make diff` to check!)\n\n**`make destroy`**\n\n\u003e This will run a `cdk destroy` using the contents of your `.env` file. The destroy is auto-approved, so **make sure** you know what you're destroying first!\n\n**`make ssh-config`**\n\n\u003e This will generate the SSH config entry (only really useful if for some reason the Fargate instance is re-created)\n\n**`make ssh-to-instance`**\n\n\u003e This will SSH to the instance, if the values of `SSH_CONFIG_LOCATION` and `IDENTIFIER` are not present in `.env`, the default values of `./.ssh/config` and `dev` will be used respectively\n\n# References\n\n* [VS Code Remote SSH](https://code.visualstudio.com/docs/remote/ssh)\n* [9 Steps to SSH into an AWS Fargate managed container](https://medium.com/ci-t/9-steps-to-ssh-into-an-aws-fargate-managed-container-46c1d5f834e2)\n* [How do I retrieve the public IP for a fargate task using the CLI?](https://stackoverflow.com/questions/49354116/how-do-i-retrieve-the-public-ip-for-a-fargate-task-using-the-cli)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevelopmentseed%2Fremote-workstation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevelopmentseed%2Fremote-workstation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevelopmentseed%2Fremote-workstation/lists"}