NixOS + droplet = "nixlet" π¦
a terraform module to create a nixos droplet on digitalocean. heavily inspired by elitak/nixos-infect but tuned explicitly for our tools, processes, and preferences. the goal is a quick to setup (ephemeral or long-lasting!) nixos host on digitalocean without too much headache and to provide an easy way for new developers to begin experimenting with this operating-system/platform.
- ποΈ no nix installation necessary! π only terraform and a
DIGITALOCEAN_TOKEN
! - β²οΈ deployed and ready in "under 5-microwave minutes" π.
- π·ββοΈ custom configuration is easy! π¬ (but also not required) π
- π‘ advanced droplet monitoring enabled! π½ πΈ
- π¦Ί demonstrations.
- π a safe and productive learning environment for beginners to explore.
- π developer's scratchpad.
- π¬ "clean room" for further analysis.
- π¦ ephemeral services
- tailscale node(s).
- dnscrypt-proxy2 encrypted DNS server.
- caddy web server.
- mastodon federated social network server.
- logging/tracing/event processing.
- code-server.
- github-runner/gitlab-runner
- grafana, prometheus, victoriametrics.
- factorio server
- minio s3 filestore
- jupyterhub with support for any kernel you want badly enough.
- so many more...
Configuration can live next to .tf
files, by using file()
:
module "nixlet" {
# note that every other value (besides source) is NOT required.
source = "github.com/polis-dev/nixlet.tf"
# increased droplet size to make nixlet go vroooom!
droplet_size = "s-4vcpu-8gb-intel"
# defaults to nixos-unstable, with flakes, and other sane defaults.
nixos_channel = "nixos-unstable"
# custom nixos configuration can be specified via file() like so.
nixos_config = file("${path.module}/custom.nix")
}
OR configurations can embed/inline the nix file to leverage terraform's string interpolation:
locals { domain = "example.com" }
module "nixlet" {
# note that every other value (besides source) is NOT required.
source = "github.com/polis-dev/nixlet.tf"
nixos_config = <<-NIXOS_CONFIG
{ config, lib, pkgs, ... }: {
networking.domain = "${local.domain}";
/*
add your configuration here...
*/
}
NIXOS_CONFIG
}
Then run terraform init
and then terraform plan
.
Name | Version |
---|---|
cloudinit | ~> 2.3 |
digitalocean | ~> 2.32 |
Name | Type |
---|---|
digitalocean_droplet.main | resource |
digitalocean_floating_ip.main | resource |
cloudinit_config.user_data | data source |
digitalocean_ssh_keys.all | data source |
digitalocean_vpc.main | data source |
Name | Description | Type | Default | Required |
---|---|---|---|---|
backups | enable regular digitalocean droplet backups | bool |
false |
no |
droplet_size | which digitalocean droplet size should be used? | string |
"s-1vcpu-1gb-intel" |
no |
droplet_tags | tags to apply to droplet. | list(string) |
[] |
no |
flake_config | file contents of flake.nix (if empty, default will be generated) | string |
"" |
no |
floating_ip | reserve a floating IP droplet host? | bool |
true |
no |
graceful_shutdown | allow this droplet to shutdown gracefully? | bool |
false |
no |
hostname | what name should be given to instance? | string |
"nixlet" |
no |
image | change this at your own risk. it "just works" like this... | string |
"debian-11-x64" |
no |
infect_script | file contents of infect.sh (if empty, default will be used) | string |
"" |
no |
ipv6 | enable ipv6? | bool |
true |
no |
nixos_channel | which nix channel should be used for managed hosts? | string |
"nixos-unstable" |
no |
nixos_config | file contents of custom.nix (if empty, default will be used) | string |
"" |
no |
nixos_system | n/a | string |
"x86_64-linux" |
no |
region | which digitalocean region should be used? | string |
"nyc3" |
no |
resize_disk | resize disk when resizing the droplet (permanent change) | bool |
false |
no |
ssh_key_ids | ssh key ids to grant root ssh access. does not create them. if unspecified, all currently available ssh keys will be used (within the project containing this API token). | list(number) |
[] |
no |
volume_ids | list of volumes to be mounted to the created droplet. | list(number) |
[] |
no |
vpc_name | name of the VPC to target, if "default" will be appended with -$region | string |
"default" |
no |
Name | Description |
---|---|
droplet | (augmented) droplet resource |
floating_ip | (augmented) floating_ip resource |
ipv4_address | public ipv4 address |
ipv6_address | public ipv6 address |
-
install terraform and terraform-docs.
-
clone the repository and run
./terraform.sh init
to setup providers. you can run./terraform.sh
to see available commands. -
export
DIGITALOCEAN_TOKEN=...
(directly, or via the newly created.envrc
) to set your access credentials. -
plan a deployment with
./terraform.sh plan
. -
apply the plan with
./terraform.sh apply
. allow ~5 minutes (with default config) to provision completely (or justtail -f /var/log/cloud-init-output.log
). -
ssh to your host and enjoy! clean up everything with
./terraform.sh destroy
.
"i logged into my host and its not nixos! its debian!":
well, "future self at 3am", you can read through the log output from cloud-init with less /var/log/cloud-init-output.log
. often a small syntax error or a minor typo can cause the initial build to fail. you will almost certainly want to start the provisioning process over entirely after making your correction locally; luckily with terraform thats pretty easy: ./terraform.sh apply -destroy
, then ./terraform.sh apply
to create it again.
NOTE that the documentation is automatically updated by terraform-docs.