Hands-on: No-install browser-based VSCode commandline

Photo by Umar Farooq / Unsplash

This page contains materials for my thing on giving a whole bunch of testers a working dev env in their browsers. We'll be on Zoom.

It's good for people who teach at conferences.

You're going to end up with: a web address that opens a development environment in anyone's browser, containing your repo and more.

I can't give you ownership of my web address, of my Cloudflare account, or of my Digital Ocean account. So you're going to need to bring those if you want to follow along. Or you can watch, and we can talk.

Info for the workshop

You'll use the following environment to run ansible: not yet

Repo for ansible tools

Repo for env

It won't

  • Run desktop apps. Won't run mobile, either. It's a commandline that happens to have VSCode in a browser window.
  • Give your participants copilot. They can install VSCode's continue extension and bring their own key.

Setup / Scavenger hunt

To be hands-on, you'll need to spend time and money (not a lot of either). You don't need all of these things, but the more you have the more you can do this for yourself.

You need to get:

  • A web address that you control to let you change the Domain Name Servers, and to be legitimately yours when we set up https.
  • A (free) CloudFlare account to let the script point your web address at your server
    • A CloudFlare API key
    • Your web address needs to have its Domain Name Servers managed by CloudFlare
    • (you can buy one through CloudFlare)
  • A Digital Ocean account to let the script set up a server
    • A digital ocean key
    • A credit card on file (servers aren't free)
  • A git repo – preferably with a requirements.txt (Python) or a package.json (JavsScript) to list dependencies
  • A machine running Ansible (JL can supply – and yes, it's in the cloud)

Steps

We'll set up an up-to-date server – then store an image

  • set up a server from a base ubuntu image
  • update packages
  • install basics – curl, wget, git, python, pip, node, npm, ngnix
  • tidy up and make a snapshot

We'll use the image to make one (or more) servers

  • make a droplet from the snapshot image
  • set up CloudFlare and Let's Encrypt to allow HTTPS
  • create the user accounts and Nginx for each
  • install code-server, python, flask,
  • clone the repo

About secrets

note to self: lost this... too frustrated to reknit.

The scripts are set up to use a secrets.yml file.

Secrets file content

```

do_api_key: no_key

claude_key: no_key (unused?_

cloudflare_api_token: no_token

certbot_email: no_emalil

envs_anthropic: no_key

envs_openai: no_key

```

When

ansible.cfg says to expect the password to the secrets file in vault_pass.txt. You might want to put that somewhere that's NOT in the repo.

Using a password manager: 1password

As it happens, I keep the password to the secrets file in a password manager, 1Password. So all my interactions with ansible use this parameter: --vault-password-file <(op item get 'Ansible secrets' --fields label=password --reveal).

That overrides references to the password for the secrets file with the field password from the 1Password item Ansible secrets . In practice: I use the command, verify with a fingerprint, and off it goes.

About the scripts

There are two key Ansible scripts:

  • droplet_only_setup.yml – sets up one droplet, gets everything up-to-date, makes a snapshot
  • user_setup_and_info.yml – uses a snapshot as the basis for a multi-user code-server setup.

You run and ansible playbook with: ansible-playbook user_setup_and_info.yml – but it's not quite as simple as that.

First, the playbooks use secrets files. If you use ansible-playbook user_setup_and_info.yml, it will look for vault_pass.txt, where it expects to find your secrets password. That is as set up in ansible.cfg.

As it happens, I don't like to put the password to my secrets into a plaintext file, wherever it is, so I use a password manager: 1password. The following picks up the password from a field password in the Ansible secrets item in 1password, and asks for my fingertip to get the info. Easy!

ansible-playbook -e "group_name=7july" user_setup_and_info.yml --vault-password-file <(op item get 'Ansible secrets' --fields label=password --reveal)

The extra parameter -e "group_name=7july" overrides the group_name in /vars/main.yml. group_name is used for the subdomain of the web address, and is also used for the LLM keys. So if I've got 5 tables, I can give each table a group_name

They take in parameters

They use tasks

  • certificate_tasks.yml - Installs certbot, creates Cloudflare credentials, and obtains/renews Let's Encrypt SSL certificates using DNS challenge.
  • clone_adjust_and_commit.yml - Clones the Git repository for each user, sets proper ownership and permissions, and commits any changes locally.
  • cloudflare_work.yml - Checks and configures Cloudflare DNS A records, then waits for DNS propagation to complete.
  • create_user_and_landing.yml - Creates user accounts with sudo access and generates personalized HTML landing pages for each user.
  • digital_ocean_work.yml - Manages DigitalOcean droplet creation from snapshots, including checking for existing droplets and waiting for network assignment.
  • setup_code_server.yml - Installs and configures code-server for each user with custom settings, systemd services, and VS Code preferences.
  • setup_flask.yml - Creates Python virtual environments, installs Flask dependencies, and sets up systemd services for Flask applications.
  • setup_git.yml - Configures Git user settings and creates global gitignore files for each user account.
  • setup_js_dependencies.yml - Installs Node.js/npm system packages and runs npm install for JavaScript dependencies in web directories.
  • setup_llm_tool.yml - Creates Python virtual environments with LLM tools, configures API keys, and sets up prompt templates for AI assistance.
  • setup_nginx_base.yml - Checks for and installs nginx if not present, waiting for system updates to complete first.
  • setup_nginx_for_multiple_users.yml - Configures nginx proxy locations for multiple users and removes the default nginx site.
  • setup_python.yml - Installs Python development packages including venv, pip, pytest, and coverage tools.

Here are templates, and where they're used.

  • access_info.txt.j2 - Used in generate_access_info at the end of the playbook to make a .txt file of access information (connection details and credentials). That file is not used directly, but acts as a record.
  • code-server-config.yaml.j2 - used in setup_code_server to build code-server's .yaml config file.
  • code-server.service.j2 - used in setup_code_server to make a Systemd .service file for running code-server as a system service.
  • flask-app.service.j2 - used in setup_flask to set up the Systemd .service file for running a flask application as a system service.
  • llm_config.yaml.j2 - used in setup_llm_tool to make llm's .yaml config file (check this – using an old key!!)
  • nginx.conf.j2 - used in droplet_only_setup for very basic Nginx config.
  • nginx_ssl.conf.j2 - used in certificate_tasks for Nginx config – routing HTTP traffic to HTTPS, and setting up ssl for HTTPS.
  • root_landing.html.j2 - used in create_user_and_landing for the domain landing .html page.
  • settings.json.j2 - used in setup_code_server to make VS Code/code-server's settings configuration file (i.e. editor preferences and extensions).
  • user_landing.html.j2 - used in `create_user_and_landing` for each user's .html page with personalised content and links.
  • user_proxy_locations.conf.j2 - used in setup_nginx_for_multiple_users as a Nginx location block template for user-specific proxy configurations and routing.

Ansible

Digital Ocean

CloudFlare

Let's Encrypt

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.