Compare commits

..

10 commits

Author SHA1 Message Date
d482fd0694 flake file rearranging 2026-02-08 14:02:12 -03:00
6d28510dca reformat programs 2026-02-07 10:00:06 -03:00
0112637288 move common/users.nix into users/ 2026-02-07 09:49:52 -03:00
c6fbd21009 move podmand security options to podman aspect 2026-02-07 09:33:55 -03:00
d83172f487 eza uses --git by default 2026-02-07 09:31:14 -03:00
ab69b26b40 this shouldn't ever have been commited 2026-02-07 08:21:02 -03:00
4bbf14f750 terranix: import flakeModule once in flake.nix
Fixes duplicate module declaration error by importing terranix
flakeModule once at the top level instead of in each config file.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-07 08:18:49 -03:00
c7757c139f terranix: convert to self-contained flake-parts modules
Each terranix configuration now exports its own flake output as a
self-contained module. Flattened directory structure and removed
centralized terranixConfigurations.nix in favor of import-tree.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-07 08:16:58 -03:00
f8478a75eb shells: convert to self-contained flake-parts module
Move devShells.nix to shells/default.nix as a flake-parts module
and use import-tree for automatic module discovery.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-07 08:11:55 -03:00
124d414359 packages/overlays: use builtins.readDir for dynamic package discovery
Instead of manually listing packages, the overlay now reads the
packages/ directory and automatically includes all .nix files
(except overlays.nix itself) as overlay attributes.

This makes adding new packages simpler - just add the file and it
will automatically be included in the overlay.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-07 08:08:59 -03:00
30 changed files with 856 additions and 832 deletions

View file

@ -1,6 +1,8 @@
{ ... }:
{
flake.modules.nixos.common-programs = { lib, pkgs, ... }: {
flake.modules.nixos.common-programs =
{ lib, pkgs, ... }:
{
environment = {
systemPackages = with pkgs; [
### Dev Tools ###
@ -18,7 +20,7 @@
];
shellAliases = {
cat = "${lib.getExe pkgs.bat} --paging=never --style=plain";
ls = "${lib.getExe pkgs.eza} --icons --group-directories-first";
ls = "${lib.getExe pkgs.eza} --git --icons --group-directories-first";
tree = "ls --tree";
};
};

View file

@ -1,14 +1,13 @@
{ ... }:
{
flake.modules.nixos.common-security = { ... }: {
security = {
unprivilegedUsernsClone = true; # Needed for rootless podman
sudo = {
flake.modules.nixos.common-security =
{ ... }:
{
security.sudo = {
wheelNeedsPassword = false;
extraConfig = ''
Defaults lecture = never
'';
};
};
};
}

View file

@ -1,25 +0,0 @@
{ ... }:
{
flake.modules.nixos.common-users = { pkgs, ... }: {
users.users = {
user = {
isNormalUser = true;
shell = pkgs.fish;
extraGroups = [
"networkmanager"
"wheel"
];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICQPkAyy+Du9Omc2WtnUF2TV8jFAF4H6mJi2D4IZ1nzg user@himalia"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO3Y0PVpGfJHonqDS7qoCFhqzUvqGq9I9sax+F9e/5cs user@io"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL user@rotterdam"
];
hashedPassword = "$6$Pj7v/CpstyuWQQV0$cNujVDhfMBdwlGVEnnd8t71.kZPixbo0u25cd.874iaqLTH4V5fa1f98V5zGapjQCz5JyZmsR94xi00sUrntT0";
};
root = {
shell = pkgs.fish;
hashedPassword = "!";
};
};
};
}

View file

@ -6,7 +6,12 @@
modules = [
inputs.agenix.nixosModules.default
{ networking.hostName = "alexandria"; }
{ nixpkgs.overlays = [ inputs.agenix.overlays.default inputs.self.overlays.default ]; }
{
nixpkgs.overlays = [
inputs.agenix.overlays.default
inputs.self.overlays.default
];
}
# Common aspects (always included)
inputs.self.modules.nixos.common-boot
@ -19,7 +24,10 @@
inputs.self.modules.nixos.common-security
inputs.self.modules.nixos.common-services
inputs.self.modules.nixos.common-tailscale
inputs.self.modules.nixos.common-users
# User aspects
inputs.self.modules.nixos.user
inputs.self.modules.nixos.root
# Server aspects
inputs.self.modules.nixos.server-boot

View file

@ -6,7 +6,12 @@
modules = [
inputs.agenix.nixosModules.default
{ networking.hostName = "io"; }
{ nixpkgs.overlays = [ inputs.agenix.overlays.default inputs.self.overlays.default ]; }
{
nixpkgs.overlays = [
inputs.agenix.overlays.default
inputs.self.overlays.default
];
}
# Common aspects (always included)
inputs.self.modules.nixos.common-boot
@ -19,7 +24,10 @@
inputs.self.modules.nixos.common-security
inputs.self.modules.nixos.common-services
inputs.self.modules.nixos.common-tailscale
inputs.self.modules.nixos.common-users
# User aspects
inputs.self.modules.nixos.user
inputs.self.modules.nixos.root
# Desktop aspects
inputs.self.modules.nixos.desktop-boot

View file

@ -6,7 +6,12 @@
modules = [
inputs.agenix.nixosModules.default
{ networking.hostName = "rotterdam"; }
{ nixpkgs.overlays = [ inputs.agenix.overlays.default inputs.self.overlays.default ]; }
{
nixpkgs.overlays = [
inputs.agenix.overlays.default
inputs.self.overlays.default
];
}
# Common aspects (always included)
inputs.self.modules.nixos.common-boot
@ -19,7 +24,10 @@
inputs.self.modules.nixos.common-security
inputs.self.modules.nixos.common-services
inputs.self.modules.nixos.common-tailscale
inputs.self.modules.nixos.common-users
# User aspects
inputs.self.modules.nixos.user
inputs.self.modules.nixos.root
# Desktop aspects
inputs.self.modules.nixos.desktop-boot

View file

@ -6,7 +6,12 @@
modules = [
inputs.agenix.nixosModules.default
{ networking.hostName = "trantor"; }
{ nixpkgs.overlays = [ inputs.agenix.overlays.default inputs.self.overlays.default ]; }
{
nixpkgs.overlays = [
inputs.agenix.overlays.default
inputs.self.overlays.default
];
}
# Common aspects (always included)
inputs.self.modules.nixos.common-boot
@ -19,7 +24,10 @@
inputs.self.modules.nixos.common-security
inputs.self.modules.nixos.common-services
inputs.self.modules.nixos.common-tailscale
inputs.self.modules.nixos.common-users
# User aspects
inputs.self.modules.nixos.user
inputs.self.modules.nixos.root
# Server aspects
inputs.self.modules.nixos.server-boot

View file

@ -1,12 +1,21 @@
{ ... }:
{
flake.modules.nixos.podman = { config, lib, pkgs, ... }: {
flake.modules.nixos.podman =
{
config,
lib,
pkgs,
...
}:
{
virtualisation.podman = {
enable = true;
autoPrune.enable = true;
extraPackages = [ pkgs.podman-compose ];
};
security.unprivilegedUsernsClone = true; # Needed for rootless podman
systemd = {
services.podman-auto-update.enable = true;
timers.podman-auto-update.enable = true;

View file

@ -1,19 +1,17 @@
{ ... }:
{
flake.modules.nixos.programs-graphics = { pkgs, ... }: {
flake.modules.nixos.programs-graphics =
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
# Image Editing
gimp
inkscape
# CAD & 3D Modeling
plasticity
];
services.flatpak.packages = [
# Vector Graphics
"com.boxy_svg.BoxySVG"
# 3D Printing / Slicing
rec {
appId = "io.github.softfever.OrcaSlicer";
sha256 = "0hdx5sg6fknj1pfnfxvlfwb5h6y1vjr6fyajbsnjph5gkp97c6p1";

View file

@ -2,20 +2,20 @@
{
flake.modules = {
nixos.programs-media = { pkgs, ... }: {
nixos.programs-media =
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
# Audio
decibels
# Video
showtime
# Image Viewer
loupe
# Recording & Streaming
obs-studio
showtime
];
};
homeManager.programs-media = { pkgs, ... }: {
homeManager.programs-media =
{ pkgs, ... }:
{
programs.obs-studio = {
enable = true;
plugins = with pkgs.obs-studio-plugins; [

View file

@ -1,24 +1,21 @@
{ ... }:
{
flake.modules.nixos.programs-office = { pkgs, ... }: {
flake.modules.nixos.programs-office =
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
# Spelling
aspell
aspellDicts.de
aspellDicts.en
aspellDicts.en-computers
aspellDicts.pt_BR
# Document Viewing
papers
# Presentations
presenterm
# Note Taking & Drawing
rnote
];
services.flatpak.packages = [
# Office Suite
"com.collabora.Office"
];
};

View file

@ -2,20 +2,17 @@
{
flake.modules = {
nixos.programs-utilities = { pkgs, ... }: {
nixos.programs-utilities =
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
# Terminal
ghostty
# File Management
nautilus
gnome-disk-utility
# Archive Tools
p7zip
unrar
# Cloud & Remote
rclone
# System Monitoring
mission-center
nautilus
p7zip
rclone
unrar
# Desktop Integration
adwaita-icon-theme
junction
@ -26,14 +23,14 @@
];
services.flatpak.packages = [
# Flatpak Management
"com.github.tchx84.Flatseal"
# Remote Desktop
"com.rustdesk.RustDesk"
];
};
homeManager.programs-utilities = { pkgs, ... }: {
homeManager.programs-utilities =
{ pkgs, ... }:
{
programs = {
ghostty = {
enable = true;

View file

@ -1,18 +1,21 @@
{ ... }:
{
flake.modules.nixos.programs-web = { inputs, pkgs, system, ... }: {
flake.modules.nixos.programs-web =
{
inputs,
pkgs,
system,
...
}:
{
environment.systemPackages = with pkgs; [
# Browsers
inputs.zen-browser.packages."${system}".default
tor-browser
# Communication
vesktop
# Cloud & Sync
bitwarden-desktop
nextcloud-client
# Downloads
fragments
nextcloud-client
tor-browser
vesktop
];
};
}

12
aspects/users/root.nix Normal file
View file

@ -0,0 +1,12 @@
{ ... }:
{
flake.modules.nixos.root =
{ pkgs, ... }:
{
users.root = {
shell = pkgs.fish;
hashedPassword = "!";
};
};
}

View file

@ -1,10 +1,33 @@
# aspects/users/user.nix
{ inputs, ... }:
{
flake.homeConfigurations = {
flake = {
modules.nixos.user =
{ pkgs, ... }:
{
users.users.user = {
isNormalUser = true;
shell = pkgs.fish;
extraGroups = [
"networkmanager"
"wheel"
];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICQPkAyy+Du9Omc2WtnUF2TV8jFAF4H6mJi2D4IZ1nzg user@himalia"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO3Y0PVpGfJHonqDS7qoCFhqzUvqGq9I9sax+F9e/5cs user@io"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL user@rotterdam"
];
hashedPassword = "$6$Pj7v/CpstyuWQQV0$cNujVDhfMBdwlGVEnnd8t71.kZPixbo0u25cd.874iaqLTH4V5fa1f98V5zGapjQCz5JyZmsR94xi00sUrntT0";
};
};
homeConfigurations = {
"user@rotterdam" = inputs.home-manager.lib.homeManagerConfiguration {
pkgs = inputs.nixpkgs.legacyPackages.x86_64-linux;
extraSpecialArgs = { inherit inputs; hostname = "rotterdam"; };
extraSpecialArgs = {
inherit inputs;
hostname = "rotterdam";
};
modules = [
{ nixpkgs.overlays = [ inputs.self.overlays.default ]; }
@ -50,7 +73,10 @@
"user@io" = inputs.home-manager.lib.homeManagerConfiguration {
pkgs = inputs.nixpkgs.legacyPackages.x86_64-linux;
extraSpecialArgs = { inherit inputs; hostname = "io"; };
extraSpecialArgs = {
inherit inputs;
hostname = "io";
};
modules = [
{ nixpkgs.overlays = [ inputs.self.overlays.default ]; }
@ -88,4 +114,5 @@
];
};
};
};
}

View file

@ -2,58 +2,52 @@
description = "My nix hosts";
inputs = {
# nix tools
flake-parts.url = "github:hercules-ci/flake-parts";
import-tree.url = "github:vic/import-tree";
# nixos/hm
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-25.11";
home-manager = {
url = "github:nix-community/home-manager/master";
inputs.nixpkgs.follows = "nixpkgs";
};
# nixos/hm functionality modules
agenix = {
url = "github:ryantm/agenix";
inputs.nixpkgs.follows = "nixpkgs-stable";
};
disko.url = "github:nix-community/disko";
noctalia = {
url = "github:noctalia-dev/noctalia-shell";
inputs.nixpkgs.follows = "nixpkgs";
};
impermanence.url = "github:nix-community/impermanence";
nixos-cli.url = "github:nix-community/nixos-cli";
nix-flatpak.url = "github:gmodena/nix-flatpak/main";
stylix.url = "github:danth/stylix";
nixos-cli.url = "github:nix-community/nixos-cli";
nix-flatpak.url = "github:gmodena/nix-flatpak/main";
zen-browser.url = "github:0xc000022070/zen-browser-flake";
impermanence.url = "github:nix-community/impermanence";
deploy-rs.url = "github:serokell/deploy-rs";
# nixos/hm program modules
niri-flake.url = "github:sodiboo/niri-flake";
niri.url = "github:baduhai/niri/auto-center-when-space-available";
nix-ai-tools.url = "github:numtide/llm-agents.nix";
nix-index-database = {
url = "github:nix-community/nix-index-database";
inputs.nixpkgs.follows = "nixpkgs";
};
noctalia = {
url = "github:noctalia-dev/noctalia-shell";
inputs.nixpkgs.follows = "nixpkgs";
};
vicinae.url = "github:vicinaehq/vicinae";
zen-browser.url = "github:0xc000022070/zen-browser-flake";
# stand-alone tools
deploy-rs.url = "github:serokell/deploy-rs";
terranix = {
url = "github:terranix/terranix";
inputs.nixpkgs.follows = "nixpkgs";
};
nix-ai-tools.url = "github:numtide/llm-agents.nix";
vicinae.url = "github:vicinaehq/vicinae";
# others
niri.url = "github:baduhai/niri/auto-center-when-space-available";
};
outputs =
@ -61,6 +55,8 @@
let
aspectsModule = import-tree ./aspects;
packagesModule = import-tree ./packages;
shellsModule = import-tree ./shells;
terranixModule = import-tree ./terranix;
in
flake-parts.lib.mkFlake { inherit inputs; } {
systems = [
@ -70,12 +66,14 @@
imports = [
flake-parts.flakeModules.modules
] ++ aspectsModule.imports
inputs.terranix.flakeModule
]
++ aspectsModule.imports
++ packagesModule.imports
++ shellsModule.imports
++ terranixModule.imports
++ [
./deploy.nix
./devShells.nix
./terranixConfigurations.nix
];
};
}

View file

@ -1,12 +1,22 @@
{ inputs, ... }:
let
packageDir = builtins.readDir ./.;
# Filter to .nix files, excluding overlays.nix
isPackageFile = name:
name != "overlays.nix" && builtins.match ".*\\.nix$" name != null;
# Extract package name from filename (e.g., "foo-bar.nix" -> "foo-bar")
toPackageName = filename:
builtins.head (builtins.match "(.+)\\.nix$" filename);
packageNames = map toPackageName (builtins.filter isPackageFile (builtins.attrNames packageDir));
in
{
flake.overlays.default = final: prev: {
base16-schemes = inputs.self.packages.${final.system}.base16-schemes;
claude-desktop = inputs.self.packages.${final.system}.claude-desktop;
fastfetch = inputs.self.packages.${final.system}.fastfetch;
hm-cli = inputs.self.packages.${final.system}.hm-cli;
kwrite = inputs.self.packages.${final.system}.kwrite;
toggleaudiosink = inputs.self.packages.${final.system}.toggleaudiosink;
};
flake.overlays.default = final: prev:
builtins.listToAttrs (map (name: {
inherit name;
value = inputs.self.packages.${final.system}.${name};
}) packageNames);
}

89
plan.md
View file

@ -1,89 +0,0 @@
# Current structure:
```
 hosts
├──  alexandria
│ ├──  hardware-configuration.nix
│ ├──  jellyfin.nix
│ ├──  kanidm.nix
│ ├──  nextcloud.nix
│ ├──  nginx.nix
│ ├──  unbound.nix
│ └──  vaultwarden.nix
├──  io
│ ├──  boot.nix
│ ├──  disko.nix
│ ├──  hardware-configuration.nix
│ ├──  programs.nix
│ └──  services.nix
├──  modules
│ ├──  common
│ │ ├──  boot.nix
│ │ ├──  console.nix
│ │ ├──  firewall.nix
│ │ ├──  locale.nix
│ │ ├──  nix.nix
│ │ ├──  openssh.nix
│ │ ├──  programs.nix
│ │ ├──  security.nix
│ │ ├──  services.nix
│ │ ├──  tailscale.nix
│ │ └──  users.nix
│ ├──  desktop
│ │ ├──  boot.nix
│ │ ├──  desktop.nix
│ │ ├──  nix.nix
│ │ └──  services.nix
│ ├──  server
│ │ ├──  boot.nix
│ │ ├──  nix.nix
│ │ └──  tailscale.nix
│ ├──  ai.nix
│ ├──  bluetooth.nix
│ ├──  dev.nix
│ ├──  ephemeral.nix
│ ├──  fwupd.nix
│ ├──  gaming.nix
│ ├──  libvirtd.nix
│ ├──  networkmanager.nix
│ └──  podman.nix
├──  rotterdam
│ ├──  boot.nix
│ ├──  hardware-configuration.nix
│ ├──  hardware.nix
│ ├──  programs.nix
│ └──  services.nix
└──  trantor
├──  boot.nix
├──  disko.nix
├──  fail2ban.nix
├──  forgejo.nix
├──  hardware-configuration.nix
├──  networking.nix
├──  nginx.nix
├──  openssh.nix
└──  unbound.nix
 modules
└──  ephemeral.nix
 users
├──  modules
│ ├──  common
│ │ ├──  bash.nix
│ │ ├──  fish.nix
│ │ └──  hm-cli.nix
│ ├──  desktop
│ │ ├──  desktop.nix
│ │ └──  niri.nix
│ ├──  btop.nix
│ ├──  comma.nix
│ ├──  direnv.nix
│ ├──  gaming.nix
│ ├──  helix.nix
│ ├──  obs-studio.nix
│ ├──  starship.nix
│ ├──  stylix.nix
│ └──  tmux.nix
└──  user
└──  git.nix
```

113
terranix/baduhai.dev.nix Normal file
View file

@ -0,0 +1,113 @@
# Required environment variables:
# CLOUDFLARE_API_TOKEN - API token with "Edit zone DNS" permissions
# AWS_ACCESS_KEY_ID - Cloudflare R2 access key for state storage
# AWS_SECRET_ACCESS_KEY - Cloudflare R2 secret key for state storage
{ ... }:
{
perSystem =
{ pkgs, ... }:
{
terranix.terranixConfigurations.cloudflare-baduhaidev = {
terraformWrapper.package = pkgs.opentofu;
modules = [
(
{ config, lib, ... }:
let
sharedData = import ../data/services.nix;
# Enrich services with host IPs
services = map (
svc:
let
hostInfo = sharedData.hosts.${svc.host} or { };
in
svc
// {
lanIP = hostInfo.lanIP or null;
tailscaleIP = hostInfo.tailscaleIP or null;
}
) sharedData.services;
# Helper to extract subdomain from full domain (e.g., "git.baduhai.dev" -> "git")
getSubdomain = domain: lib.head (lib.splitString "." domain);
# Generate DNS records for services
# Public services point to trantor's public IP
# Private services point to their tailscale IP
mkServiceRecords = lib.listToAttrs (
lib.imap0 (
i: svc:
let
subdomain = getSubdomain svc.domain;
targetIP =
if svc.public or false then
config.data.terraform_remote_state.trantor "outputs.instance_public_ip"
else
svc.tailscaleIP;
in
{
name = "service_${toString i}";
value = {
zone_id = config.variable.zone_id.default;
name = subdomain;
type = "A";
content = targetIP;
proxied = false;
ttl = 3600;
};
}
) services
);
in
{
terraform.required_providers.cloudflare = {
source = "cloudflare/cloudflare";
version = "~> 5.0";
};
terraform.backend.s3 = {
bucket = "terraform-state";
key = "cloudflare/baduhai.dev.tfstate";
region = "auto";
endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com";
skip_credentials_validation = true;
skip_metadata_api_check = true;
skip_region_validation = true;
skip_requesting_account_id = true;
use_path_style = true;
};
variable = {
zone_id = {
default = "c63a8332fdddc4a8e5612ddc54557044";
type = "string";
};
};
data = {
terraform_remote_state.trantor = {
backend = "s3";
config = {
bucket = "terraform-state";
key = "oci/trantor.tfstate";
region = "auto";
endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com";
skip_credentials_validation = true;
skip_metadata_api_check = true;
skip_region_validation = true;
skip_requesting_account_id = true;
use_path_style = true;
};
};
};
resource.cloudflare_dns_record = mkServiceRecords;
}
)
];
};
};
}

View file

@ -1,94 +0,0 @@
# Required environment variables:
# CLOUDFLARE_API_TOKEN - API token with "Edit zone DNS" permissions
# AWS_ACCESS_KEY_ID - Cloudflare R2 access key for state storage
# AWS_SECRET_ACCESS_KEY - Cloudflare R2 secret key for state storage
{ config, lib, ... }:
let
sharedData = import ../../data/services.nix;
# Enrich services with host IPs
services = map (svc:
let hostInfo = sharedData.hosts.${svc.host} or {};
in svc // {
lanIP = hostInfo.lanIP or null;
tailscaleIP = hostInfo.tailscaleIP or null;
}
) sharedData.services;
# Helper to extract subdomain from full domain (e.g., "git.baduhai.dev" -> "git")
getSubdomain = domain: lib.head (lib.splitString "." domain);
# Generate DNS records for services
# Public services point to trantor's public IP
# Private services point to their tailscale IP
mkServiceRecords = lib.listToAttrs (
lib.imap0 (
i: svc:
let
subdomain = getSubdomain svc.domain;
targetIP =
if svc.public or false then
config.data.terraform_remote_state.trantor "outputs.instance_public_ip"
else
svc.tailscaleIP;
in
{
name = "service_${toString i}";
value = {
zone_id = config.variable.zone_id.default;
name = subdomain;
type = "A";
content = targetIP;
proxied = false;
ttl = 3600;
};
}
) services
);
in
{
terraform.required_providers.cloudflare = {
source = "cloudflare/cloudflare";
version = "~> 5.0";
};
terraform.backend.s3 = {
bucket = "terraform-state";
key = "cloudflare/baduhai.dev.tfstate";
region = "auto";
endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com";
skip_credentials_validation = true;
skip_metadata_api_check = true;
skip_region_validation = true;
skip_requesting_account_id = true;
use_path_style = true;
};
variable = {
zone_id = {
default = "c63a8332fdddc4a8e5612ddc54557044";
type = "string";
};
};
data = {
terraform_remote_state.trantor = {
backend = "s3";
config = {
bucket = "terraform-state";
key = "oci/trantor.tfstate";
region = "auto";
endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com";
skip_credentials_validation = true;
skip_metadata_api_check = true;
skip_region_validation = true;
skip_requesting_account_id = true;
use_path_style = true;
};
};
};
resource.cloudflare_dns_record = mkServiceRecords;
}

View file

@ -0,0 +1,17 @@
# Cloudflare kernelpanic.space configuration placeholder
{ ... }:
{
perSystem =
{ pkgs, ... }:
{
terranix.terranixConfigurations.cloudflare-kernelpanicspace = {
terraformWrapper.package = pkgs.opentofu;
modules = [
({ config, ... }: {
# Terraform config goes here
})
];
};
};
}

View file

@ -1,258 +0,0 @@
# Required environment variables:
# instead of OCI variables, ~/.oci/config may also be used
# OCI_TENANCY_OCID - Oracle tenancy OCID (or use TF_VAR_* to override variables)
# OCI_USER_OCID - Oracle user OCID
# OCI_FINGERPRINT - API key fingerprint
# OCI_PRIVATE_KEY_PATH - Path to OCI API private key
# AWS variables are required
# AWS_ACCESS_KEY_ID - Cloudflare R2 access key for state storage
# AWS_SECRET_ACCESS_KEY - Cloudflare R2 secret key for state storage
{ config, ... }:
{
terraform.required_providers.oci = {
source = "oracle/oci";
version = "~> 7.0";
};
provider.oci.region = "sa-saopaulo-1";
terraform.backend.s3 = {
bucket = "terraform-state";
key = "oci/trantor.tfstate";
region = "auto";
endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com";
skip_credentials_validation = true;
skip_metadata_api_check = true;
skip_region_validation = true;
skip_requesting_account_id = true;
use_path_style = true;
};
variable = {
tenancy_ocid = {
default = "ocid1.tenancy.oc1..aaaaaaaap3vfdz4piygqza6e6zqunbcuso43ddqfo3ydmpmnomidyghh7rvq";
type = "string";
};
compartment_name = {
default = "trantor";
type = "string";
};
vcn_cidr = {
default = "10.0.0.0/24";
type = "string";
};
instance_name = {
default = "trantor";
type = "string";
};
ssh_public_keys = {
default = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICQPkAyy+Du9Omc2WtnUF2TV8jFAF4H6mJi2D4IZ1nzg user@himalia"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO3Y0PVpGfJHonqDS7qoCFhqzUvqGq9I9sax+F9e/5cs user@io"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL user@rotterdam"
];
type = "list(string)";
};
};
data = {
oci_identity_availability_domains.ads = {
compartment_id = config.variable.tenancy_ocid.default;
};
oci_core_images.ubuntu_arm = {
compartment_id = config.variable.tenancy_ocid.default;
operating_system = "Canonical Ubuntu";
operating_system_version = "24.04";
shape = "VM.Standard.A1.Flex";
sort_by = "TIMECREATED";
sort_order = "DESC";
};
};
resource = {
oci_identity_compartment.trantor = {
compartment_id = config.variable.tenancy_ocid.default;
description = "trantor infrastructure compartment";
name = config.variable.compartment_name.default;
};
oci_core_vcn.vcn = {
compartment_id = config.resource.oci_identity_compartment.trantor "id";
cidr_blocks = [ config.variable.vcn_cidr.default ];
display_name = "trantor-vcn";
dns_label = "trantor";
};
oci_core_internet_gateway.ig = {
compartment_id = config.resource.oci_identity_compartment.trantor "id";
vcn_id = config.resource.oci_core_vcn.vcn "id";
display_name = "trantor-ig";
enabled = true;
};
oci_core_route_table.rt = {
compartment_id = config.resource.oci_identity_compartment.trantor "id";
vcn_id = config.resource.oci_core_vcn.vcn "id";
display_name = "trantor-rt";
route_rules = [
{
network_entity_id = config.resource.oci_core_internet_gateway.ig "id";
destination = "0.0.0.0/0";
destination_type = "CIDR_BLOCK";
}
];
};
oci_core_security_list.sl = {
compartment_id = config.resource.oci_identity_compartment.trantor "id";
vcn_id = config.resource.oci_core_vcn.vcn "id";
display_name = "trantor-sl";
egress_security_rules = [
{
destination = "0.0.0.0/0";
protocol = "all";
stateless = false;
}
];
ingress_security_rules = [
{
protocol = "6"; # TCP
source = "0.0.0.0/0";
stateless = false;
tcp_options = {
min = 22;
max = 22;
};
}
{
protocol = "6"; # TCP
source = "0.0.0.0/0";
stateless = false;
tcp_options = {
min = 80;
max = 80;
};
}
{
protocol = "6"; # TCP
source = "0.0.0.0/0";
stateless = false;
tcp_options = {
min = 443;
max = 443;
};
}
{
protocol = "6"; # TCP
source = "0.0.0.0/0";
stateless = false;
tcp_options = {
min = 25565;
max = 25565;
};
}
{
protocol = "6"; # TCP
source = "0.0.0.0/0";
stateless = false;
tcp_options = {
min = 19132;
max = 19133;
};
}
{
protocol = "17"; # UDP
source = "0.0.0.0/0";
stateless = false;
udp_options = {
min = 19132;
max = 19133;
};
}
];
};
oci_core_subnet.subnet = {
compartment_id = config.resource.oci_identity_compartment.trantor "id";
vcn_id = config.resource.oci_core_vcn.vcn "id";
cidr_block = config.variable.vcn_cidr.default;
display_name = "trantor-subnet";
dns_label = "subnet";
route_table_id = config.resource.oci_core_route_table.rt "id";
security_list_ids = [ (config.resource.oci_core_security_list.sl "id") ];
prohibit_public_ip_on_vnic = false;
};
oci_core_instance.trantor = {
availability_domain = config.data.oci_identity_availability_domains.ads "availability_domains[0].name";
compartment_id = config.resource.oci_identity_compartment.trantor "id";
display_name = config.variable.instance_name.default;
shape = "VM.Standard.A1.Flex";
shape_config = {
ocpus = 2;
memory_in_gbs = 12;
};
source_details = {
source_type = "image";
source_id = config.data.oci_core_images.ubuntu_arm "images[0].id";
boot_volume_size_in_gbs = 100;
};
create_vnic_details = {
subnet_id = config.resource.oci_core_subnet.subnet "id";
display_name = "trantor-vnic";
assign_public_ip = true;
hostname_label = config.variable.instance_name.default;
};
metadata = {
ssh_authorized_keys = builtins.concatStringsSep "\n" config.variable.ssh_public_keys.default;
};
preserve_boot_volume = false;
};
oci_budget_budget.trantor_budget = {
compartment_id = config.variable.tenancy_ocid.default;
targets = [ (config.resource.oci_identity_compartment.trantor "id") ];
amount = 1;
reset_period = "MONTHLY";
display_name = "trantor-budget";
description = "Monthly budget for trantor compartment";
target_type = "COMPARTMENT";
};
oci_budget_alert_rule.daily_spend_alert = {
budget_id = config.resource.oci_budget_budget.trantor_budget "id";
type = "ACTUAL";
threshold = 5;
threshold_type = "PERCENTAGE";
display_name = "daily-spend-alert";
recipients = "baduhai@proton.me";
description = "Alert when daily spending exceeds $0.05";
message = "Daily spending has exceeded $0.05 in the trantor compartment";
};
};
output = {
compartment_id = {
value = config.resource.oci_identity_compartment.trantor "id";
};
instance_public_ip = {
value = config.resource.oci_core_instance.trantor "public_ip";
};
};
}

57
terranix/tailnet.nix Normal file
View file

@ -0,0 +1,57 @@
# Required environment variables:
# TAILSCALE_API_KEY - Tailscale API key with appropriate permissions
# TAILSCALE_TAILNET - Your tailnet name (e.g., "user@example.com" or "example.org.github")
# AWS_ACCESS_KEY_ID - Cloudflare R2 access key for state storage
# AWS_SECRET_ACCESS_KEY - Cloudflare R2 secret key for state storage
{ ... }:
{
perSystem =
{ pkgs, ... }:
{
terranix.terranixConfigurations.tailscale-tailnet = {
terraformWrapper.package = pkgs.opentofu;
modules = [
(
{ config, ... }:
{
terraform.required_providers.tailscale = {
source = "tailscale/tailscale";
version = "~> 0.17";
};
terraform.backend.s3 = {
bucket = "terraform-state";
key = "tailscale/tailnet.tfstate";
region = "auto";
endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com";
skip_credentials_validation = true;
skip_metadata_api_check = true;
skip_region_validation = true;
skip_requesting_account_id = true;
use_path_style = true;
};
variable = {
trantor_tailscale_ip = {
default = "100.108.5.90";
type = "string";
};
};
resource = {
tailscale_dns_nameservers.global = {
nameservers = [
config.variable.trantor_tailscale_ip.default
"1.1.1.1"
"1.0.0.1"
];
};
};
}
)
];
};
};
}

View file

@ -1,43 +0,0 @@
# Required environment variables:
# TAILSCALE_API_KEY - Tailscale API key with appropriate permissions
# TAILSCALE_TAILNET - Your tailnet name (e.g., "user@example.com" or "example.org.github")
# AWS_ACCESS_KEY_ID - Cloudflare R2 access key for state storage
# AWS_SECRET_ACCESS_KEY - Cloudflare R2 secret key for state storage
{ config, ... }:
{
terraform.required_providers.tailscale = {
source = "tailscale/tailscale";
version = "~> 0.17";
};
terraform.backend.s3 = {
bucket = "terraform-state";
key = "tailscale/tailnet.tfstate";
region = "auto";
endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com";
skip_credentials_validation = true;
skip_metadata_api_check = true;
skip_region_validation = true;
skip_requesting_account_id = true;
use_path_style = true;
};
variable = {
trantor_tailscale_ip = {
default = "100.108.5.90";
type = "string";
};
};
resource = {
tailscale_dns_nameservers.global = {
nameservers = [
config.variable.trantor_tailscale_ip.default
"1.1.1.1"
"1.0.0.1"
];
};
};
}

17
terranix/terminus.nix Normal file
View file

@ -0,0 +1,17 @@
# OCI Terminus configuration placeholder
{ ... }:
{
perSystem =
{ pkgs, ... }:
{
terranix.terranixConfigurations.oci-terminus = {
terraformWrapper.package = pkgs.opentofu;
modules = [
({ config, ... }: {
# Terraform config goes here
})
];
};
};
}

272
terranix/trantor.nix Normal file
View file

@ -0,0 +1,272 @@
# Required environment variables:
# instead of OCI variables, ~/.oci/config may also be used
# OCI_TENANCY_OCID - Oracle tenancy OCID (or use TF_VAR_* to override variables)
# OCI_USER_OCID - Oracle user OCID
# OCI_FINGERPRINT - API key fingerprint
# OCI_PRIVATE_KEY_PATH - Path to OCI API private key
# AWS variables are required
# AWS_ACCESS_KEY_ID - Cloudflare R2 access key for state storage
# AWS_SECRET_ACCESS_KEY - Cloudflare R2 secret key for state storage
{ ... }:
{
perSystem =
{ pkgs, ... }:
{
terranix.terranixConfigurations.oci-trantor = {
terraformWrapper.package = pkgs.opentofu;
modules = [
(
{ config, ... }:
{
terraform.required_providers.oci = {
source = "oracle/oci";
version = "~> 7.0";
};
provider.oci.region = "sa-saopaulo-1";
terraform.backend.s3 = {
bucket = "terraform-state";
key = "oci/trantor.tfstate";
region = "auto";
endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com";
skip_credentials_validation = true;
skip_metadata_api_check = true;
skip_region_validation = true;
skip_requesting_account_id = true;
use_path_style = true;
};
variable = {
tenancy_ocid = {
default = "ocid1.tenancy.oc1..aaaaaaaap3vfdz4piygqza6e6zqunbcuso43ddqfo3ydmpmnomidyghh7rvq";
type = "string";
};
compartment_name = {
default = "trantor";
type = "string";
};
vcn_cidr = {
default = "10.0.0.0/24";
type = "string";
};
instance_name = {
default = "trantor";
type = "string";
};
ssh_public_keys = {
default = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICQPkAyy+Du9Omc2WtnUF2TV8jFAF4H6mJi2D4IZ1nzg user@himalia"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO3Y0PVpGfJHonqDS7qoCFhqzUvqGq9I9sax+F9e/5cs user@io"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL user@rotterdam"
];
type = "list(string)";
};
};
data = {
oci_identity_availability_domains.ads = {
compartment_id = config.variable.tenancy_ocid.default;
};
oci_core_images.ubuntu_arm = {
compartment_id = config.variable.tenancy_ocid.default;
operating_system = "Canonical Ubuntu";
operating_system_version = "24.04";
shape = "VM.Standard.A1.Flex";
sort_by = "TIMECREATED";
sort_order = "DESC";
};
};
resource = {
oci_identity_compartment.trantor = {
compartment_id = config.variable.tenancy_ocid.default;
description = "trantor infrastructure compartment";
name = config.variable.compartment_name.default;
};
oci_core_vcn.vcn = {
compartment_id = config.resource.oci_identity_compartment.trantor "id";
cidr_blocks = [ config.variable.vcn_cidr.default ];
display_name = "trantor-vcn";
dns_label = "trantor";
};
oci_core_internet_gateway.ig = {
compartment_id = config.resource.oci_identity_compartment.trantor "id";
vcn_id = config.resource.oci_core_vcn.vcn "id";
display_name = "trantor-ig";
enabled = true;
};
oci_core_route_table.rt = {
compartment_id = config.resource.oci_identity_compartment.trantor "id";
vcn_id = config.resource.oci_core_vcn.vcn "id";
display_name = "trantor-rt";
route_rules = [
{
network_entity_id = config.resource.oci_core_internet_gateway.ig "id";
destination = "0.0.0.0/0";
destination_type = "CIDR_BLOCK";
}
];
};
oci_core_security_list.sl = {
compartment_id = config.resource.oci_identity_compartment.trantor "id";
vcn_id = config.resource.oci_core_vcn.vcn "id";
display_name = "trantor-sl";
egress_security_rules = [
{
destination = "0.0.0.0/0";
protocol = "all";
stateless = false;
}
];
ingress_security_rules = [
{
protocol = "6"; # TCP
source = "0.0.0.0/0";
stateless = false;
tcp_options = {
min = 22;
max = 22;
};
}
{
protocol = "6"; # TCP
source = "0.0.0.0/0";
stateless = false;
tcp_options = {
min = 80;
max = 80;
};
}
{
protocol = "6"; # TCP
source = "0.0.0.0/0";
stateless = false;
tcp_options = {
min = 443;
max = 443;
};
}
{
protocol = "6"; # TCP
source = "0.0.0.0/0";
stateless = false;
tcp_options = {
min = 25565;
max = 25565;
};
}
{
protocol = "6"; # TCP
source = "0.0.0.0/0";
stateless = false;
tcp_options = {
min = 19132;
max = 19133;
};
}
{
protocol = "17"; # UDP
source = "0.0.0.0/0";
stateless = false;
udp_options = {
min = 19132;
max = 19133;
};
}
];
};
oci_core_subnet.subnet = {
compartment_id = config.resource.oci_identity_compartment.trantor "id";
vcn_id = config.resource.oci_core_vcn.vcn "id";
cidr_block = config.variable.vcn_cidr.default;
display_name = "trantor-subnet";
dns_label = "subnet";
route_table_id = config.resource.oci_core_route_table.rt "id";
security_list_ids = [ (config.resource.oci_core_security_list.sl "id") ];
prohibit_public_ip_on_vnic = false;
};
oci_core_instance.trantor = {
availability_domain = config.data.oci_identity_availability_domains.ads "availability_domains[0].name";
compartment_id = config.resource.oci_identity_compartment.trantor "id";
display_name = config.variable.instance_name.default;
shape = "VM.Standard.A1.Flex";
shape_config = {
ocpus = 2;
memory_in_gbs = 12;
};
source_details = {
source_type = "image";
source_id = config.data.oci_core_images.ubuntu_arm "images[0].id";
boot_volume_size_in_gbs = 100;
};
create_vnic_details = {
subnet_id = config.resource.oci_core_subnet.subnet "id";
display_name = "trantor-vnic";
assign_public_ip = true;
hostname_label = config.variable.instance_name.default;
};
metadata = {
ssh_authorized_keys = builtins.concatStringsSep "\n" config.variable.ssh_public_keys.default;
};
preserve_boot_volume = false;
};
oci_budget_budget.trantor_budget = {
compartment_id = config.variable.tenancy_ocid.default;
targets = [ (config.resource.oci_identity_compartment.trantor "id") ];
amount = 1;
reset_period = "MONTHLY";
display_name = "trantor-budget";
description = "Monthly budget for trantor compartment";
target_type = "COMPARTMENT";
};
oci_budget_alert_rule.daily_spend_alert = {
budget_id = config.resource.oci_budget_budget.trantor_budget "id";
type = "ACTUAL";
threshold = 5;
threshold_type = "PERCENTAGE";
display_name = "daily-spend-alert";
recipients = "baduhai@proton.me";
description = "Alert when daily spending exceeds $0.05";
message = "Daily spending has exceeded $0.05 in the trantor compartment";
};
};
output = {
compartment_id = {
value = config.resource.oci_identity_compartment.trantor "id";
};
instance_public_ip = {
value = config.resource.oci_core_instance.trantor "public_ip";
};
};
}
)
];
};
};
}

View file

@ -1,27 +0,0 @@
{ inputs, ... }:
{
imports = [
inputs.terranix.flakeModule
];
perSystem =
{ pkgs, ... }:
{
terranix.terranixConfigurations = {
oci-trantor = {
modules = [ ./terranix/oci/trantor.nix ];
terraformWrapper.package = pkgs.opentofu;
};
cloudflare-baduhaidev = {
modules = [ ./terranix/cloudflare/baduhai.dev.nix ];
terraformWrapper.package = pkgs.opentofu;
};
tailscale-tailnet = {
modules = [ ./terranix/tailscale/tailnet.nix ];
terraformWrapper.package = pkgs.opentofu;
};
};
};
}