|
| 1 | +--- |
| 2 | +title: Run Coder in a self-hosted homelab |
| 3 | +date: April 7, 2023 |
| 4 | +author: Marc Paquette |
| 5 | +--- |
| 6 | + |
| 7 | +# Run Coder in a self-hosted homelab |
| 8 | + |
| 9 | +I outgrew my little homelab. I have a couple of [ODROID-HC2](https://ameridroid.com/products/odroid-hc2) devices in a closet for serving files and experimenting with ARM assembly. They work great but they’re small, single board computers with matching small capacity. |
| 10 | + |
| 11 | +It was time to expand my homelab to handle my dev projects too. |
| 12 | + |
| 13 | +## My problem: I wasn't getting anywhere |
| 14 | + |
| 15 | +I was spending too much time working around my project's obstacles instead of working on them. They're spread out over several environments and places: |
| 16 | + |
| 17 | +* They run on OpenBSD, Windows, Linux, ARM, python3, browsers, and command-line tools. |
| 18 | +* I’m typing right now on an OpenBSD laptop. I sometimes use a Windows laptop. The ODROIDs are almost literally chained to my homelab closet. |
| 19 | +* I work from home, a co-work space, and sometimes other time zones. |
| 20 | + |
| 21 | +In other words, my location and the machine I use put a limit on the projects I could work on at any given time. |
| 22 | + |
| 23 | +A good solution would let me self-host my projects and work on them wherever and however I want. A better solution would also let me use an iPad for the [ultimate sofa software development rig](https://coder.com/blog/a-guide-to-writing-code-on-an-ipad). |
| 24 | + |
| 25 | +I put off fixing this because I expected to hack and contort different tools into something that might eventually approach what I wanted. The cure seemed worse than the disease. |
| 26 | + |
| 27 | +## I discovered Coder |
| 28 | + |
| 29 | +It turns out that [Coder](https://coder.com/docs/v2) is a much easier solution. Coder solves big problems for big enterprise dev teams. And I discovered that it can solve my problems: |
| 30 | + |
| 31 | +- An isolated workspace for each project, no matter the environment |
| 32 | +- Secure, remote access |
| 33 | +- Flexibility of handling cloud and on-prem workspaces |
| 34 | +- Administering all these workspaces from a single place |
| 35 | +- Easy to install |
| 36 | +- Runs on modest hardware |
| 37 | +- Bonus: [Open source](https://github.com/coder)! |
| 38 | + |
| 39 | +## First, the hardware |
| 40 | + |
| 41 | +My homelab would need more hardware. I found a used [Lenovo m92P Tiny](https://www.lenovo.com/il/en/desktops/thinkcentre/m-series-tiny/m92p) with 16 GB RAM and upgraded its spinning disk with a 1 TB SSD, all for $200. I named it "Marvin", a character from my favorite movie. |
| 42 | + |
| 43 | +I installed [Debian](https://www.debian.org/intro/why_debian) and crammed Marvin into the homelab closet. Marvin’s only connection to the outside world is an ethernet cable. |
| 44 | + |
| 45 | + |
| 46 | + |
| 47 | + |
| 48 | +## Install Docker then Coder |
| 49 | + |
| 50 | +I ssh'd into Marvin to get started. |
| 51 | + |
| 52 | +First I installed Docker, before Coder. You'll see why in two paragraphs. |
| 53 | + |
| 54 | +Instead of [Docker Desktop](https://www.docker.com/products/docker-desktop/), I installed [Docker Engine for Debian](https://docs.docker.com/engine/install/debian/) because Marvin is headless. I'm not missing out on Docker Desktop's GUI since Coder does a lot of Docker management for me. |
| 55 | + |
| 56 | +Next was Coder. Its [install script](https://coder.com/docs/v2/latest/install/install.sh) does the right thing. In Marvin’s case it detected Debian to install a `.deb` package. It also recognized Docker so it added the `coder` user to the `docker` group. |
| 57 | + |
| 58 | +```bash |
| 59 | +marc@marvin:~$ sudo curl -fsSL https://coder.com/install.sh | sh |
| 60 | +[sudo] password for marc: |
| 61 | +Debian GNU/Linux 11 (bullseye) |
| 62 | +Installing v0.18.1 of the amd64 deb package from GitHub. |
| 63 | +# Installation progress... |
| 64 | +deb package has been installed. |
| 65 | +# Info for next steps, including setting up Coder as a systemd server... |
| 66 | +marc@marvin:~$ |
| 67 | +``` |
| 68 | + |
| 69 | +I wanted to dedicate Marvin to hosting my projects, so I followed the installer's suggestion to run Coder [as a system service](https://coder.com/docs/v2/latest/admin/configure#system-packages): |
| 70 | + |
| 71 | +```bash |
| 72 | +marc@marvin:~$ sudo systemctl enable --now coder |
| 73 | +``` |
| 74 | + |
| 75 | +Accessing Coder is straightforward: |
| 76 | + |
| 77 | +- [Command line tool](https://coder.com/docs/v2/latest/cli) |
| 78 | +- Web user interface that I can access on my home network with Marvin's local IP address |
| 79 | +- Publicly accessible, encrypted tunnel based on [Tailscale](https://coder.com/docs/v2/latest/networking) |
| 80 | +- An [API](https://coder.com/docs/v2/latest/api) |
| 81 | + |
| 82 | +I got the [tunnel’s access URL](https://coder.com/docs/v2/latest/admin/configure) (and checked that Coder is up and running): |
| 83 | + |
| 84 | +```bash |
| 85 | +marc@marvin:~$ sudo journalctl -u coder.service -b |
| 86 | +# Log entries from Coder |
| 87 | +Mar 09 14:22:21 marvin coder[617]: Opening tunnel so workspaces can connect to your deployment. For production scenarios, specify an external access URL |
| 88 | +Mar 09 14:22:22 marvin coder[617]: View the Web UI: https://marvin-access-url.pit-1.try.coder.app |
| 89 | +# More log entries from Coder |
| 90 | +``` |
| 91 | + |
| 92 | +## Using Coder for the first time |
| 93 | + |
| 94 | +At this point I was able to use my laptop's browser to log in to Coder. I opened a tab with the access URL and was asked to set up an account. This account is only for Marvin's instance of Coder. |
| 95 | + |
| 96 | + |
| 97 | + |
| 98 | +Once logged in, I was ready to set up my first workspace. A Coder [workspace](https://coder.com/docs/v2/latest/workspaces) is a runnable environment that a developer, well, develops in. Each developer has their own workspace (or workspaces). |
| 99 | + |
| 100 | +A developer can connect to a workspace from their [favorite IDE](https://coder.com/docs/v2/latest/ides) and dev tools. That includes browser-based [VS Code](https://coder.com/docs/code-server/latest), [LSP](https://langserver.org/) servers, and local JetBrains or Emacs. |
| 101 | + |
| 102 | +## Create a template |
| 103 | + |
| 104 | +Before I could start a workspace, I needed to create a [template](https://coder.com/docs/v2/latest/templates). A template is the collection of settings that Coder uses to create new workspaces. You only have to set up a template once to create as many workspaces as you need from it. |
| 105 | + |
| 106 | +A Coder template is a [Terraform](https://www.terraform.io/) file. That means that a Coder workspace can be whatever you can provision with Terraform. For big dev teams, that can be as sophisticated as pods in a [Kubernetes](https://coder.com/docs/v2/latest/platforms/kubernetes) cluster. |
| 107 | + |
| 108 | +Or when an ephemeral container won't do, like when a project is more "pet" than "cattle" or the project needs fuller access to the OS and hardware, a template can provision a virtual machine with [Proxmox VE](https://github.com/bpmct/coder-templates/tree/main/proxmox-vm). This way, the developer can treat the workspace like a full computer but still manage it like any other workspace. |
| 109 | + |
| 110 | +Coder comes with a few templates out of the box. These templates include cloud computing like [Fly.io](https://coder.com/blog/remote-developer-environments-on-fly-io), Digital Ocean, Azure, Google Cloud, and AWS. |
| 111 | + |
| 112 | +For Marvin, I'd just be using Docker. |
| 113 | + |
| 114 | +For my first workspace, I wanted to keep things simple with a template that would let me self-host with Docker. I selected **Templates** then **Starter Templates**. |
| 115 | + |
| 116 | + |
| 117 | + |
| 118 | +In **Starter Templates** I selected [Develop in Docker](https://github.com/coder/coder/tree/main/examples/templates/docker). |
| 119 | + |
| 120 | + |
| 121 | + |
| 122 | +I went back to Marvin's shell to set up my template, starting with authentication: |
| 123 | + |
| 124 | +```bash |
| 125 | +marc@marvin:~$ coder login https://marvin-access-url.coder.app |
| 126 | +Open the following in your browser: |
| 127 | + |
| 128 | + https://marvin-access-url.coder.app/cli-auth |
| 129 | + |
| 130 | +> Paste your token here: |
| 131 | +> Welcome to Coder, marc! You're authenticated. |
| 132 | +``` |
| 133 | +
|
| 134 | +Then I followed the instructions to create a Docker template. This template creates a directory named `docker`: |
| 135 | +
|
| 136 | +```bash |
| 137 | +marc@marvin:~$ coder templates init |
| 138 | +# Follow instructions to choose Develop in Docker... |
| 139 | +Create your template by running: |
| 140 | +
|
| 141 | + cd ./docker && coder templates create |
| 142 | +
|
| 143 | +Examples provide a starting point and are expected to be edited! |
| 144 | +``` |
| 145 | +
|
| 146 | +This starter template uses the vanilla [Ubuntu container image](https://hub.docker.com/_/ubuntu/). Normally at this point, I would have customized the template for a project by editing the Terraform file, `main.tf`, in the `docker` directory: |
| 147 | +
|
| 148 | +```bash |
| 149 | +marc@marvin:~$ ls docker |
| 150 | +main.tf README.md |
| 151 | +``` |
| 152 | +
|
| 153 | +Next, I followed Coder's instructions to create the template: |
| 154 | + |
| 155 | +```bash |
| 156 | +marc@marvin:~$ cd ./docker && coder template create |
| 157 | +> Upload "~/docker"? (yes/no) yes |
| 158 | +# Progress info... |
| 159 | +┌────────────────────────────────┐ |
| 160 | +│ Template Preview │ |
| 161 | +├────────────────────────────────┤ |
| 162 | +│ RESOURCE │ |
| 163 | +├────────────────────────────────┤ |
| 164 | +│ docker_container.workspace │ |
| 165 | +│ └─ main (linux, amd64) │ |
| 166 | +├────────────────────────────────┤ |
| 167 | +│ docker_image.main │ |
| 168 | +├────────────────────────────────┤ |
| 169 | +│ docker_volume.home_volume │ |
| 170 | +└────────────────────────────────┘ |
| 171 | +> Confirm create? (yes/no) yes |
| 172 | +The docker template has been created at Mar 09 14:28:39! Developers can |
| 173 | +provision a workspace with this template using: |
| 174 | +
|
| 175 | + coder create --template="docker" [workspace name] |
| 176 | +
|
| 177 | +marc@marvin:~/docker$ |
| 178 | +``` |
| 179 | + |
| 180 | +There! The web interface confirmed that the template was ready to go: |
| 181 | + |
| 182 | + |
| 183 | + |
| 184 | +## Create a workspace |
| 185 | + |
| 186 | +I was then able to create a workspace from my first template. I selected **Workspaces** then **Create from template**: |
| 187 | + |
| 188 | + |
| 189 | + |
| 190 | +I filled in details about my first workspace then started it: |
| 191 | + |
| 192 | + |
| 193 | + |
| 194 | +Marvin took a couple of minutes as Coder prepared the workspace for the first time, including downloading the Docker image. After that starting the workspace would take only a few seconds. |
| 195 | + |
| 196 | +That got me my first workspace, running and ready to use! I could access it in a few ways, including [code-server](https://coder.com/docs/code-server/latest), which lets me use VS Code in the browser. |
| 197 | + |
| 198 | + |
| 199 | + |
| 200 | +Out of curiosity, I went back to Marvin's shell to confirm that Docker was running my workspace: |
| 201 | +
|
| 202 | +```bash |
| 203 | +marc@marvin:~/docker$ docker ps |
| 204 | +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES |
| 205 | +9fed4695ac59 coder-4868739b-5bc8-421c-123f-59fd8d2581ab "sh -c '#!/usr/bin/e…" 7 minutes ago Up 7 minutes coder-marc-myfirstworkspace |
| 206 | +``` |
| 207 | + |
| 208 | +## Where to go from here |
| 209 | + |
| 210 | +I can finally go places while my homelab hosts my projects. Coder's public access URL for Marvin lets me work wherever I want. And I can finally work on my projects however I want. |
| 211 | + |
| 212 | + |
| 213 | + |
| 214 | +For the next step, I'll set up some of my projects as Coder workspaces on my homelab: |
| 215 | + |
| 216 | +* Static web site generator: Create a template with [persistence](https://coder.com/docs/v2/latest/templates/resource-persistence) and add [Pelican](https://getpelican.com/) to the template's Docker image. |
| 217 | +* ARM assembly: Create a template that provisions an ODROID. |
0 commit comments