Unified flake module: DNS and nginx vhost
It is possible to combine multiple infrastructure-as-code domains.
This example consists of a flake-parts module that combines a deSEC.io DNS record via the community-provided Valodim/terraform-provider-desec provider, and an importable NixOS module that configures the matching nginx virtualhost. The webserver will have a virtualhost rule corresponding to the DNS entry, preventing drift.
The entrypoint is a flake:
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
terranix.url = "github:terranix/terranix";
};
outputs = inputs@{ flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
imports = [
inputs.terranix.flakeModule
./modules/sites.nix
];
systems = [ "x86_64-linux" ];
sites.www = {
subname = "www";
domain = "example.dedyn.io";
ipv4 = "203.0.113.42";
};
};
}It mentions a custom configuration option, sites.<name> defined in the following module:
{ lib, config, ... }:
let
cfg = config.sites;
in
{
options.sites = lib.mkOption {
default = { };
type = lib.types.attrsOf (lib.types.submodule {
options = {
subname = lib.mkOption { type = lib.types.str; };
domain = lib.mkOption { type = lib.types.str; };
ipv4 = lib.mkOption { type = lib.types.str; };
};
});
};
config = {
# terranix configuration: one per site, deSEC DNS A record.
perSystem = { ... }: {
terranix.terranixConfigurations = lib.mapAttrs (name: site: {
modules = [{
terraform.required_providers.desec.source = "Valodim/desec";
variable.desec_token.sensitive = true;
provider.desec.api_token = "\${var.desec_token}";
resource.desec_rrset.${name} = {
domain = site.domain;
subname = site.subname;
type = "A";
ttl = 3600;
records = [ site.ipv4 ];
};
}];
}) cfg;
};
# NixOS module: importable from any nixosSystem, configures nginx.
flake.nixosModules = lib.mapAttrs (name: site: { ... }: {
services.nginx = {
enable = true;
virtualHosts."${site.subname}.${site.domain}" = {
enableACME = true;
forceSSL = true;
locations."/".return = ''200 "hello from ${site.subname}.${site.domain}\n"'';
};
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
}) cfg;
};
}Use it #
Provision the DNS record (the deSEC token is read from the environment):
$ export TF_VAR_desec_token="…"
$ nix run .#wwwImport the matching NixOS module into the host that should serve the site:
{ inputs, ... }: {
imports = [ inputs.self.nixosModules.www ];
}Adding a second site is two more lines in flake.nix:
sites.api = {
subname = "api";
domain = "example.dedyn.io";
ipv4 = "203.0.113.42";
};Both nix run .#api and inputs.self.nixosModules.api appear automatically.
Their deployment is still handled as two separate steps.
info
The Valodim/desec provider is not on the public Terraform registry; consult
the provider README for installing it (Nix users typically pin
it via terraform-providers overrides or a local plugin cache).