Skip to content

Commit 8c92754

Browse files
committed
feat: add Hetzner Cloud server template and configuration files
1 parent cf66809 commit 8c92754

File tree

7 files changed

+275
-0
lines changed

7 files changed

+275
-0
lines changed

.github/typos.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
muc = "muc" # For Munich location code
33
Hashi = "Hashi"
44
HashiCorp = "HashiCorp"
5+
hel = "hel" # For Helsinki location code
56

67
[files]
78
extend-exclude = ["registry/coder/templates/aws-devcontainer/architecture.svg"] #False positive

.icons/hetzner.svg

Lines changed: 5 additions & 0 deletions
Loading

registry/brymut/.images/avatar.png

30.6 KB
Loading

registry/brymut/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
display_name: brymut (Bryan Mutai)
3+
bio: Independent software developer based in Kenya, passionate about DevOps and Cloud Native solutions. Combining expert automation and scalability with a strong commitment to the community. Explore collaboration and drive success together.
4+
avatar: ./.images/avatar.png
5+
github: brymut
6+
support_email: mutaiwork@gmail.com
7+
status: community
8+
---
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
display_name: Hetzner Cloud Server
3+
description: Provision Hetzner Cloud servers as Coder workspaces
4+
icon: ../../../../.icons/hetzner.svg
5+
tags: [vm, linux, hetzner]
6+
---
7+
8+
# Remote Development on Hetzner Cloud (Linux)
9+
10+
Provision Hetzner Cloud servers as [Coder workspaces](https://coder.com/docs/workspaces) with this example template.
11+
12+
## Prerequisites
13+
14+
To deploy workspaces as Hetzner Cloud servers, you'll need:
15+
16+
- Hetzner Cloud [API token](https://console.hetzner.cloud/projects) (create under Security > API Tokens)
17+
18+
### Authentication
19+
20+
This template assumes that the Coder Provisioner is run in an environment that is authenticated with Hetzner Cloud.
21+
22+
Obtain a Hetzner Cloud API token from your [Hetzner Cloud Console](https://console.hetzner.cloud/projects) and provide it as the `hcloud_token` variable when creating a workspace.
23+
For more authentication options, see the [Terraform provider documentation](https://registry.terraform.io/providers/hetznercloud/hcloud/latest/docs#authentication).
24+
25+
> [!NOTE]
26+
> This template is designed to be a starting point. Edit the Terraform to extend the template to support your use case.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#cloud-config
2+
users:
3+
- name: ${username}
4+
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
5+
groups: sudo
6+
shell: /bin/bash
7+
packages:
8+
- git
9+
mounts:
10+
- [
11+
"LABEL=${home_volume_label}",
12+
"/home/${username}",
13+
auto,
14+
"defaults,uid=1000,gid=1000",
15+
]
16+
write_files:
17+
- path: /opt/coder/init
18+
permissions: "0755"
19+
encoding: b64
20+
content: ${init_script}
21+
- path: /etc/systemd/system/coder-agent.service
22+
permissions: "0644"
23+
content: |
24+
[Unit]
25+
Description=Coder Agent
26+
After=network-online.target
27+
Wants=network-online.target
28+
29+
[Service]
30+
User=${username}
31+
ExecStart=/opt/coder/init
32+
Environment=CODER_AGENT_TOKEN=${coder_agent_token}
33+
Restart=always
34+
RestartSec=10
35+
TimeoutStopSec=90
36+
KillMode=process
37+
38+
OOMScoreAdjust=-900
39+
SyslogIdentifier=coder-agent
40+
41+
[Install]
42+
WantedBy=multi-user.target
43+
runcmd:
44+
- chown ${username}:${username} /home/${username}
45+
- systemctl enable coder-agent
46+
- systemctl start coder-agent
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
terraform {
2+
required_providers {
3+
hcloud = {
4+
source = "hetznercloud/hcloud"
5+
}
6+
coder = {
7+
source = "coder/coder"
8+
}
9+
}
10+
}
11+
12+
variable "hcloud_token" {
13+
sensitive = true
14+
}
15+
16+
provider "hcloud" {
17+
token = var.hcloud_token
18+
}
19+
20+
# Available locations: https://docs.hetzner.com/cloud/general/locations/
21+
data "coder_parameter" "hcloud_location" {
22+
name = "hcloud_location"
23+
display_name = "Hetzner Location"
24+
description = "Select the Hetzner Cloud location for your workspace."
25+
type = "string"
26+
default = "fsn1"
27+
option {
28+
name = "DE Falkenstein"
29+
value = "fsn1"
30+
}
31+
option {
32+
name = "US Ashburn, VA"
33+
value = "ash"
34+
}
35+
option {
36+
name = "US Hillsboro, OR"
37+
value = "hil"
38+
}
39+
option {
40+
name = "SG Singapore"
41+
value = "sin"
42+
}
43+
option {
44+
name = "DE Nuremberg"
45+
value = "nbg1"
46+
}
47+
option {
48+
name = "FI Helsinki"
49+
value = "hel1"
50+
}
51+
}
52+
53+
# Available server types: https://docs.hetzner.com/cloud/servers/overview/
54+
data "coder_parameter" "hcloud_server_type" {
55+
name = "hcloud_server_type"
56+
display_name = "Hetzner Server Type"
57+
description = "Select the Hetzner Cloud server type for your workspace."
58+
type = "string"
59+
default = "cx22"
60+
option {
61+
name = "CX22 (2 vCPU, 4GB RAM, 40GB, $3.99/mo)"
62+
value = "cx22"
63+
}
64+
option {
65+
name = "CPX11 (2 vCPU, 2GB RAM, 40GB, $4.49/mo)"
66+
value = "cpx11"
67+
}
68+
option {
69+
name = "CX32 (4 vCPU, 8GB RAM, 80GB, $6.99/mo)"
70+
value = "cx32"
71+
}
72+
option {
73+
name = "CPX21 (3 vCPU, 4GB RAM, 80GB, $7.99/mo)"
74+
value = "cpx21"
75+
}
76+
option {
77+
name = "CPX31 (4 vCPU, 8GB RAM, 160GB, $14.99/mo)"
78+
value = "cpx31"
79+
}
80+
option {
81+
name = "CX42 (8 vCPU, 16GB RAM, 160GB, $17.99/mo)"
82+
value = "cx42"
83+
}
84+
option {
85+
name = "CPX41 (8 vCPU, 16GB RAM, 240GB, $27.49/mo)"
86+
value = "cpx41"
87+
}
88+
option {
89+
name = "CX52 (16 vCPU, 32GB RAM, 320GB, $35.49/mo)"
90+
value = "cx52"
91+
}
92+
option {
93+
name = "CPX51 (16 vCPU, 32GB RAM, 360GB, $60.49/mo)"
94+
value = "cpx51"
95+
}
96+
}
97+
98+
resource "hcloud_server" "dev" {
99+
name = "dev"
100+
image = "ubuntu-24.04"
101+
server_type = data.coder_parameter.hcloud_server_type.value
102+
location = data.coder_parameter.hcloud_location.value
103+
public_net {
104+
ipv4_enabled = true
105+
ipv6_enabled = true
106+
}
107+
user_data = templatefile("cloud-config.yaml.tftpl", {
108+
username = lower(data.coder_workspace_owner.me.name)
109+
home_volume_label = hcloud_volume.home_volume.name
110+
init_script = base64encode(coder_agent.main.init_script)
111+
coder_agent_token = coder_agent.main.token
112+
})
113+
}
114+
115+
resource "hcloud_volume" "home_volume" {
116+
name = "coder-${data.coder_workspace.me.id}-home"
117+
size = data.coder_parameter.home_volume_size.value
118+
location = data.coder_parameter.hcloud_location.value
119+
format = "ext4"
120+
delete_protection = true
121+
}
122+
123+
resource "hcloud_volume_attachment" "home_volume_attachment" {
124+
volume_id = hcloud_volume.home_volume.id
125+
server_id = hcloud_server.dev.id
126+
}
127+
128+
locals {
129+
username = lower(data.coder_workspace_owner.me.name)
130+
}
131+
132+
data "coder_provisioner" "me" {}
133+
134+
provider "coder" {}
135+
136+
data "coder_workspace" "me" {}
137+
138+
data "coder_workspace_owner" "me" {}
139+
140+
data "coder_parameter" "home_volume_size" {
141+
name = "home_volume_size"
142+
display_name = "Home volume size"
143+
description = "How large would you like your home volume to be (in GB)?"
144+
type = "number"
145+
default = "20"
146+
mutable = false
147+
validation {
148+
min = 1
149+
max = 100 # Adjust the max size as needed
150+
}
151+
}
152+
153+
resource "coder_agent" "main" {
154+
os = "linux"
155+
arch = "amd64"
156+
157+
metadata {
158+
key = "cpu"
159+
display_name = "CPU Usage"
160+
interval = 5
161+
timeout = 5
162+
script = "coder stat cpu"
163+
}
164+
metadata {
165+
key = "memory"
166+
display_name = "Memory Usage"
167+
interval = 5
168+
timeout = 5
169+
script = "coder stat mem"
170+
}
171+
metadata {
172+
key = "home"
173+
display_name = "Home Usage"
174+
interval = 600 # every 10 minutes
175+
timeout = 30 # df can take a while on large filesystems
176+
script = "coder stat disk --path /home/${local.username}"
177+
}
178+
}
179+
180+
module "code-server" {
181+
count = data.coder_workspace.me.start_count
182+
source = "registry.coder.com/coder/code-server/coder"
183+
184+
# This ensures that the latest non-breaking version of the module gets downloaded, you can also pin the module version to prevent breaking changes in production.
185+
version = "~> 1.0"
186+
187+
agent_id = coder_agent.main.id
188+
order = 1
189+
}

0 commit comments

Comments
 (0)