-
Notifications
You must be signed in to change notification settings - Fork 86
Add Hetzner Cloud server template example #560
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+317
−0
Merged
Changes from 14 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
3fb4a54
Add Hetzner Cloud server template example
Excellencedev 4449570
Merge branch 'main' into fix-209
Excellencedev efe7db9
Merge branch 'main' into fix-209
Excellencedev d78ca6d
Merge branch 'main' into fix-209
Excellencedev 5d84815
Merge branch 'main' into fix-209
Excellencedev a7af83e
Merge branch 'main' into fix-209
Excellencedev 1470852
Merge branch 'main' into fix-209
Excellencedev 71f4f5d
Merge branch 'main' into fix-209
Excellencedev 25d863d
Merge branch 'main' into fix-209
Excellencedev 9bb0523
Merge branch 'main' into fix-209
Excellencedev 5dfb99c
Fix formatting
Excellencedev edec1cc
Merge branch 'main' into fix-209
Excellencedev 0f2de13
Remove comment and satisfy CI
Excellencedev aa22d7e
Change avatar to .png
Excellencedev 470af24
Update registry/Excellencedev/templates/hetzner-linux/cloud-config.ya…
Excellencedev 2a99b0b
Merge branch 'main' into fix-209
DevelopmentCats 3bb021e
Add GFM Alert Warning
Excellencedev 1eba36b
Merge branch 'main' into fix-209
DevelopmentCats File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| --- | ||
| display_name: "Excellencedev" | ||
| bio: "Love to contribute" | ||
| avatar: "./.images/avatar.png" | ||
| support_email: "[email protected]" | ||
| status: "community" | ||
| --- |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| --- | ||
| display_name: Hetzner Cloud Server | ||
| description: Provision Hetzner Cloud servers as Coder workspaces | ||
| icon: ../../../../.icons/hetzner.svg | ||
| tags: [vm, linux, hetzner] | ||
| --- | ||
|
|
||
| # Remote Development on Hetzner Cloud (Linux) | ||
|
|
||
| Provision Hetzner Cloud servers as [Coder workspaces](https://coder.com/docs/workspaces) with this example template. | ||
|
|
||
| > [!IMPORTANT] | ||
| > **Volume Management & Costs:** Hetzner Cloud volumes persist even when workspaces are stopped and will continue to incur storage costs (€0.0476/GB/month). Volumes are only automatically deleted when the workspace is completely deleted. Monitor your volumes in the [Hetzner Cloud Console](https://console.hetzner.cloud/) to manage costs effectively. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| To deploy workspaces as Hetzner Cloud servers, you'll need: | ||
|
|
||
| - Hetzner Cloud [API token](https://console.hetzner.cloud/projects) (create under Security > API Tokens) | ||
|
|
||
| ### Authentication | ||
|
|
||
| This template assumes that the Coder Provisioner is run in an environment that is authenticated with Hetzner Cloud. | ||
|
|
||
| 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. | ||
| For more authentication options, see the [Terraform provider documentation](https://registry.terraform.io/providers/hetznercloud/hcloud/latest/docs#authentication). | ||
|
|
||
| > [!NOTE] | ||
| > This template is designed to be a starting point. Edit the Terraform to extend the template to support your use case. |
62 changes: 62 additions & 0 deletions
62
registry/Excellencedev/templates/hetzner-linux/cloud-config.yaml.tftpl
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| #cloud-config | ||
| users: | ||
| - name: ${username} | ||
| sudo: ["ALL=(ALL) NOPASSWD:ALL"] | ||
| groups: sudo | ||
| shell: /bin/bash | ||
| packages: | ||
| - git | ||
| %{ if home_volume_label != "" ~} | ||
| fs_setup: | ||
| - device: /dev/disk/by-id/scsi-0HC_Volume_${volume_id} | ||
| filesystem: ext4 | ||
| label: ${home_volume_label} | ||
| overwrite: false # This prevents reformatting the disk on every boot | ||
|
|
||
| mounts: | ||
| - [ | ||
| "/dev/disk/by-id/scsi-0HC_Volume_${volume_id}", | ||
| "/home/${username}", | ||
| auto, | ||
| "defaults,uid=1000,gid=1000", | ||
| ] | ||
| %{ endif ~} | ||
| write_files: | ||
| - path: /opt/coder/init | ||
| permissions: "0755" | ||
| encoding: b64 | ||
| content: ${init_script} | ||
| - path: /etc/systemd/system/coder-agent.service | ||
| permissions: "0644" | ||
| content: | | ||
| [Unit] | ||
| Description=Coder Agent | ||
| After=network-online.target | ||
| Wants=network-online.target | ||
|
|
||
| [Service] | ||
| User=${username} | ||
| ExecStart=/opt/coder/init | ||
| Environment=CODER_AGENT_TOKEN=${coder_agent_token} | ||
| Restart=always | ||
| RestartSec=10 | ||
| TimeoutStopSec=90 | ||
| KillMode=process | ||
|
|
||
| OOMScoreAdjust=-900 | ||
| SyslogIdentifier=coder-agent | ||
|
|
||
| [Install] | ||
| WantedBy=multi-user.target | ||
| runcmd: | ||
| %{ if home_volume_label != "" ~} | ||
| - | | ||
| until [ -e /dev/disk/by-id/scsi-0HC_Volume_${volume_id} ]; do | ||
| echo "Waiting for volume device..." | ||
| sleep 2 | ||
| done | ||
| %{ endif ~} | ||
| - mount -a | ||
| - chown ${username}:${username} /home/${username} | ||
| - systemctl enable coder-agent | ||
| - systemctl start coder-agent | ||
27 changes: 27 additions & 0 deletions
27
registry/Excellencedev/templates/hetzner-linux/hetzner_server_types.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| { | ||
| "type_meta": { | ||
| "cx22": { "cores": 2, "memory_gb": 4, "disk_gb": 40 }, | ||
| "cx32": { "cores": 4, "memory_gb": 8, "disk_gb": 80 }, | ||
| "cx42": { "cores": 8, "memory_gb": 16, "disk_gb": 160 }, | ||
| "cx52": { "cores": 16, "memory_gb": 32, "disk_gb": 320 }, | ||
| "cpx11": { "cores": 2, "memory_gb": 2, "disk_gb": 40 }, | ||
| "cpx21": { "cores": 3, "memory_gb": 4, "disk_gb": 80 }, | ||
| "cpx31": { "cores": 4, "memory_gb": 8, "disk_gb": 160 }, | ||
| "cpx41": { "cores": 8, "memory_gb": 16, "disk_gb": 240 }, | ||
| "cpx51": { "cores": 16, "memory_gb": 32, "disk_gb": 360 }, | ||
| "ccx13": { "cores": 2, "memory_gb": 8, "disk_gb": 80 }, | ||
| "ccx23": { "cores": 4, "memory_gb": 16, "disk_gb": 160 }, | ||
| "ccx33": { "cores": 8, "memory_gb": 32, "disk_gb": 240 }, | ||
| "ccx43": { "cores": 16, "memory_gb": 64, "disk_gb": 360 }, | ||
| "ccx53": { "cores": 32, "memory_gb": 128, "disk_gb": 600 }, | ||
| "ccx63": { "cores": 48, "memory_gb": 192, "disk_gb": 960 } | ||
| }, | ||
| "availability": { | ||
| "fsn1": ["cpx11", "cpx21", "cpx31", "cpx41", "cpx51", "ccx13", "ccx23", "ccx33"], | ||
| "ash": ["cpx11", "cpx21", "cpx31", "cpx41", "cpx51", "ccx13", "ccx23", "ccx33"], | ||
| "hel1": ["cx22", "cpx11", "cpx21", "cpx31", "cpx41", "cpx51", "ccx13", "ccx23", "ccx33"], | ||
| "hil": ["cpx11", "cpx21", "cpx31", "cpx41", "ccx13", "ccx23", "ccx33"], | ||
| "nbg1": ["cx22", "cx32", "cx42", "cx52", "cpx11", "cpx21", "cpx31", "cpx41", "cpx51", "ccx13", "ccx23", "ccx33"], | ||
| "sin": ["cpx11", "cpx21", "cpx31", "cpx41", "cpx51", "ccx13", "ccx23", "ccx33"] | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,183 @@ | ||
| terraform { | ||
| required_providers { | ||
| hcloud = { | ||
| source = "hetznercloud/hcloud" | ||
| } | ||
| coder = { | ||
| source = "coder/coder" | ||
| } | ||
| } | ||
| } | ||
|
|
||
| variable "hcloud_token" { | ||
| sensitive = true | ||
| } | ||
|
|
||
| provider "hcloud" { | ||
| token = var.hcloud_token | ||
| } | ||
|
|
||
| # Available locations: https://docs.hetzner.com/cloud/general/locations/ | ||
| data "coder_parameter" "hcloud_location" { | ||
| name = "hcloud_location" | ||
| display_name = "Hetzner Location" | ||
| description = "Select the Hetzner Cloud location for your workspace." | ||
| type = "string" | ||
| default = "fsn1" | ||
| option { | ||
| name = "DE Falkenstein" | ||
| value = "fsn1" | ||
| } | ||
| option { | ||
| name = "US Ashburn, VA" | ||
| value = "ash" | ||
| } | ||
| option { | ||
| name = "US Hillsboro, OR" | ||
| value = "hil" | ||
| } | ||
| option { | ||
| name = "SG Singapore" | ||
| value = "sin" | ||
| } | ||
| option { | ||
| name = "DE Nuremberg" | ||
| value = "nbg1" | ||
| } | ||
| option { | ||
| name = "FI Helsinki" | ||
| value = "hel1" | ||
| } | ||
| } | ||
|
|
||
| # Available server types: https://docs.hetzner.com/cloud/servers/overview/ | ||
| data "coder_parameter" "hcloud_server_type" { | ||
| name = "hcloud_server_type" | ||
| display_name = "Hetzner Server Type" | ||
| description = "Select the Hetzner Cloud server type for your workspace." | ||
| type = "string" | ||
|
|
||
| dynamic "option" { | ||
| for_each = local.hcloud_server_type_options_for_selected_location | ||
| content { | ||
| name = option.value.name | ||
| value = option.value.value | ||
| } | ||
| } | ||
| } | ||
|
|
||
| resource "hcloud_server" "dev" { | ||
| count = data.coder_workspace.me.start_count | ||
| name = "coder-${data.coder_workspace.me.name}-dev" | ||
| image = "ubuntu-24.04" | ||
| server_type = data.coder_parameter.hcloud_server_type.value | ||
| location = data.coder_parameter.hcloud_location.value | ||
| public_net { | ||
| ipv4_enabled = true | ||
| ipv6_enabled = true | ||
| } | ||
| user_data = templatefile("cloud-config.yaml.tftpl", { | ||
| username = lower(data.coder_workspace_owner.me.name) | ||
| home_volume_label = "coder-${data.coder_workspace.me.id}-home" | ||
| volume_id = hcloud_volume.home_volume.id | ||
| init_script = base64encode(coder_agent.main.init_script) | ||
| coder_agent_token = coder_agent.main.token | ||
| }) | ||
| labels = { | ||
| "coder_workspace_name" = data.coder_workspace.me.name, | ||
| "coder_workspace_owner" = data.coder_workspace_owner.me.name, | ||
| } | ||
| } | ||
|
|
||
| resource "hcloud_volume" "home_volume" { | ||
| name = "coder-${data.coder_workspace.me.id}-home" | ||
| size = data.coder_parameter.home_volume_size.value | ||
| location = data.coder_parameter.hcloud_location.value | ||
| labels = { | ||
| "coder_workspace_name" = data.coder_workspace.me.name, | ||
| "coder_workspace_owner" = data.coder_workspace_owner.me.name, | ||
| } | ||
| } | ||
|
|
||
| resource "hcloud_volume_attachment" "home_volume_attachment" { | ||
| count = data.coder_workspace.me.start_count | ||
| volume_id = hcloud_volume.home_volume.id | ||
| server_id = hcloud_server.dev[count.index].id | ||
| automount = false | ||
| } | ||
|
|
||
| locals { | ||
| username = lower(data.coder_workspace_owner.me.name) | ||
|
|
||
| # Data source: local JSON file under the module directory | ||
| # Check API for latest server types & availability: https://docs.hetzner.cloud/reference/cloud#server-types | ||
| hcloud_server_types_data = jsondecode(file("${path.module}/hetzner_server_types.json")) | ||
| hcloud_server_type_meta = local.hcloud_server_types_data.type_meta | ||
| hcloud_server_types_by_location = local.hcloud_server_types_data.availability | ||
|
|
||
| hcloud_server_type_options_for_selected_location = [ | ||
| for type_name in lookup(local.hcloud_server_types_by_location, data.coder_parameter.hcloud_location.value, []) : { | ||
| name = format("%s (%d vCPU, %dGB RAM, %dGB)", upper(type_name), local.hcloud_server_type_meta[type_name].cores, local.hcloud_server_type_meta[type_name].memory_gb, local.hcloud_server_type_meta[type_name].disk_gb) | ||
| value = type_name | ||
| } | ||
| ] | ||
| } | ||
|
|
||
| data "coder_provisioner" "me" {} | ||
|
|
||
| provider "coder" {} | ||
|
|
||
| data "coder_workspace" "me" {} | ||
|
|
||
| data "coder_workspace_owner" "me" {} | ||
|
|
||
| data "coder_parameter" "home_volume_size" { | ||
| name = "home_volume_size" | ||
| display_name = "Home volume size" | ||
| description = "How large would you like your home volume to be (in GB)?" | ||
| type = "number" | ||
| default = "20" | ||
| mutable = false | ||
| validation { | ||
| min = 1 | ||
| max = 100 # Adjust the max size as needed | ||
| } | ||
| } | ||
|
|
||
| resource "coder_agent" "main" { | ||
| os = "linux" | ||
| arch = "amd64" | ||
|
|
||
| metadata { | ||
| key = "cpu" | ||
| display_name = "CPU Usage" | ||
| interval = 5 | ||
| timeout = 5 | ||
| script = "coder stat cpu" | ||
| } | ||
| metadata { | ||
| key = "memory" | ||
| display_name = "Memory Usage" | ||
| interval = 5 | ||
| timeout = 5 | ||
| script = "coder stat mem" | ||
| } | ||
| metadata { | ||
| key = "home" | ||
| display_name = "Home Usage" | ||
| interval = 600 # every 10 minutes | ||
| timeout = 30 # df can take a while on large filesystems | ||
| script = "coder stat disk --path /home/${local.username}" | ||
| } | ||
| } | ||
|
|
||
| module "code-server" { | ||
| count = data.coder_workspace.me.start_count | ||
| source = "registry.coder.com/coder/code-server/coder" | ||
|
|
||
| # 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. | ||
| version = "~> 1.0" | ||
|
|
||
| agent_id = coder_agent.main.id | ||
| order = 1 | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.