Curtis McEnroe

Chromebook as a Thin Client for Development

After handing in my MacBook Pro at the end of my last job, I needed a new setup to code on. I had an old Lenovo IdeaPad that I had repurposed as a home server. I also had an HP Chromebook 11 that I hadn’t used much in a while.

I spent a bit of time trying to make the Lenovo usable as a “desktop” again, but I found it was too much work to configure an environment minimal enough for my tastes. Instead, I slid it back on the shelf and started exploring other options. What I’ve settled on for now is a stack of OpenVPN, SSH and tmux.

Chrome Secure Shell

The built-in crosh shell of Chrome OS includes an SSH client, but it is very tedious to make connections with, since it requires entering the user, host, and SSH key every time.

Luckily, there is a Chrome app named Secure Shell, which exposes a much nicer interface. It saves connection information and remembers your SSH keys, although you still have to generate them beforehand. It is still in beta, but the only thing that seems to be missing is a more usable settings page.

Generating Keys

Generating SSH keys for Secure Shell works much the same way as usual:

ssh-keygen -t rsa -C 'comment' -f chromebook.id_rsa

This will write the private key to chromebook.id_rsa and the public key to

I then served these files over local HTTP and downloaded them on my Chromebook. They can then be imported from the Secure Shell connection dialog.


Secure Shell works great, but the default colour scheme isn’t exactly pretty to look at. Since there isn’t much of a settings interface, you have to enter a JSON object in the color-pallete-overrides field. I based mine on the Gruvbox Generalized XResources file:

  "0": "#282828", "8":  "#928374",
  "1": "#cc241d", "9":  "#fb4934",
  "2": "#98971a", "10": "#b8bb26",
  "3": "#d79921", "11": "#fadb2f",
  "4": "#458588", "12": "#83a598",
  "5": "#b16286", "13": "#d3869b",
  "6": "#689d6a", "14": "#8ec07c",
  "7": "#a89984", "15": "#ebdbb2"

I also set background-color to #1d2021 (hard contrast), and foreground-color and cursor-color both to #ebdbb2.

Dynamic DNS

In order to easily access my home server from anywhere, I need a domain pointing to my home connection. The Arch Wiki lists many options for Dynamic DNS. I use CloudFlare for my domains, so I use wimpunk’s ddclient fork (AUR), which has support for CloudFlare and other services.

The relevant part of my ddclient configuration (/etc/ddclient/ddclient.conf) looks like this:

protocol=cloudflare, \, \, \
login=redacted, \
password=redacted, \

Note that it was necessary to manually create an A record for before ddclient could update it.

On Arch, it is then as simple as enabling and starting ddclient I found a guide for creating .onc files for OpenVPN connections, which covers creation pretty well. with systemd:

sudo systemctl enable ddclient
sudo systemctl start ddclient

OpenVPN Server

In order to access my home server securely from anywhere, I decided to set up a VPN using OpenVPN. Arch Wiki has an excellent page page on OpenVPN, with thorough setup instructions.

I did, however, run into one problem with the server configuration. When connecting to the VPN from my Chromebook on another wifi connection, the DNS configuration would break. I fixed this by having the server send DNS configuration to the client explicitly, using this option in /etc/openvpn/server.conf:

push "dhcp-option DNS"

Chrome OS & OpenVPN

Although the Chrome OS “Private Network” interface in Settings supports OpenVPN, it does not support using an HMAC secret key (ta.key), which greatly enhances security.

There is also a misinterpretation of the OpenVPN protocol on the part of Chrome OS, which causes breakage when not tunneling all traffic through the VPN. A flag needs to be used, which is not available from the interface, to prevent this behaviour.

As an alternative to the interface, Chrome OS supports “Open Network Config” files (.onc) in JSON format, which can be imported through chrome://net-internals/#chromeos. I found a guide for importing certificates and creating and importing .onc files for OpenVPN.

I would suggest using the uuidgen command line utility (from util-linux) to generate UUIDs.

The other, more important change, is the addition of the IgnoreDefaultRoute flag. This prevents the buggy behaviour mentioned above.

In the end, my home.onc file ended up looking like this:

  "Type": "UnencryptedConfiguration",
  "Certificates": [
      "GUID": "{0fac9c63-a364-407a-b680-5525b19437ab}",
      "Type": "Authority",
      "X509": "redacted"
  "NetworkConfigurations": [
      "GUID": "{c3be34ff-94f5-43cb-bc42-99d19a0ae307}",
      "Name": "Home",
      "Type": "VPN",
      "VPN": {
        "Type": "OpenVPN",
        "Host": "",
        "OpenVPN": {
          "ServerCARef": "{0fac9c63-a364-407a-b680-5525b19437ab}",
          "AuthRetry": "interact",
          "ClientCertType": "Pattern",
          "ClientCertPattern": {
            "IssuerCARef": ["{0fac9c63-a364-407a-b680-5525b19437ab}"]
          "CompLZO": true,
          "Port": 1194,
          "Proto": "udp",
          "RemoteCertTLS": "server",
          "RemoteCertEKU": "TLS Web Server Authentication",
          "SaveCredentials": true,
          "ServerPollTimeout": 10,
          "Username": "curtis",
          "KeyDirection": 1,
          "IgnoreDefaultRoute": true,
          "TLSAuthContents": "redacted"

After importing this .onc file, I could select the “Home” private connection from the interface. When prompted, I entered a fake password and checked “Save identity and password”. To check that I was properly connected, I used Secure Shell to SSH to I also made sure I could connect to everything else as normal.


I had never used tmux before, but it quickly became clear that it is an invaluable tool when doing work over SSH. I created a configuration that very closely mimics VIM window management, which can be found in my dotfiles repository.

I also wrote some shell functions for quickly getting into tmux:

tn() { [ -n "$1" ] && tmux new -s "$1" || tmux new }
ta() { [ -n "$1" ] && tmux attach -t "$1" || tmux attach }

End Result

Here is me editing this post on my Chromebook, with OpenVPN, SSH, tmux, VIM and zsh:


Bonus: OpenVPN & iPhone

I also wanted to be able to SSH into my home server from my phone if I ever needed to. I use the ServerAuditor SSH client on iOS. It can generate its own keys and export them.

For VPN, there is the OpenVPN Connect app. This app uses .ovpn files for client configuration. These files are just regular OpenVPN .conf files with a different extension. The only complicated part of creating one is adding the certificates and keys inline, using HTML-like tags. After generating a new certificate for my phone, my .ovpn file looked like this:

dev tun
proto udp
remote 1194
resolv-retry infinite



remote-cert-tls server

key-direction 1
-----BEGIN OpenVPN Static key V1-----
-----END OpenVPN Static key V1-----


I then imported the .ovpn by emailing it to myself and opening it in OpenVPN Connect from the Mail app.

This is what the end result looks like on iPhone: