Compare commits

..

117 commits

Author SHA1 Message Date
1dc55be5e1 flake.lock: Update
Flake lock file updates:

• Updated input 'nix-ai-tools':
    'github:numtide/nix-ai-tools/58d5d222d6802a75c1ed637d049ea438d199051a?narHash=sha256-pQ2XzsB/n8E5FWYnICZu/BzkKy8a50EzmUGTCo5SeHg%3D' (2025-11-13)
  → 'github:numtide/nix-ai-tools/a2dfa932ed37e5b6224b39b4982c85cd8ebcca14?narHash=sha256-n6bChFrCf2/uHzTsZdABUt1%2BUa3n0jinNfamHd5DmBA%3D' (2025-11-17)
• Updated input 'nix-ai-tools/blueprint':
    'github:numtide/blueprint/633af1961cae8e02bc6195e6e599a6b09bf75217?narHash=sha256-wTQzbbQ6XHtvNJVuhJj%2BytZDRyNtwUKbrIfIvMvKNfQ%3D' (2025-10-28)
  → 'github:numtide/blueprint/5a9bba070f801d63e2af3c9ef00b86b212429f4f?narHash=sha256-O9Y%2BWer8wOh%2BN%2B4kcCK5p/VLrXyX%2Bktk0/s3HdZvJzk%3D' (2025-11-16)
• Updated input 'nix-ai-tools/nixpkgs':
    'github:NixOS/nixpkgs/9da7f1cf7f8a6e2a7cb3001b048546c92a8258b4?narHash=sha256-SlybxLZ1/e4T2lb1czEtWVzDCVSTvk9WLwGhmxFmBxI%3D' (2025-11-11)
  → 'github:NixOS/nixpkgs/85a6c4a07faa12aaccd81b36ba9bfc2bec974fa1?narHash=sha256-3YJkOBrFpmcusnh7i8GXXEyh7qZG/8F5z5%2B717550Hk%3D' (2025-11-16)
2025-11-18 19:09:57 -03:00
eebacb0f1f add power profiles daemon to io 2025-11-13 19:16:39 -03:00
0925a66f22 flake.lock: Update
Flake lock file updates:

• Updated input 'nix-ai-tools':
    'github:numtide/nix-ai-tools/aaee8f2df1325c7f212d769515092162bcac31a7?narHash=sha256-aWt5CgOsQiiq%2BcaxF0iqp56kfHRkv8Tnz0X9DhJeBEE%3D' (2025-11-06)
  → 'github:numtide/nix-ai-tools/58d5d222d6802a75c1ed637d049ea438d199051a?narHash=sha256-pQ2XzsB/n8E5FWYnICZu/BzkKy8a50EzmUGTCo5SeHg%3D' (2025-11-13)
• Updated input 'nix-ai-tools/nixpkgs':
    'github:NixOS/nixpkgs/b3d51a0365f6695e7dd5cdf3e180604530ed33b4?narHash=sha256-4vhDuZ7OZaZmKKrnDpxLZZpGIJvAeMtK6FKLJYUtAdw%3D' (2025-11-02)
  → 'github:NixOS/nixpkgs/9da7f1cf7f8a6e2a7cb3001b048546c92a8258b4?narHash=sha256-SlybxLZ1/e4T2lb1czEtWVzDCVSTvk9WLwGhmxFmBxI%3D' (2025-11-11)
• Updated input 'nix-ai-tools/treefmt-nix':
    'github:numtide/treefmt-nix/97a30861b13c3731a84e09405414398fbf3e109f?narHash=sha256-aF5fvoZeoXNPxT0bejFUBXeUjXfHLSL7g%2BmjR/p5TEg%3D' (2025-11-06)
  → 'github:numtide/treefmt-nix/5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4?narHash=sha256-AlEObg0syDl%2BSpi4LsZIBrjw%2BsnSVU4T8MOeuZJUJjM%3D' (2025-11-12)
2025-11-13 14:26:35 -03:00
489af5a79f new noctalia ipc command 2025-11-10 11:46:54 -03:00
e95ba0215b new ssh key for himalia 2025-11-10 11:04:55 -03:00
b602a78bb3 vicinae as a launcher 2025-11-10 07:52:47 -03:00
bb0ea27696 niri keybinds 2025-11-09 19:01:37 -03:00
ae6d46012b fail2ban: fix config; forgejo: repository path and persistency 2025-11-09 18:31:46 -03:00
5906fa6f36 fix forgejo's ssh domain 2025-11-09 16:31:52 -03:00
5af6c53d81 Update readme.md 2025-11-09 16:28:17 -03:00
09a4092b92 better noctalia integration for niri 2025-11-09 13:56:57 -03:00
3d71b8c1b8 update readme.md 2025-11-09 13:41:41 -03:00
0961eb8f76 dns records only for actual services 2025-11-09 13:37:04 -03:00
f979314a3c new readme 2025-11-09 13:31:27 -03:00
f1b6be6f3f Add fail2ban configuration for SSH and Forgejo on Trantor
- Configure fail2ban with progressive ban times (1h base, up to 10000h max)
- Add SSH jail with password authentication disabled
- Add Forgejo jail using systemd journal backend
- Ignore private networks and Tailscale IPs
- Set Forgejo to 10 retries per hour, 15min initial ban

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 13:00:17 -03:00
cd17bf2561 only forgejo is public for now 2025-11-09 12:36:43 -03:00
ad9d565a8f Route DNS based on service visibility flags
Replace wildcard DNS with dynamic service-based routing that reads
from shared/services.nix. Public services (forgejo, vaultwarden,
nextcloud) point to trantor's public IP for external access, while
private services (kanidm, jellyfin) point to tailscale IPs for
internal-only access. This provides granular control over service
exposure without manual DNS management.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 11:20:21 -03:00
878c4aa3ea Add public visibility flags to service definitions
Mark services as public or private to control external access:
- Public: vaultwarden, forgejo, nextcloud
- Private: kanidm, jellyfin

This enables proper routing and firewall configuration based on
intended service visibility.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 11:12:06 -03:00
6f1aca7b01 Configure Forgejo OAuth2 and disable public registration
Add OAuth2 client configuration to enable auto-registration via SSO
with Kanidm, while disabling direct public registration. Users can now
authenticate through the identity provider with automatic account
creation and avatar syncing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 11:11:55 -03:00
14c4440dd1 forgejo: disable singup; document root password 2025-11-09 10:34:57 -03:00
1921aad1bd Update Cloudflare DNS configuration with explicit zone ID
Replace sensitive zone_id variable with hardcoded value and update
DNS record configuration to use cloudflare_dns_record resource type.
Disable proxying and set explicit TTL for better control over DNS
propagation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 10:30:02 -03:00
1b1d7896e6 Document required environment variables for OCI configuration
Add documentation about required OCI and AWS credentials for the
trantor configuration, clarifying that ~/.oci/config can be used
as an alternative to environment variables.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 10:29:54 -03:00
808bccf0a2 Add Tailscale tailnet DNS configuration via Terranix
Configure global DNS nameservers for the Tailscale tailnet, setting
trantor as the primary DNS server with Cloudflare as fallback. This
enables custom DNS resolution across the entire tailnet.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 10:29:45 -03:00
92f5593611 junction default browser; remove brave 2025-11-09 07:55:42 -03:00
095d881ad9 no ghostty notifications 2025-11-09 07:51:15 -03:00
258bcac597 Integrate Kanidm with Nextcloud via OIDC
Added Kanidm identity provider integration with Nextcloud:
- Enabled Kanidm client in kanidm.nix for CLI access
- Added user_oidc app to Nextcloud for OpenID Connect authentication
- Configured allow_local_remote_servers to permit Nextcloud to reach
  Kanidm at auth.baduhai.dev (resolves to local IP 192.168.15.142)

OAuth2 client configuration (done via kanidm CLI):
- Client ID: nextcloud
- Scopes: openid, email, profile mapped to idm_all_accounts group
- Redirect URI: https://cloud.baduhai.dev/apps/user_oidc/code
- User mapping: name claim maps to Nextcloud username

This allows users to authenticate to Nextcloud using their Kanidm
credentials, with existing Nextcloud accounts linked via username.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 23:56:40 -03:00
58fec03579 Switch ACME to DNS-01 challenge with auto-configured certificates
Changed certificate generation from HTTP-01 to DNS-01 challenge to support
services behind Tailscale/CGNAT IPs. HTTP-01 challenges fail because Let's
Encrypt cannot reach private Tailscale IPs (100.x.x.x) that Cloudflare DNS
points to.

Changes:
- Pre-configure certificates in security.acme.certs using DNS-01 via Cloudflare
- Auto-generate certificate configs from shared/services.nix
  - Alexandria: filters services with host == "alexandria"
  - Trantor: filters services with host == "trantor"
- Updated mkNginxVHosts to use useACMEHost instead of enableACME
- Each domain gets its own certificate configured with DNS-01 challenge

This ensures all services get valid Let's Encrypt certificates even when
accessible only through Tailscale or private networks.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 22:53:18 -03:00
952a55f03d Add Kanidm identity provider to alexandria
Added Kanidm server configuration to serve as central identity provider for
all services. Configuration includes:
- Server on auth.baduhai.dev with HTTPS
- LDAP support on port 636 for legacy integrations
- Nginx reverse proxy with SSL termination
- Added to shared services for DNS resolution

Kanidm will provide OAuth2/OIDC authentication for Nextcloud, Vaultwarden,
Forgejo, and other services.
2025-11-08 22:24:37 -03:00
73db534269 Switch from wildcard to per-domain SSL certificates
Updated mkNginxVHosts to use per-domain certificates (enableACME) instead
of shared wildcard certificates (useACMEHost). Each service now requests
its own certificate, avoiding conflicts between hosts and following the
principle of least privilege.

Removed wildcard certificate configuration from both alexandria and trantor.
Each host now only obtains certificates for domains it actually serves:
- Alexandria: pass.baduhai.dev, cloud.baduhai.dev, jellyfin.baduhai.dev
- Trantor: git.baduhai.dev
2025-11-08 21:47:41 -03:00
34622a05cb Move forgejo from alexandria to trantor
Migrated forgejo service and configuration to trantor. Added nginx reverse
proxy support on trantor with ACME configuration for SSL certificates.

Fixed vaultwarden domain in shared services from vault.baduhai.dev to
pass.baduhai.dev to match actual nginx configuration.
2025-11-08 21:47:16 -03:00
ee1a7c4d18 Split DNS servers: alexandria for LAN, trantor for tailnet
Alexandria's unbound now only serves LAN clients (192.168.0.0/16) and
returns LAN IPs for service domains.

Created new unbound instance on trantor to serve Tailscale clients
(100.64.0.0/10) and return tailscale IPs for service domains.

Both configurations pull service records from shared/services.nix.
2025-11-08 21:35:53 -03:00
8d8847e2fb Remove split DNS module and per-service entries
Removed the split-dns.nix module and all service-specific splitDNS.entries
configurations. Service DNS records are now sourced from the centralized
shared/services.nix file instead of being declared individually in each
service configuration.
2025-11-08 21:35:33 -03:00
af444584d0 Add shared services infrastructure for cross-host data
Created centralized service definitions in shared/services.nix to store
service metadata (domains, IPs, ports) that need to be accessible across
multiple hosts. This replaces the per-service split DNS module approach
with a single source of truth.

Services are now exported through utils.nix for easy access in host configs.
2025-11-08 21:35:13 -03:00
2289f0e6e4 beginnings of split dns 2025-11-08 20:47:21 -03:00
a1369e5818 rekeyd secrets 2025-11-08 20:46:38 -03:00
52eaf14b09 noto emoji font name change; niri window/workspace up/down keybind 2025-11-08 13:02:22 -03:00
5baff5a68e added kanshi to manage displays 2025-11-07 12:13:47 -03:00
d3ef56c724 add presenterm to desktops 2025-11-07 11:55:27 -03:00
45f89a1663 add claude-code back 2025-11-07 07:15:12 -03:00
59cda1884d add recipient to oci alert 2025-11-07 06:17:28 -03:00
6ec815a766 fix disko usage for io 2025-11-06 19:59:58 -03:00
cb59a911d6 added ai tag for desktop hosts 2025-11-06 19:57:04 -03:00
97450f0057 no more protonup 2025-11-04 08:13:16 -03:00
d6f582fffd no diskoConfirations outputs 2025-11-03 22:03:02 -03:00
f5f1541aec fixing trantor 2025-11-03 17:19:21 -03:00
4622f2b299 fix trantor disko config 2025-11-03 16:42:18 -03:00
fe091504d0 openssh greeting fixes 2025-11-03 14:46:37 -03:00
447778eb46 flake.lock: Update
Flake lock file updates:

• Updated input 'agenix':
    'github:ryantm/agenix/2f0f812f69f3eb4140157fe15e12739adf82e32a?narHash=sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L%2BVSybPfiIgzU8lbQ%3D' (2025-10-19)
  → 'github:ryantm/agenix/9ba0d85de3eaa7afeab493fed622008b6e4924f5?narHash=sha256-lsNWuj4Z%2BpE7s0bd2OKicOFq9bK86JE0ZGeKJbNqb94%3D' (2025-10-28)
• Updated input 'disko/nixpkgs':
    'github:NixOS/nixpkgs/a7fc11be66bdfb5cdde611ee5ce381c183da8386?narHash=sha256-QoJjGd4NstnyOG4mm4KXF%2BweBzA2AH/7gn1Pmpfcb0A%3D' (2025-10-31)
  → 'github:NixOS/nixpkgs/dab3a6e781554f965bde3def0aa2fda4eb8f1708?narHash=sha256-lFNVsu/mHLq3q11MuGkMhUUoSXEdQjCHvpReaGP1S2k%3D' (2025-07-15)
• Updated input 'flake-parts':
    'github:hercules-ci/flake-parts/864599284fc7c0ba6357ed89ed5e2cd5040f0c04?narHash=sha256-TmWcdiUUaWk8J4lpjzu4gCGxWY6/Ok7mOK4fIFfBuU4%3D' (2025-10-20)
  → 'github:hercules-ci/flake-parts/0010412d62a25d959151790968765a70c436598b?narHash=sha256-z5PlZ47j50VNF3R%2BIMS9LmzI5fYRGY/Z5O5tol1c9I4%3D' (2025-11-01)
• Updated input 'flake-parts/nixpkgs-lib':
    'github:nix-community/nixpkgs.lib/a73b9c743612e4244d865a2fdee11865283c04e6?narHash=sha256-x2rJ%2BOvzq0sCMpgfgGaaqgBSwY%2BLST%2BWbZ6TytnT9Rk%3D' (2025-08-10)
  → 'github:nix-community/nixpkgs.lib/719359f4562934ae99f5443f20aa06c2ffff91fc?narHash=sha256-b0yj6kfvO8ApcSE%2BQmA6mUfu8IYG6/uU28OFn4PaC8M%3D' (2025-10-29)
• Updated input 'home-manager':
    'github:nix-community/home-manager/189c21cf879669008ccf06e78a553f17e88d8ef0?narHash=sha256-nZh6uvc71nVNaf/y%2BwesnjwsmJ6IZZUnP2EzpZe48To%3D' (2025-10-20)
  → 'github:nix-community/home-manager/8c824254b1ed9e797f6235fc3c62f365893c561a?narHash=sha256-I%2B8yE5HVR2SFcHnW0771psQ/zn0qVzsKHY/gUM0nEVM%3D' (2025-11-03)
• Updated input 'niri-flake':
    'github:sodiboo/niri-flake/f851a923137c0a54719412146fd63d24b3214e60?narHash=sha256-E2ySTu/oK7cYBdAI3tlGP9zVjF4mZgWJ1OZInBCMb00%3D' (2025-10-20)
  → 'github:sodiboo/niri-flake/df17789929ac80f4157b15724450db6a303a6dc9?narHash=sha256-U3SDbk7tIwLChpvb3FL66o8V0byaQ2RGMiy/3oLdxTI%3D' (2025-11-03)
• Updated input 'niri-flake/niri-unstable':
    'github:YaLTeR/niri/b3245b81a6ed8edfaf5388a74d2e0a23c24941e5?narHash=sha256-KbM47vD6E0cx%2Bv4jYQZ8mD5N186AKm2CQlyh34TW58U%3D' (2025-10-20)
  → 'github:YaLTeR/niri/a2ca2b3c866bc781b12c334a9f949b3db6d7c943?narHash=sha256-anRlNG6t7esBbF1%2BALDeathVBSclA0PEL52Vo0WnN5g%3D' (2025-11-03)
• Updated input 'niri-flake/nixpkgs':
    'github:NixOS/nixpkgs/5e2a59a5b1a82f89f2c7e598302a9cacebb72a67?narHash=sha256-K5Osef2qexezUfs0alLvZ7nQFTGS9DL2oTVsIXsqLgs%3D' (2025-10-19)
  → 'github:NixOS/nixpkgs/2fb006b87f04c4d3bdf08cfdbc7fab9c13d94a15?narHash=sha256-kJ8lIZsiPOmbkJypG%2BB5sReDXSD1KGu2VEPNqhRa/ew%3D' (2025-10-31)
• Updated input 'niri-flake/nixpkgs-stable':
    'github:NixOS/nixpkgs/33c6dca0c0cb31d6addcd34e90a63ad61826b28c?narHash=sha256-PXwG0TM7Ek87DNx4LbGWuD93PbFeKAJs4FfALtp7Wo0%3D' (2025-10-19)
  → 'github:NixOS/nixpkgs/3de8f8d73e35724bf9abef41f1bdbedda1e14a31?narHash=sha256-IYlYnp4O4dzEpL77BD/lj5NnJy2J8qbHkNSFiPBCbqo%3D' (2025-11-01)
• Updated input 'niri-flake/xwayland-satellite-unstable':
    'github:Supreeeme/xwayland-satellite/a9188e70bd748118b4d56a529871b9de5adb9988?narHash=sha256-0pkftKs6/LReNvxw7DVTN2AJEheZVgyeK0Aarbagi70%3D' (2025-10-05)
  → 'github:Supreeeme/xwayland-satellite/0728d59ff6463a502e001fb090f6eb92dbc04756?narHash=sha256-fBrUszJXmB4MY%2Bwf3QsCnqWHcz7u7fLq0QMAWCltIQg%3D' (2025-10-28)
• Updated input 'nix-index-database':
    'github:nix-community/nix-index-database/5024e1901239a76b7bf94a4cd27f3507e639d49e?narHash=sha256-xmU8kAsRprJiTGBTaGrwmjBP3AMA9ltlrxHKFuy5JWc%3D' (2025-10-19)
  → 'github:nix-community/nix-index-database/359ff6333a7b0b60819d4c20ed05a3a1f726771f?narHash=sha256-Pu1v3mlFhRzZiSxVHb2/i/f5yeYyRNqr0RvEUJ4UgHo%3D' (2025-11-02)
• Updated input 'nixos-cli':
    'github:nix-community/nixos-cli/c8f5ce1fd9bf151df74328795b6b2720e2e22d75?narHash=sha256-N%2BF4n1WYE3AWc/kmdqIz67GNX7PgyKosnmGYYx8vR9k%3D' (2025-10-19)
  → 'github:nix-community/nixos-cli/5c259f72ae1eaa00b99354d81130d8fddb7f9a7a?narHash=sha256-IUm2nkbKlDkG94ruTmIYLERpBn6gXydm3scZIKzpcKs%3D' (2025-11-01)
• Updated input 'nixos-cli/flake-compat':
    'github:edolstra/flake-compat/9100a0f413b0c601e0533d1d94ffd501ce2e7885?narHash=sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX%2BfjA8Xf8PUmqCY%3D' (2025-05-12)
  → 'github:edolstra/flake-compat/f387cd2afec9419c8ee37694406ca490c3f34ee5?narHash=sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4%3D' (2025-10-27)
• Updated input 'nixos-cli/nixpkgs':
    'github:NixOS/nixpkgs/647e5c14cbd5067f44ac86b74f014962df460840?narHash=sha256-JVZl8NaVRYb0%2B381nl7LvPE%2BA774/dRpif01FKLrYFQ%3D' (2025-09-28)
  → 'github:NixOS/nixpkgs/a7fc11be66bdfb5cdde611ee5ce381c183da8386?narHash=sha256-QoJjGd4NstnyOG4mm4KXF%2BweBzA2AH/7gn1Pmpfcb0A%3D' (2025-10-31)
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/5e2a59a5b1a82f89f2c7e598302a9cacebb72a67?narHash=sha256-K5Osef2qexezUfs0alLvZ7nQFTGS9DL2oTVsIXsqLgs%3D' (2025-10-19)
  → 'github:nixos/nixpkgs/2fb006b87f04c4d3bdf08cfdbc7fab9c13d94a15?narHash=sha256-kJ8lIZsiPOmbkJypG%2BB5sReDXSD1KGu2VEPNqhRa/ew%3D' (2025-10-31)
• Updated input 'nixpkgs-stable':
    'github:nixos/nixpkgs/33c6dca0c0cb31d6addcd34e90a63ad61826b28c?narHash=sha256-PXwG0TM7Ek87DNx4LbGWuD93PbFeKAJs4FfALtp7Wo0%3D' (2025-10-19)
  → 'github:nixos/nixpkgs/3de8f8d73e35724bf9abef41f1bdbedda1e14a31?narHash=sha256-IYlYnp4O4dzEpL77BD/lj5NnJy2J8qbHkNSFiPBCbqo%3D' (2025-11-01)
• Updated input 'noctalia':
    'github:noctalia-dev/noctalia-shell/c3439b262c7cb3d57c93197a93a3aa382582bdae?narHash=sha256-XAs/Q4zBJIfK/bwq9KjTUkTH15A%2BPe2rIilyvalEHuM%3D' (2025-10-23)
  → 'github:noctalia-dev/noctalia-shell/5ca5aa602f58a8e0e73fedbef351f1cdf8cbe981?narHash=sha256-gHfzrTDSnNC5yRJwkZfP55fPHUc8DuB4OQEIBSQSs18%3D' (2025-11-03)
• Updated input 'noctalia/quickshell':
    'git+https://git.outfoxxed.me/outfoxxed/quickshell?ref=refs/heads/master&rev=a5431dd02dc23d9ef1680e67777fed00fe5f7cda' (2025-07-27)
  → 'git+https://git.outfoxxed.me/outfoxxed/quickshell?ref=refs/heads/master&rev=db1777c20b936a86528c1095cbcb1ebd92801402' (2025-10-30)
• Updated input 'stylix':
    'github:danth/stylix/8d008296a1b3be9b57ad570f7acea00dd2fc92db?narHash=sha256-4C3I/ssFsq8EgaUmZP0xv5V7RV0oCHgL/Rx%2BMUkuE%2BE%3D' (2025-10-14)
  → 'github:danth/stylix/8c0640d5722a02178c8ee80a62c5f019cab4b3c1?narHash=sha256-wGiL2K3kAyBBmIZpJEskaSIgyzzpg0zwfvri%2BSy6/CI%3D' (2025-11-02)
• Updated input 'terranix':
    'github:terranix/terranix/924573fa6587ac57b0d15037fbd2d3f0fcdf17fb?narHash=sha256-hTMi6oGU%2B6VRnW9SZZ%2BmuFcbfMEf2ajjOp7Z2KM5MMY%3D' (2025-09-07)
  → 'github:terranix/terranix/a79a47b4617dfb92184e2e5b8f5aa6fc06c659c8?narHash=sha256-J1L1yP29NVBJO04LA/JGM6kwhnjeNhEsX0tLFnuN3FI%3D' (2025-11-03)
• Updated input 'zen-browser':
    'github:0xc000022070/zen-browser-flake/596c3ac14be576b93f5db9252a1b0581e453ec9f?narHash=sha256-RehxVjBRC9EiBO36EPZROLHhVVSWFe3KEROhaEapboM%3D' (2025-10-20)
  → 'github:0xc000022070/zen-browser-flake/10e69cb268b1d3dc91135e72f5462b2acfbcc3aa?narHash=sha256-sIPhzkDrfe6ptthZiwoxQyO6rKd9PgJnl%2BLOyythQkI%3D' (2025-11-03)
2025-11-03 11:13:56 -03:00
697a9f2cab wrap fastfetch with config; run fastfetch on ssh login 2025-11-03 10:55:14 -03:00
716ed5cc53 trator terranix config functional; move disko configs to individual outputs; touching up trantor 2025-11-03 08:07:43 -03:00
5899e42fa4 started oci terranix config 2025-10-29 16:04:31 -03:00
b75f9752d1 use terranix flake parts module directly 2025-10-29 11:14:52 -03:00
90cdc7b8a5 begin configuring terranix 2025-10-29 11:04:26 -03:00
a8977d7dfb greetd only autologin on io 2025-10-29 11:00:50 -03:00
8a64636cc5 niri media keys 2025-10-25 09:10:47 -03:00
98b2d1f44c niri xdg desktop portal config 2025-10-24 17:55:55 -03:00
2d2d27a6fc don't autostart valent 2025-10-23 21:18:44 -03:00
dd06744929 flake.lock: Update
Flake lock file updates:

• Updated input 'noctalia':
    'github:noctalia-dev/noctalia-shell/73267d1d37b60c963fc4f938acab1eef8a655fe7?narHash=sha256-SqBuR0BsZnXopIA8T1Fh8V4hf54pOPoMRwnkML3HGi0%3D' (2025-10-20)
  → 'github:noctalia-dev/noctalia-shell/c3439b262c7cb3d57c93197a93a3aa382582bdae?narHash=sha256-XAs/Q4zBJIfK/bwq9KjTUkTH15A%2BPe2rIilyvalEHuM%3D' (2025-10-23)
2025-10-23 21:18:19 -03:00
8254683b5f set collate locale option 2025-10-23 18:58:20 -03:00
d3c3c78cdd niri: struts only for rotterdam 2025-10-22 18:43:05 -03:00
db4b93273e kdeconnect: use valent instead; ghostty: set up shift+enter 2025-10-22 14:16:52 -03:00
39d1602864 xdg portals 2025-10-22 11:58:03 -03:00
ccd4d5314c new stylix theme 2025-10-21 22:39:25 -03:00
025bd2ccf8 readme glowup 2025-10-21 22:01:34 -03:00
14d08d6d70 specify server hosts 2025-10-21 17:21:14 -03:00
602fec0235 no more home manager stable 2025-10-21 17:18:17 -03:00
66d5275f7d no more better-control; niri config spacing 2025-10-21 13:57:49 -03:00
30ca5f6b29 kde connect needs to be enabled both in the user as the host 2025-10-21 13:12:40 -03:00
5969f2ba9f default desktop programs 2025-10-21 10:22:05 -03:00
c32c37596f io needs battery management 2025-10-21 07:22:35 -03:00
8fc3e89e56 noctalia variable for icons pack 2025-10-21 07:15:35 -03:00
a6aa171a4d nocatlia > dankMaterialShell 2025-10-20 19:49:28 -03:00
831b9c95cd better-control for desktops 2025-10-20 17:38:05 -03:00
6d3ceccf93 finalising niri config on io 2025-10-20 14:10:18 -03:00
8600145275 niri proportions and scaling 2025-10-20 11:58:43 -03:00
5006f6fc95 local build on io deploy 2025-10-20 11:41:15 -03:00
d931282a35 fix niri config spacing 2025-10-20 10:39:44 -03:00
0758864078 niri fully in home manager now 2025-10-20 10:29:16 -03:00
f2921c030b flake.lock: Update
Flake lock file updates:

• Updated input 'agenix':
    'github:ryantm/agenix/9edb1787864c4f59ae5074ad498b6272b3ec308d?narHash=sha256-NA/FT2hVhKDftbHSwVnoRTFhes62%2B7dxZbxj5Gxvghs%3D' (2025-08-05)
  → 'github:ryantm/agenix/2f0f812f69f3eb4140157fe15e12739adf82e32a?narHash=sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L%2BVSybPfiIgzU8lbQ%3D' (2025-10-19)
• Updated input 'dms':
    'github:AvengeMedia/DankMaterialShell/5c816463973d52010839a882d95ea1a44d80c52a?narHash=sha256-ZNIieGgeSRcaok5W0Vre6fOtXVoebkoyBR2yrvhwues%3D' (2025-10-16)
  → 'github:AvengeMedia/DankMaterialShell/d38b98459a157a854cdcb14b8493a517c6416bac?narHash=sha256-mBK9Gwbslo7HASfFkfi%2B5RUEAYJ3SLeEdSZvpRBbsWM%3D' (2025-10-20)
• Updated input 'flake-parts':
    'github:hercules-ci/flake-parts/758cf7296bee11f1706a574c77d072b8a7baa881?narHash=sha256-wfG0S7pltlYyZTM%2BqqlhJ7GMw2fTF4mLKCIVhLii/4M%3D' (2025-10-01)
  → 'github:hercules-ci/flake-parts/864599284fc7c0ba6357ed89ed5e2cd5040f0c04?narHash=sha256-TmWcdiUUaWk8J4lpjzu4gCGxWY6/Ok7mOK4fIFfBuU4%3D' (2025-10-20)
• Updated input 'home-manager':
    'github:nix-community/home-manager/c53e65ec92f38d30e3c14f8d628ab55d462947aa?narHash=sha256-zfY4F4CpeUjTGgecIJZ%2BM7vFpwLc0Gm9epM/iMQd4w8%3D' (2025-10-15)
  → 'github:nix-community/home-manager/189c21cf879669008ccf06e78a553f17e88d8ef0?narHash=sha256-nZh6uvc71nVNaf/y%2BwesnjwsmJ6IZZUnP2EzpZe48To%3D' (2025-10-20)
• Updated input 'nixos-cli':
    'github:nix-community/nixos-cli/437b586743c3d06b0a72893097395b10e70a2b7b?narHash=sha256-cFA87F149mDeogKjty5Kbk6Qy/RhMBr1fM3qEFbdTIg%3D' (2025-10-07)
  → 'github:nix-community/nixos-cli/c8f5ce1fd9bf151df74328795b6b2720e2e22d75?narHash=sha256-N%2BF4n1WYE3AWc/kmdqIz67GNX7PgyKosnmGYYx8vR9k%3D' (2025-10-19)
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/544961dfcce86422ba200ed9a0b00dd4b1486ec5?narHash=sha256-EVAqOteLBFmd7pKkb0%2BFIUyzTF61VKi7YmvP1tw4nEw%3D' (2025-10-15)
  → 'github:nixos/nixpkgs/5e2a59a5b1a82f89f2c7e598302a9cacebb72a67?narHash=sha256-K5Osef2qexezUfs0alLvZ7nQFTGS9DL2oTVsIXsqLgs%3D' (2025-10-19)
• Updated input 'nixpkgs-stable':
    'github:nixos/nixpkgs/a493e93b4a259cd9fea8073f89a7ed9b1c5a1da2?narHash=sha256-Tb%2BNYuJhWZieDZUxN6PgglB16yuqBYQeMJyYBGCXlt8%3D' (2025-10-14)
  → 'github:nixos/nixpkgs/33c6dca0c0cb31d6addcd34e90a63ad61826b28c?narHash=sha256-PXwG0TM7Ek87DNx4LbGWuD93PbFeKAJs4FfALtp7Wo0%3D' (2025-10-19)
• Updated input 'zen-browser':
    'github:0xc000022070/zen-browser-flake/5a651a6a3bb5c9bd694adbd2c34f55b4abff9a2c?narHash=sha256-NufqXao2i6d7N1HFKp8hM8XAD8Q6s/zU2wNd065Ybus%3D' (2025-10-16)
  → 'github:0xc000022070/zen-browser-flake/596c3ac14be576b93f5db9252a1b0581e453ec9f?narHash=sha256-RehxVjBRC9EiBO36EPZROLHhVVSWFe3KEROhaEapboM%3D' (2025-10-20)
2025-10-20 10:08:52 -03:00
ce1af87bdf finally, niri is finished 2025-10-18 18:43:23 -03:00
1b1f30180e fix agenix in devshell 2025-10-18 16:20:43 -03:00
0b17f03dde disable nextcloud appstore 2025-10-18 16:17:08 -03:00
3164e1ebf2 add helix editor to all systems 2025-10-18 15:55:52 -03:00
14457d1ec2 modifications to nextcloud apps 2025-10-18 15:55:37 -03:00
7da7b7167a i give up on nextcloud office 2025-10-18 15:26:32 -03:00
7e02970b56 fix up secrets 2025-10-17 15:39:56 -03:00
265dc99476 add agenix to shell 2025-10-17 15:23:13 -03:00
f5a7377b1f nextcloud desktop client 2025-10-17 11:51:11 -03:00
f9874296ae expose nextcloud and collabora on proxy 2025-10-17 11:47:04 -03:00
d0793fb125 I'm forced to map a port in librespeed 2025-10-17 11:07:55 -03:00
c6b5cc16c1 don't touch nextcloud apps 2025-10-17 11:01:23 -03:00
64379d7ab4 fixed some stuff 2025-10-17 11:01:11 -03:00
6d41eeaf88 mkHome instead of mkUser 2025-10-17 09:51:49 -03:00
681f68d790 nexcloud on 25.05 is still at version 31 2025-10-17 09:47:40 -03:00
c8f1b3a5e0 fix mkNginxVHosts usage; fix librespeed proxy; fix vaultwarden proxy 2025-10-17 08:37:09 -03:00
ee1ed3b88e Merge branch 'refactor' 2025-10-17 07:27:29 -03:00
0cf06f8541 som more deploy-rs mods 2025-10-16 15:30:01 -03:00
3792c11bf0 add deploy-rs to devshell 2025-10-16 15:07:49 -03:00
af7467554f update nextcloud 2025-10-16 15:05:58 -03:00
3f9e2e3844 add deploy-rs 2025-10-16 15:05:42 -03:00
b03a6f1410 nextcloud in; radicale+rclone out 2025-10-16 14:28:08 -03:00
a34c15d72f stylix and zen-browser 2025-10-16 13:44:52 -03:00
8e5a0ff620 stylix on hm 2025-10-16 11:44:11 -03:00
3f2672e468 ghostty shader 2025-10-16 10:31:25 -03:00
9c909ba079 hm-cli now backups files before applying 2025-10-16 10:30:05 -03:00
ecb290a989 renamed mkUser to mkHome 2025-10-16 10:14:47 -03:00
02eb626d33 ghostty settings in hm 2025-10-16 10:03:29 -03:00
79ee8905cd some new stuff in gitignore 2025-10-16 09:47:43 -03:00
9d28046747 starship symbols 2025-10-15 21:37:53 -03:00
d8661561ef minor changes to starship 2025-10-15 20:42:00 -03:00
5e686f5bff fix xdg portal config 2025-10-15 20:32:40 -03:00
f62f34e98f fix warnings 2025-10-15 20:31:20 -03:00
edd0b5ca9c remove fish plugin sponge; updated fish plugin z 2025-10-15 20:15:11 -03:00
8ebab3907f moved kwrite to its own package definition 2025-10-15 20:10:06 -03:00
d655099d76 added error handling to ephemeral.nix 2025-10-15 20:07:51 -03:00
4b5426885c added null check to hm-cli 2025-10-15 20:02:47 -03:00
5edad8b957 ephemeral is now a nixosModule 2025-10-15 19:59:31 -03:00
70 changed files with 3214 additions and 682 deletions

13
.gitignore vendored
View file

@ -1,4 +1,13 @@
result/
# Nix build outputs
result
result-*
.direnv/
.pre-commit-config.yaml
oci-trantor/
tailscale-tailnet/
cloudflare-baduhaidev
# Personal notes and temporary files
todo.md
notes.md
scratch/
tmp/

48
deploy.nix Normal file
View file

@ -0,0 +1,48 @@
{ inputs, self, ... }:
{
flake.deploy = {
remoteBuild = true;
nodes = {
alexandria = {
hostname = "alexandria";
profiles.system = {
sshUser = "user";
path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.alexandria;
user = "root";
};
};
trantor = {
hostname = "trantor";
profiles.system = {
sshUser = "user";
path = inputs.deploy-rs.lib.aarch64-linux.activate.nixos self.nixosConfigurations.trantor;
user = "root";
};
};
io = {
hostname = "io";
profiles = {
system = {
sshUser = "user";
path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.io;
user = "root";
remoteBuild = false;
};
user = {
sshUser = "user";
path = inputs.deploy-rs.lib.x86_64-linux.activate.home-manager self.homeConfigurations."user@io";
user = "user";
remoteBuild = false;
};
};
};
};
};
perSystem =
{ system, ... }:
{
checks = inputs.deploy-rs.lib.${system}.deployChecks self.deploy;
};
}

View file

@ -1,11 +1,13 @@
{ ... }:
{ inputs, ... }:
{
perSystem =
{ pkgs, ... }:
{ pkgs, system, ... }:
{
devShells.default = pkgs.mkShell {
packages = with pkgs; [
inputs.agenix.packages.${system}.default
deploy-rs
nil
nixfmt-rfc-style
];

1134
flake.lock generated

File diff suppressed because it is too large Load diff

View file

@ -2,40 +2,57 @@
description = "My nix hosts";
inputs = {
flake-parts.url = "github:hercules-ci/flake-parts";
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-25.05";
flake-parts.url = "github:hercules-ci/flake-parts";
home-manager = {
url = "github:nix-community/home-manager/master";
inputs.nixpkgs.follows = "nixpkgs";
};
home-manager-stable = {
url = "github:nix-community/home-manager/release-25.05";
inputs.nixpkgs.follows = "nixpkgs-stable";
};
agenix = {
url = "github:ryantm/agenix";
inputs.nixpkgs.follows = "nixpkgs-stable";
};
disko = {
url = "github:nix-community/disko?ref=v1.11.0";
inputs.nixpkgs.follows = "nixpkgs-stable";
};
disko.url = "github:nix-community/disko";
dms = {
url = "github:AvengeMedia/DankMaterialShell";
noctalia = {
url = "github:noctalia-dev/noctalia-shell";
inputs.nixpkgs.follows = "nixpkgs";
};
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";
niri-flake.url = "github:sodiboo/niri-flake";
niri.url = "github:baduhai/niri/auto-center-when-space-available";
nix-index-database = {
url = "github:nix-community/nix-index-database";
inputs.nixpkgs.follows = "nixpkgs";
};
terranix = {
url = "github:terranix/terranix";
inputs.nixpkgs.follows = "nixpkgs";
};
nix-ai-tools.url = "github:numtide/nix-ai-tools";
vicinae.url = "github:vicinaehq/vicinae";
};
outputs =
@ -47,11 +64,14 @@
];
imports = [
./deploy.nix
./devShells.nix
./homeConfigurations.nix
./nixosConfigurations.nix
./nixosModules.nix
./overlays.nix
./packages.nix
./terranixConfigurations.nix
];
};
}

View file

@ -1,33 +1,41 @@
{ inputs, ... }:
let
lib = inputs.nixpkgs.lib;
utils = import ./utils.nix { inherit inputs lib; };
inherit (utils) mkUser;
inherit (utils) mkHome;
in
{
flake.homeConfigurations = {
"user@rotterdam" = mkUser {
"user@rotterdam" = mkHome {
username = "user";
hostname = "rotterdam";
tags = [
"btop"
"desktop"
"btop"
"comma"
"direnv"
"gaming"
"helix"
"obs-studio"
"starship"
"stylix"
"tmux"
];
};
"user@io" = mkUser {
"user@io" = mkHome {
username = "user";
hostname = "io";
tags = [
"btop"
"desktop"
"btop"
"comma"
"direnv"
"helix"
"starship"
"stylix"
"tmux"
];
};

View file

@ -1,11 +0,0 @@
{ ... }:
{
networking.firewall = {
allowedTCPPorts = [
80
443
];
allowedUDPPorts = [ ];
};
}

View file

@ -1,35 +0,0 @@
{
config,
lib,
inputs,
...
}:
let
utils = import ../../utils.nix { inherit inputs lib; };
inherit (utils) mkNginxVHosts;
in
{
services.forgejo = {
enable = true;
repositoryRoot = "/data/forgejo";
settings = {
session.COOKIE_SECURE = true;
server = {
PROTOCOL = "http+unix";
DOMAIN = "git.baduhai.dev";
ROOT_URL = "https://git.baduhai.dev";
OFFLINE_MODE = true; # disable use of CDNs
SSH_DOMAIN = "baduhai.dev";
};
log.LEVEL = "Warn";
mailer.ENABLED = false;
actions.ENABLED = false;
};
};
services.nginx.virtualHosts = mkNginxVHosts {
acmeHost = "baduhai.dev";
domains."git.baduhai.dev".locations."/".proxyPass =
"http://unix:${config.services.forgejo.settings.server.HTTP_ADDR}:/";
};
}

View file

@ -10,7 +10,6 @@ in
};
services.nginx.virtualHosts = mkNginxVHosts {
acmeHost = "baduhai.dev";
domains."jellyfin.baduhai.dev".locations."/".proxyPass = "http://127.0.0.1:8096/";
};
}

View file

@ -0,0 +1,83 @@
{
config,
lib,
inputs,
pkgs,
...
}:
let
utils = import ../../utils.nix { inherit inputs lib; };
inherit (utils) mkNginxVHosts;
kanidmCertDir = "/var/lib/kanidm/certs";
in
{
services.kanidm = {
enableServer = true;
enableClient = true;
package = pkgs.kanidm;
serverSettings = {
domain = "auth.baduhai.dev";
origin = "https://auth.baduhai.dev";
bindaddress = "127.0.0.1:8443";
ldapbindaddress = "127.0.0.1:636";
trust_x_forward_for = true;
# Use self-signed certificates for internal TLS
tls_chain = "${kanidmCertDir}/cert.pem";
tls_key = "${kanidmCertDir}/key.pem";
};
clientSettings = {
uri = "https://auth.baduhai.dev";
};
};
services.nginx.virtualHosts = mkNginxVHosts {
domains."auth.baduhai.dev" = {
locations."/" = {
proxyPass = "https://127.0.0.1:8443";
extraConfig = ''
proxy_ssl_verify off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
'';
};
};
};
networking.firewall.allowedTCPPorts = [ 636 ];
# Generate self-signed certificates for kanidm's internal TLS
systemd.services.kanidm-generate-certs = {
description = "Generate self-signed TLS certificates for Kanidm";
wantedBy = [ "multi-user.target" ];
before = [ "kanidm.service" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
mkdir -p ${kanidmCertDir}
if [ ! -f ${kanidmCertDir}/key.pem ]; then
${pkgs.openssl}/bin/openssl req -x509 -newkey rsa:4096 \
-keyout ${kanidmCertDir}/key.pem \
-out ${kanidmCertDir}/cert.pem \
-days 3650 -nodes \
-subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
chown -R kanidm:kanidm ${kanidmCertDir}
chmod 600 ${kanidmCertDir}/key.pem
chmod 644 ${kanidmCertDir}/cert.pem
fi
'';
};
# Ensure certificate generation runs before kanidm starts
systemd.services.kanidm = {
after = [ "kanidm-generate-certs.service" ];
wants = [ "kanidm-generate-certs.service" ];
};
}

View file

@ -1,22 +0,0 @@
{ lib, inputs, ... }:
let
utils = import ../../utils.nix { inherit inputs lib; };
inherit (utils) mkNginxVHosts;
in
{
virtualisation.oci-containers.containers."librespeed" = {
image = "lscr.io/linuxserver/librespeed:latest";
environment = {
TZ = "America/Bahia";
};
extraOptions = [
"--pull=newer"
"--label=io.containers.autoupdate=registry"
];
};
services.nginx.virtualHosts = mkNginxVHosts {
acmeHost = "baduhai.dev";
domains."speedtest.baduhai.dev".locations."/".proxyPass = "http://librespeed:80/";
};
}

View file

@ -0,0 +1,97 @@
{
lib,
config,
pkgs,
inputs,
...
}:
let
utils = import ../../utils.nix { inherit inputs lib; };
inherit (utils) mkNginxVHosts;
in
{
services = {
nextcloud = {
enable = true;
package = pkgs.nextcloud32;
datadir = "/data/nextcloud";
hostName = "cloud.baduhai.dev";
configureRedis = true;
https = true;
secretFile = config.age.secrets."nextcloud-secrets.json".path;
database.createLocally = true;
maxUploadSize = "16G";
extraApps = {
inherit (config.services.nextcloud.package.packages.apps)
calendar
contacts
notes
tasks
user_oidc
;
};
extraAppsEnable = true;
caching = {
apcu = true;
redis = true;
};
settings = {
trusted_proxies = [ "127.0.0.1" ];
default_phone_region = "BR";
maintenance_window_start = "4";
allow_local_remote_servers = true;
enabledPreviewProviders = [
"OC\\Preview\\BMP"
"OC\\Preview\\EMF"
"OC\\Preview\\Font"
"OC\\Preview\\GIF"
"OC\\Preview\\HEIC"
"OC\\Preview\\Illustrator"
"OC\\Preview\\JPEG"
"OC\\Preview\\Krita"
"OC\\Preview\\MarkDown"
"OC\\Preview\\Movie"
"OC\\Preview\\MP3"
"OC\\Preview\\MSOffice2003"
"OC\\Preview\\MSOffice2007"
"OC\\Preview\\MSOfficeDoc"
"OC\\Preview\\OpenDocument"
"OC\\Preview\\PDF"
"OC\\Preview\\Photoshop"
"OC\\Preview\\PNG"
"OC\\Preview\\Postscript"
"OC\\Preview\\SVG"
"OC\\Preview\\TIFF"
"OC\\Preview\\TXT"
"OC\\Preview\\XBitmap"
];
};
config = {
dbtype = "pgsql";
adminpassFile = config.age.secrets.nextcloud-adminpass.path;
};
phpOptions = {
"opcache.interned_strings_buffer" = "16";
};
};
nginx.virtualHosts = mkNginxVHosts {
domains."cloud.baduhai.dev" = { };
};
};
age.secrets = {
"nextcloud-secrets.json" = {
file = ../../secrets/nextcloud-secrets.json.age;
owner = "nextcloud";
group = "nextcloud";
};
nextcloud-adminpass = {
file = ../../secrets/nextcloud-adminpass.age;
owner = "nextcloud";
group = "nextcloud";
};
};
}

View file

@ -4,10 +4,20 @@
inputs,
...
}:
let
utils = import ../../utils.nix { inherit inputs lib; };
inherit (utils) mkNginxVHosts;
inherit (utils) mkNginxVHosts services;
# Get all unique domains from shared services that have LAN IPs (served by this host)
localDomains = lib.unique (map (s: s.domain) (lib.filter (s: s.host == "alexandria") services));
# Generate ACME cert configs for all local domains
acmeCerts = lib.genAttrs localDomains (domain: {
group = "nginx";
});
in
{
security.acme = {
acceptTerms = true;
@ -17,15 +27,7 @@ in
dnsProvider = "cloudflare";
credentialsFile = config.age.secrets.cloudflare.path;
};
certs."baduhai.dev" = {
extraDomainNames = [ "*.baduhai.dev" ];
};
};
age.secrets.cloudflare = {
file = ../../secrets/cloudflare.age;
owner = "nginx";
group = "nginx";
certs = acmeCerts;
};
services.nginx = {
@ -34,11 +36,24 @@ in
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
virtualHosts = mkNginxVHosts {
acmeHost = "baduhai.dev";
domains."_".locations."/".return = "444";
virtualHosts = {
"_" = {
default = true;
locations."/".return = "444";
};
};
};
users.users.nginx.extraGroups = [ "acme" ];
networking.firewall.allowedTCPPorts = [
80
443
];
age.secrets.cloudflare = {
file = ../../secrets/cloudflare.age;
owner = "nginx";
group = "nginx";
};
}

View file

@ -0,0 +1,58 @@
{ inputs, lib, ... }:
let
utils = import ../../utils.nix { inherit inputs lib; };
in
{
services.unbound = {
enable = true;
enableRootTrustAnchor = true;
settings = {
server = {
interface = [
"0.0.0.0"
"::"
];
access-control = [
"127.0.0.0/8 allow"
"192.168.0.0/16 allow"
"::1/128 allow"
];
num-threads = 2;
msg-cache-size = "50m";
rrset-cache-size = "100m";
cache-min-ttl = 300;
cache-max-ttl = 86400;
prefetch = true;
prefetch-key = true;
hide-identity = true;
hide-version = true;
so-rcvbuf = "1m";
so-sndbuf = "1m";
# LAN-only DNS records
local-zone = ''"baduhai.dev." transparent'';
local-data = map (e: ''"${e.domain}. IN A ${e.lanIP}"'')
(lib.filter (e: e ? lanIP) utils.services);
};
forward-zone = [
{
name = ".";
forward-addr = [
"1.1.1.1@853#cloudflare-dns.com"
"1.0.0.1@853#cloudflare-dns.com"
];
forward-tls-upstream = true;
}
];
};
};
networking.firewall = {
allowedTCPPorts = [ 53 ];
allowedUDPPorts = [ 53 ];
};
}

View file

@ -14,13 +14,13 @@ in
config = {
DOMAIN = "https://pass.baduhai.dev";
SIGNUPS_ALLOWED = false;
ROCKET_ADDRESS = "/run/vaultwarden/vaultwarden.sock";
ROCKET_ADDRESS = "127.0.0.1";
ROCKET_PORT = 58222;
};
};
services.nginx.virtualHosts = mkNginxVHosts {
acmeHost = "baduhai.dev";
domains."pass.baduhai.dev".locations."/".proxyPass =
"http://unix:${config.services.vaultwarden.config.ROCKET_ADDRESS}:/";
"http://${config.services.vaultwarden.config.ROCKET_ADDRESS}:${toString config.services.vaultwarden.config.ROCKET_PORT}/";
};
}

View file

@ -3,75 +3,71 @@
{
imports = [ inputs.disko.nixosModules.default ];
disko.devices = {
disk = {
main = {
type = "disk";
device = "/dev/disk/by-id/mmc-hDEaP3_0x1041b689";
content = {
type = "gpt";
partitions = {
ESP = {
priority = 1;
name = "ESP";
start = "1MiB";
end = "1GiB";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot/efi";
mountOptions = [
"noatime"
"fmask=0077"
"dmask=0077"
];
};
};
cryptroot = {
priority = 2;
name = "root";
size = "100%";
content = {
type = "luks";
name = "cryptroot";
content = {
type = "btrfs";
extraArgs = [ "-f" ];
subvolumes = {
"@root" = {
mountpoint = "/";
mountOptions = [
"noatime"
"compress=zstd"
"subvol=@root"
];
};
"@home" = {
mountpoint = "/home";
mountOptions = [
"noatime"
"compress=zstd"
"subvol=@home"
];
};
"@nix" = {
mountpoint = "/nix";
mountOptions = [
"noatime"
"compress=zstd"
"subvol=@nix"
];
};
"@persistent" = {
mountpoint = "/persistent";
mountOptions = [
"noatime"
"compress=zstd"
"subvol=@persistent"
];
};
};
disko.devices.disk.main = {
type = "disk";
device = "/dev/disk/by-id/mmc-hDEaP3_0x1041b689";
content = {
type = "gpt";
partitions = {
ESP = {
priority = 1;
name = "ESP";
start = "1MiB";
end = "1GiB";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot/efi";
mountOptions = [
"noatime"
"fmask=0077"
"dmask=0077"
];
};
};
cryptroot = {
priority = 2;
name = "root";
size = "100%";
content = {
type = "luks";
name = "cryptroot";
content = {
type = "btrfs";
extraArgs = [ "-f" ];
subvolumes = {
"@root" = {
mountpoint = "/";
mountOptions = [
"noatime"
"compress=zstd"
"subvol=@root"
];
};
"@home" = {
mountpoint = "/home";
mountOptions = [
"noatime"
"compress=zstd"
"subvol=@home"
];
};
"@nix" = {
mountpoint = "/nix";
mountOptions = [
"noatime"
"compress=zstd"
"subvol=@nix"
];
};
"@persistent" = {
mountpoint = "/persistent";
mountOptions = [
"noatime"
"compress=zstd"
"subvol=@persistent"
];
};
};
};

View file

@ -2,6 +2,7 @@
config,
lib,
modulesPath,
inputs,
...
}:

View file

@ -48,6 +48,8 @@
};
};
};
upower.enable = true;
power-profiles-daemon.enable = true;
};
# TODO: remove once gmodena/nix-flatpak/issues/45 fixed

10
hosts/modules/ai.nix Normal file
View file

@ -0,0 +1,10 @@
{ inputs, pkgs, ... }:
{
environment.systemPackages = with inputs.nix-ai-tools.packages.${pkgs.system}; [
claude-desktop
claude-code
claudebox
opencode
];
}

View file

@ -7,6 +7,7 @@
defaultLocale = "en_US.UTF-8";
extraLocaleSettings = {
LC_ADDRESS = "pt_BR.utf8";
LC_COLLATE = "pt_BR.utf8";
LC_IDENTIFICATION = "pt_BR.utf8";
LC_MEASUREMENT = "pt_BR.utf8";
LC_MONETARY = "pt_BR.utf8";

View file

@ -26,13 +26,11 @@
buildDocs = false;
};
services = {
nixos-cli = {
enable = true;
config = {
use_nvd = true;
ignore_dirty_tree = true;
};
services.nixos-cli = {
enable = true;
config = {
use_nvd = true;
ignore_dirty_tree = true;
};
};

View file

@ -4,5 +4,8 @@
services.openssh = {
enable = true;
settings.PermitRootLogin = "no";
extraConfig = ''
PrintLastLog no
'';
};
}

View file

@ -7,6 +7,8 @@
git
### System Utilities ###
btop
fastfetch
helix
nixos-firewall-tool
nvd
sysz
@ -17,13 +19,22 @@
shellAliases = {
cat = "${lib.getExe pkgs.bat} --paging=never --style=plain";
ls = "${lib.getExe pkgs.eza} --icons --group-directories-first";
neofetch = "${lib.getExe pkgs.fastfetch}";
tree = "ls --tree";
};
};
programs = {
command-not-found.enable = false;
fish.enable = true;
fish = {
enable = true;
interactiveShellInit = ''
set fish_greeting
if set -q SSH_CONNECTION
export TERM=xterm-256color
clear
fastfetch
end
'';
};
};
}

View file

@ -10,8 +10,9 @@
"wheel"
];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL user@rotterdam"
"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";
};
@ -20,10 +21,4 @@
hashedPassword = "!";
};
};
programs.fish = {
enable = true;
interactiveShellInit = ''
set fish_greeting
'';
};
}

View file

@ -1,79 +1,63 @@
{
config,
inputs,
lib,
pkgs,
...
}:
let
kwrite = pkgs.symlinkJoin {
name = "kwrite";
paths = [ pkgs.kdePackages.kate ];
postBuild = ''
rm -rf $out/bin/kate \
$out/bin/.kate-wrapped \
$out/share/applications/org.kde.kate.desktop \
$out/share/man \
$out/share/icons/hicolor/*/apps/kate.png \
$out/share/icons/hicolor/scalable/apps/kate.svg \
$out/share/appdata/org.kde.kate.appdata.xml
'';
};
in
{
imports = [ inputs.nix-flatpak.nixosModules.nix-flatpak ];
imports = [
inputs.niri-flake.nixosModules.niri
inputs.nix-flatpak.nixosModules.nix-flatpak
];
environment = {
sessionVariables = {
KDEHOME = "$XDG_CONFIG_HOME/kde4"; # Stops kde from placing a .kde4 folder in the home dir
NIXOS_OZONE_WL = "1"; # Forces chromium and most electron apps to run in wayland
};
systemPackages =
with pkgs;
[
### Web ###
bitwarden-desktop
brave
tor-browser
qbittorrent
vesktop
### Office & Productivity ###
aspell
aspellDicts.de
aspellDicts.en
aspellDicts.en-computers
aspellDicts.pt_BR
kwrite
libreoffice-qt
onlyoffice-desktopeditors
rnote
### Graphics & Design ###
gimp
inkscape
plasticity
### System Utilities ###
adwaita-icon-theme
colloid-gtk-theme
junction
kara
kde-rounded-corners
libfido2
mission-center
p7zip
rclone
toggleaudiosink
unrar
### Media ###
mpv
obs-studio
qview
]
++ (with pkgs.kdePackages; [
ark
dolphin
dolphin-plugins
kolourpaint
]);
systemPackages = with pkgs; [
### Web ###
bitwarden-desktop
fragments
nextcloud-client
tor-browser
vesktop
inputs.zen-browser.packages."${system}".default
### Office & Productivity ###
aspell
aspellDicts.de
aspellDicts.en
aspellDicts.en-computers
aspellDicts.pt_BR
libreoffice
onlyoffice-desktopeditors
papers
presenterm
rnote
### Graphics & Design ###
gimp
inkscape
plasticity
### System Utilities ###
adwaita-icon-theme
ghostty
gnome-disk-utility
junction
libfido2
mission-center
nautilus
p7zip
rclone
toggleaudiosink
unrar
### Media ###
decibels
loupe
obs-studio
showtime
];
};
services = {
@ -89,11 +73,13 @@ in
enable = true;
settings = {
default_session = {
command = "${lib.getExe pkgs.greetd.tuigreet} --time --remember --asterisks --cmd ${lib.getExe pkgs.niri}";
command = "${lib.getExe pkgs.tuigreet} --user-menu --time --remember --asterisks --cmd ${config.programs.niri.package}/bin/niri-session";
user = "greeter";
};
}
// lib.optionalAttrs (config.networking.hostName == "io") {
initial_session = {
command = "${lib.getExe pkgs.niri}";
command = "${config.programs.niri.package}/bin/niri-session";
user = "user";
};
};
@ -101,8 +87,6 @@ in
flatpak = {
enable = true;
packages = [
### Internet Browsers & Communication ###
"app.zen_browser.zen"
### Graphics & Design ###
"com.boxy_svg.BoxySVG"
rec {
@ -120,6 +104,7 @@ in
uninstallUnmanaged = true;
update.auto.enable = true;
};
gvfs.enable = true;
};
security.rtkit.enable = true; # Needed for pipewire to acquire realtime priority
@ -133,16 +118,23 @@ in
};
programs = {
niri.enable = true;
niri = {
enable = true;
package = inputs.niri.packages.${pkgs.system}.niri;
};
kdeconnect = {
enable = true;
package = pkgs.valent;
};
dconf.enable = true;
kdeconnect.enable = true;
partition-manager.enable = true;
appimage = {
enable = true;
binfmt = true;
};
};
niri-flake.cache.enable = false;
fonts = {
fontDir.enable = true;
packages = with pkgs; [
@ -154,4 +146,18 @@ in
roboto
];
};
xdg.portal = {
extraPortals = with pkgs; [
xdg-desktop-portal-gnome
xdg-desktop-portal-gtk
];
config = {
common.default = "*";
niri.default = [
"gtk"
"gnome"
];
};
};
}

View file

@ -3,7 +3,6 @@
{
environment.systemPackages = with pkgs; [
bat
claude-code
lazygit
fd
fzf

View file

@ -0,0 +1,41 @@
{ config, inputs, ... }:
{
imports = [
inputs.impermanence.nixosModules.impermanence
inputs.self.nixosModules.ephemeral
];
ephemeral = {
enable = true;
rootDevice =
if config.networking.hostName == "trantor" then
"/dev/disk/by-id/scsi-360b207ed25d84372a95d1ecf842f8e20-part2"
else
"/dev/mapper/cryptroot";
rootSubvolume = "@root";
};
environment.persistence.main = {
persistentStoragePath = "/persistent";
files = [
"/etc/machine-id"
"/etc/ssh/ssh_host_ed25519_key"
"/etc/ssh/ssh_host_ed25519_key.pub"
"/etc/ssh/ssh_host_rsa_key"
"/etc/ssh/ssh_host_rsa_key.pub"
];
directories = [
"/etc/NetworkManager/system-connections"
"/etc/nixos"
"/var/lib/bluetooth"
"/var/lib/flatpak"
"/var/lib/lxd"
"/var/lib/nixos"
"/var/lib/systemd/coredump"
"/var/lib/systemd/timers"
"/var/lib/tailscale"
"/var/log"
];
};
}

View file

@ -1,72 +0,0 @@
{ inputs, ... }:
{
imports = [ inputs.impermanence.nixosModules.impermanence ];
boot.initrd.systemd.services.recreate-root = {
description = "Rolling over and creating new filesystem root";
requires = [ "initrd-root-device.target" ];
after = [
"local-fs-pre.target"
"initrd-root-device.target"
];
requiredBy = [ "initrd-root-fs.target" ];
before = [ "sysroot.mount" ];
unitConfig = {
AssertPathExists = "/etc/initrd-release";
DefaultDependencies = false;
};
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
mkdir /btrfs_tmp
mount /dev/mapper/cryptroot /btrfs_tmp
if [[ -e /btrfs_tmp/@root ]]; then
mkdir -p /btrfs_tmp/old_roots
timestamp=$(date --date="@$(stat -c %Y /btrfs_tmp/@root)" "+%Y-%m-%-d_%H:%M:%S")
mv /btrfs_tmp/@root "/btrfs_tmp/old_roots/$timestamp"
fi
delete_subvolume_recursively() {
IFS=$'\n'
for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do
delete_subvolume_recursively "/btrfs_tmp/$i"
done
btrfs subvolume delete "$1"
}
for i in $(find /btrfs_tmp/old_roots/ -maxdepth 1 -mtime +30); do
delete_subvolume_recursively "$i"
done
btrfs subvolume create /btrfs_tmp/@root
umount /btrfs_tmp
'';
};
environment.persistence.main = {
persistentStoragePath = "/persistent";
files = [
"/etc/machine-id"
"/etc/ssh/ssh_host_ed25519_key"
"/etc/ssh/ssh_host_ed25519_key.pub"
"/etc/ssh/ssh_host_rsa_key"
"/etc/ssh/ssh_host_rsa_key.pub"
];
directories = [
"/etc/NetworkManager/system-connections"
"/etc/nixos"
"/var/lib/bluetooth"
"/var/lib/flatpak"
"/var/lib/lxd"
"/var/lib/nixos"
"/var/lib/systemd/coredump"
"/var/lib/systemd/timers"
"/var/lib/tailscale"
"/var/log"
];
};
}

View file

@ -6,7 +6,6 @@
heroic
mangohud
prismlauncher
protonup
steam-run
];

View file

@ -1,6 +1,6 @@
{
boot = {
loader.efi.efiSysMountPoint = "/boot";
initrd.systemd.enable = true;
loader.efi.efiSysMountPoint = "/boot/efi";
};
}

View file

@ -3,29 +3,57 @@
{
imports = [ inputs.disko.nixosModules.default ];
disko.devices = {
disk = {
main = {
type = "disk";
device = "/dev/disk/by-id/scsi-3605e4addb4c640319c8c03436205530b";
content = {
type = "gpt";
partitions = {
boot = {
size = "512M";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
size = "100%";
content = {
type = "filesystem";
format = "ext4";
disko.devices.disk.main = {
type = "disk";
device = "/dev/disk/by-id/scsi-360b207ed25d84372a95d1ecf842f8e20";
content = {
type = "gpt";
partitions = {
ESP = {
priority = 1;
name = "ESP";
start = "1MiB";
end = "512MiB";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot/efi";
mountOptions = [
"noatime"
"fmask=0077"
"dmask=0077"
];
};
};
root = {
priority = 2;
name = "root";
size = "100%";
content = {
type = "btrfs";
extraArgs = [ "-f" ];
subvolumes = {
"@root" = {
mountpoint = "/";
mountOptions = [
"noatime"
"compress=zstd"
];
};
"@nix" = {
mountpoint = "/nix";
mountOptions = [
"noatime"
"compress=zstd"
];
};
"@persistent" = {
mountpoint = "/persistent";
mountOptions = [
"noatime"
"compress=zstd"
];
};
};
};

View file

@ -0,0 +1,23 @@
{ config, pkgs, ... }:
{
services.fail2ban = {
enable = true;
maxretry = 5;
ignoreIP = [
"127.0.0.0/8"
"::1"
"10.0.0.0/8"
"172.16.0.0/12"
"192.168.0.0/16"
"100.64.0.0/10"
];
bantime = "1h";
bantime-increment = {
enable = true;
multipliers = "1 2 4 8 16 32 64";
maxtime = "10000h";
overalljails = true;
};
};
}

72
hosts/trantor/forgejo.nix Normal file
View file

@ -0,0 +1,72 @@
{
config,
lib,
inputs,
...
}:
let
utils = import ../../utils.nix { inherit inputs lib; };
inherit (utils) mkNginxVHosts;
in
{
services = {
forgejo = {
enable = true;
settings = {
session.COOKIE_SECURE = true;
server = {
PROTOCOL = "http+unix";
DOMAIN = "git.baduhai.dev";
ROOT_URL = "https://git.baduhai.dev";
OFFLINE_MODE = true; # disable use of CDNs
SSH_DOMAIN = "git.baduhai.dev";
};
log.LEVEL = "Warn";
mailer.ENABLED = false;
actions.ENABLED = false;
service.DISABLE_REGISTRATION = true;
oauth2_client = {
ENABLE_AUTO_REGISTRATION = true;
UPDATE_AVATAR = true;
ACCOUNT_LINKING = "login";
USERNAME = "preferred_username";
};
};
};
nginx.virtualHosts = mkNginxVHosts {
domains."git.baduhai.dev".locations."/".proxyPass =
"http://unix:${config.services.forgejo.settings.server.HTTP_ADDR}:/";
};
fail2ban.jails.forgejo = {
settings = {
enabled = true;
filter = "forgejo";
maxretry = 3;
findtime = "10m";
bantime = "1h";
};
};
};
environment = {
etc."fail2ban/filter.d/forgejo.conf".text = ''
[Definition]
failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>
ignoreregex =
journalmatch = _SYSTEMD_UNIT=forgejo.service
'';
persistence.main.directories = [
{
directory = config.services.forgejo.stateDir;
inherit (config.services.forgejo) user group;
mode = "0700";
}
];
};
# Disable PrivateMounts to allow LoadCredential to work with bind-mounted directories
systemd.services.forgejo.serviceConfig.PrivateMounts = lib.mkForce false;
}

View file

@ -7,19 +7,12 @@
{
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
boot = {
kernelModules = [ ];
extraModulePackages = [ ];
initrd = {
availableKernelModules = [
"xhci_pci"
"virtio_pci"
"virtio_scsi"
"usbhid"
];
kernelModules = [ ];
};
};
boot.initrd.availableKernelModules = [
"xhci_pci"
"virtio_pci"
"virtio_scsi"
"usbhid"
];
networking.useDHCP = lib.mkDefault true;

61
hosts/trantor/nginx.nix Normal file
View file

@ -0,0 +1,61 @@
{
config,
lib,
inputs,
...
}:
let
utils = import ../../utils.nix { inherit inputs lib; };
inherit (utils) mkNginxVHosts services;
# Get all unique domains from shared services on trantor (host = "trantor")
localDomains = lib.unique (
map (s: s.domain) (lib.filter (s: s.host == "trantor") services)
);
# Generate ACME cert configs for all local domains
acmeCerts = lib.genAttrs localDomains (domain: {
group = "nginx";
});
in
{
security.acme = {
acceptTerms = true;
defaults = {
email = "baduhai@proton.me";
dnsResolver = "1.1.1.1:53";
dnsProvider = "cloudflare";
credentialsFile = config.age.secrets.cloudflare.path;
};
certs = acmeCerts;
};
services.nginx = {
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
virtualHosts = {
"_" = {
default = true;
locations."/".return = "444";
};
};
};
users.users.nginx.extraGroups = [ "acme" ];
networking.firewall.allowedTCPPorts = [
80
443
];
age.secrets.cloudflare = {
file = ../../secrets/cloudflare.age;
owner = "nginx";
group = "nginx";
};
}

23
hosts/trantor/openssh.nix Normal file
View file

@ -0,0 +1,23 @@
{ ... }:
{
services = {
openssh = {
settings = {
PasswordAuthentication = false;
KbdInteractiveAuthentication = false;
};
};
fail2ban.jails.sshd = {
settings = {
enabled = true;
port = "ssh";
filter = "sshd";
logpath = "/var/log/auth.log";
maxretry = 3;
findtime = "10m";
bantime = "1h";
};
};
};
}

58
hosts/trantor/unbound.nix Normal file
View file

@ -0,0 +1,58 @@
{ inputs, lib, ... }:
let
utils = import ../../utils.nix { inherit inputs lib; };
in
{
services.unbound = {
enable = true;
enableRootTrustAnchor = true;
settings = {
server = {
interface = [
"0.0.0.0"
"::"
];
access-control = [
"127.0.0.0/8 allow"
"100.64.0.0/10 allow" # Tailscale CGNAT range
"::1/128 allow"
"fd7a:115c:a1e0::/48 allow" # Tailscale IPv6
];
num-threads = 2;
msg-cache-size = "50m";
rrset-cache-size = "100m";
cache-min-ttl = 300;
cache-max-ttl = 86400;
prefetch = true;
prefetch-key = true;
hide-identity = true;
hide-version = true;
so-rcvbuf = "1m";
so-sndbuf = "1m";
# Tailnet DNS records from shared services
local-zone = ''"baduhai.dev." transparent'';
local-data = map (e: ''"${e.domain}. IN A ${e.tailscaleIP}"'') utils.services;
};
forward-zone = [
{
name = ".";
forward-addr = [
"1.1.1.1@853#cloudflare-dns.com"
"1.0.0.1@853#cloudflare-dns.com"
];
forward-tls-upstream = true;
}
];
};
};
networking.firewall = {
allowedTCPPorts = [ 53 ];
allowedUDPPorts = [ 53 ];
};
}

84
modules/ephemeral.nix Normal file
View file

@ -0,0 +1,84 @@
{ lib, config, ... }:
let
cfg = config.ephemeral;
in
{
options.ephemeral = {
enable = lib.mkEnableOption "ephemeral root with automatic rollback";
rootDevice = lib.mkOption {
type = lib.types.str;
example = "/dev/mapper/cryptroot";
description = "Device path for the root btrfs filesystem";
};
rootSubvolume = lib.mkOption {
type = lib.types.str;
example = "@root";
description = "Name of the root btrfs subvolume";
};
oldRootRetentionDays = lib.mkOption {
type = lib.types.int;
default = 30;
description = "Number of days to keep old root snapshots before deletion";
};
};
config = lib.mkIf cfg.enable {
boot.initrd.systemd.services.recreate-root = {
description = "Rolling over and creating new filesystem root";
requires = [ "initrd-root-device.target" ];
after = [
"local-fs-pre.target"
"initrd-root-device.target"
];
requiredBy = [ "initrd-root-fs.target" ];
before = [ "sysroot.mount" ];
unitConfig = {
AssertPathExists = "/etc/initrd-release";
DefaultDependencies = false;
};
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
set -euo pipefail
mkdir /btrfs_tmp
if ! mount ${cfg.rootDevice} /btrfs_tmp; then
echo "ERROR: Failed to mount ${cfg.rootDevice}"
exit 1
fi
if [[ -e /btrfs_tmp/${cfg.rootSubvolume} ]]; then
mkdir -p /btrfs_tmp/old_roots
timestamp=$(date --date="@$(stat -c %Y /btrfs_tmp/${cfg.rootSubvolume})" "+%Y-%m-%-d_%H:%M:%S")
mv /btrfs_tmp/${cfg.rootSubvolume} "/btrfs_tmp/old_roots/$timestamp"
fi
delete_subvolume_recursively() {
IFS=$'\n'
for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do
delete_subvolume_recursively "/btrfs_tmp/$i"
done
btrfs subvolume delete "$1"
}
for i in $(find /btrfs_tmp/old_roots/ -maxdepth 1 -mtime +${toString cfg.oldRootRetentionDays}); do
delete_subvolume_recursively "$i"
done
if ! btrfs subvolume create /btrfs_tmp/${cfg.rootSubvolume}; then
echo "ERROR: Failed to create subvolume ${cfg.rootSubvolume}"
umount /btrfs_tmp
exit 1
fi
umount /btrfs_tmp
'';
};
};
}

View file

@ -10,9 +10,10 @@ in
hostname = "rotterdam";
tags = [
"desktop"
"ai"
"bluetooth"
"dev"
"ephermal"
"ephemeral"
"fwupd"
"gaming"
"libvirtd"
@ -25,9 +26,10 @@ in
hostname = "io";
tags = [
"desktop"
"ai"
"bluetooth"
"dev"
"ephermal"
"ephemeral"
"networkmanager"
"podman"
];
@ -36,8 +38,8 @@ in
alexandria = mkHost {
hostname = "alexandria";
tags = [
# "server" TODO: uncomment when 25.11 is out.
"fwupd"
"podman"
];
};
@ -45,6 +47,8 @@ in
hostname = "trantor";
system = "aarch64-linux";
tags = [
"server"
"ephemeral"
];
};
};

7
nixosModules.nix Normal file
View file

@ -0,0 +1,7 @@
{ ... }:
{
flake.nixosModules = {
ephemeral = import ./modules/ephemeral.nix;
};
}

View file

@ -3,8 +3,11 @@
{
flake.overlays = {
default = final: prev: {
toggleaudiosink = inputs.self.packages.${final.system}.toggleaudiosink;
base16-schemes = inputs.self.packages.${final.system}.base16-schemes;
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;
};
};
}

View file

@ -5,8 +5,11 @@
{ pkgs, system, ... }:
{
packages = {
toggleaudiosink = pkgs.callPackage ./packages/toggleaudiosink.nix { };
base16-schemes = pkgs.callPackage ./packages/base16-schemes.nix { };
fastfetch = pkgs.callPackage ./packages/fastfetch.nix { };
hm-cli = pkgs.callPackage ./packages/hm-cli.nix { };
kwrite = pkgs.callPackage ./packages/kwrite.nix { };
toggleaudiosink = pkgs.callPackage ./packages/toggleaudiosink.nix { };
};
};
}

View file

@ -0,0 +1,32 @@
{
lib,
stdenv,
fetchFromGitHub,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "base16-schemes";
version = "0-unstable-2025-06-04";
src = fetchFromGitHub {
owner = "tinted-theming";
repo = "schemes";
rev = "317a5e10c35825a6c905d912e480dfe8e71c7559";
hash = "sha256-d4km8W7w2zCUEmPAPUoLk1NlYrGODuVa3P7St+UrqkM=";
};
installPhase = ''
runHook preInstall
mkdir -p $out/share/themes/
install base16/*.yaml $out/share/themes/
runHook postInstall
'';
meta = {
description = "All the color schemes for use in base16 packages";
homepage = "https://github.com/tinted-theming/schemes";
maintainers = [ lib.maintainers.DamienCassou ];
license = lib.licenses.mit;
};
})

81
packages/fastfetch.nix Normal file
View file

@ -0,0 +1,81 @@
{
lib,
pkgs ? import <nixpkgs> { },
}:
let
fastfetch-logo = pkgs.fetchurl {
url = "https://discourse.nixos.org/uploads/default/original/3X/3/6/36954e6d6aa32c8b00f50ca43f142d898c1ff535.png";
hash = "sha256-aLHz8jSAFocrn+Pb4vRq0wtkYFJpBpZRevd+VoZC/PQ=";
};
fastfetch-config = pkgs.writeText "fastfetch-config.json" (
builtins.toJSON {
"$schema" = "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json";
modules = [
"title"
"separator"
{
type = "os";
keyWidth = 9;
}
{
type = "kernel";
keyWidth = 9;
}
{
type = "uptime";
keyWidth = 9;
}
{
type = "shell";
keyWidth = 9;
}
"break"
{
type = "cpu";
keyWidth = 11;
}
{
type = "memory";
keyWidth = 11;
}
{
type = "swap";
keyWidth = 11;
}
{
type = "disk";
folders = "/";
keyWidth = 11;
}
{
type = "command";
key = "Systemd";
keyWidth = 11;
text = "echo \"$(systemctl list-units --state=failed --no-legend | wc -l) failed units, $(systemctl list-jobs --no-legend | wc -l) queued jobs\"";
}
"break"
{
type = "command";
key = "Public IP";
keyWidth = 15;
text = "curl -s -4 ifconfig.me 2>/dev/null || echo 'N/A'";
}
{
type = "command";
key = "Tailscale IP";
keyWidth = 15;
text = "tailscale ip -4 2>/dev/null || echo 'N/A'";
}
{
type = "command";
key = "Local IP";
keyWidth = 15;
text = "ip -4 addr show scope global | grep inet | head -n1 | awk '{print $2}' | cut -d/ -f1";
}
];
}
);
in
pkgs.writeShellScriptBin "fastfetch" ''exec ${lib.getExe pkgs.fastfetch} --config ${fastfetch-config} --logo-type kitty --logo ${fastfetch-logo} --logo-padding-right 1 --logo-width 36 "$@" ''

View file

@ -23,9 +23,9 @@ pkgs.writeShellScriptBin "hm" ''
Environment Variables:
HM_PATH Override default flake path (~/.config/home-manager)
Currently set to "$(echo $HM_PATH)"
Currently set to "''${HM_PATH:-<not set>}"
HM_USER Override default user output ("$(whoami)@$(hostname)")
Currently set to "$(echo $HM_USER)"
Currently set to "''${HM_USER:-<not set>}"
EOF
}
@ -36,7 +36,7 @@ pkgs.writeShellScriptBin "hm" ''
case "$1" in
apply)
"$HM" switch --flake "$FLAKE_PATH#$FLAKE_OUTPUT"
"$HM" switch --flake "$FLAKE_PATH#$FLAKE_OUTPUT" -b bkp
;;
generation)
if [[ $# -lt 2 ]]; then
@ -58,17 +58,21 @@ pkgs.writeShellScriptBin "hm" ''
"$HM" remove-generations "$@"
;;
rollback)
"$HM" generations | \
PREV_GEN=$("$HM" generations | \
sed -n 's/^[[:space:]]*id \([0-9]\+\).*/\1/p' | \
head -n 2 | tail -n 1 | \
xargs -I {} "$HM" switch --flake "$FLAKE_PATH" --switch-generation {}
head -n 2 | tail -n 1)
if [[ -z "$PREV_GEN" ]]; then
echo "Error: could not determine previous generation (possibly only one generation exists)"
exit 1
fi
"$HM" switch --flake "$FLAKE_PATH" --switch-generation "$PREV_GEN" -b bkp
;;
switch)
if [[ $# -ne 3 ]]; then
echo "Error: switch requires exactly one generation ID"
exit 1
fi
"$HM" switch --flake "$FLAKE_PATH" --switch-generation "$3"
"$HM" switch --flake "$FLAKE_PATH" --switch-generation "$3" -b bkp
;;
cleanup)
CURRENT_GEN=$("$HM" generations | sed -n 's/^.*id \([0-9]\+\) .* (current)$/\1/p')

15
packages/kwrite.nix Normal file
View file

@ -0,0 +1,15 @@
{ pkgs }:
pkgs.symlinkJoin {
name = "kwrite";
paths = [ pkgs.kdePackages.kate ];
postBuild = ''
rm -rf $out/bin/kate \
$out/bin/.kate-wrapped \
$out/share/applications/org.kde.kate.desktop \
$out/share/man \
$out/share/icons/hicolor/*/apps/kate.png \
$out/share/icons/hicolor/scalable/apps/kate.svg \
$out/share/appdata/org.kde.kate.appdata.xml
'';
}

View file

@ -1,8 +1,87 @@
All my personal Nix and NixOS hosts, in a flake.
# Nix Configuration
|Host|Description|System Version|
|:---|:---:|---:|
|alexandria|Personal server/NAS|NixOS 25.05|
|io|Mobile workstation|NixOS Unstable|
|rotterdam|Workstation|NixOS Unstable|
|trantor|Oracle Cloud VPS|NixOS 25.05|
My personal Nix configuration for multiple NixOS hosts, home-manager users, miscellaneous resources... too many things to list. If I could put my life in a flake I would.
## Hosts
### Desktop Systems
- **rotterdam** - Main desktop workstation (x86_64)
- Features: Desktop, AI tools, Bluetooth, Dev environment, Gaming, Virtualization (libvirtd), Podman
- Storage: Ephemeral root with LUKS encryption
- **io** - Laptop workstation (x86_64)
- Features: Desktop, AI tools, Bluetooth, Dev environment, Podman
- Storage: Ephemeral root with LUKS encryption
### Servers
- **alexandria** - Home server (x86_64)
- Hosts: Nextcloud, Vaultwarden, Jellyfin, Kanidm
- **trantor** - Cloud server (aarch64)
- Hosts: Forgejo
- Cloud provider: Oracle Cloud Infrastructure
- Storage: Ephemeral root with btrfs
## Home Manager Configurations
- **user@rotterdam** - Full desktop setup with gaming, OBS, and complete development environment
- **user@io** - Lightweight desktop setup
Both configurations include:
- btop, direnv, helix, starship, tmux
- Stylix theme management
- Fish shell with custom configurations
## Terranix Configurations
Infrastructure as code using Terranix (NixOS + Terraform/OpenTofu):
- **oci-trantor** - Oracle Cloud Infrastructure provisioning for Trantor server
- **cloudflare-baduhaidev** - DNS and CDN configuration for baduhai.dev domain
- **tailscale-tailnet** - Tailscale network ACL and device management
## Services
All services are accessible via custom domains under baduhai.dev:
- **Kanidm** (auth.baduhai.dev) - Identity and access management
- **Vaultwarden** (pass.baduhai.dev) - Password manager
- **Forgejo** (git.baduhai.dev) - Git forge (publicly accessible)
- **Nextcloud** (cloud.baduhai.dev) - File sync and collaboration
- **Jellyfin** (jellyfin.baduhai.dev) - Media server
Services are accessible via:
- LAN for alexandria-hosted services
- Tailscale VPN for all services
- Public internet for Forgejo only
## Notable Features
### Ephemeral Root
Rotterdam, io, and trantor use an ephemeral root filesystem that resets on every boot:
- Root filesystem is automatically rolled back using btrfs snapshots
- Old snapshots retained for 30 days
- Persistent data stored in dedicated subvolumes
- Implements truly stateless systems
### Custom DNS Architecture
- Unbound DNS servers on both alexandria and trantor
- Service routing based on visibility flags (public/LAN/Tailscale)
- Split-horizon DNS for optimal access paths
### Security
- LUKS full-disk encryption on desktop systems
- Fail2ban on public-facing servers
- agenix for secrets management
- Tailscale for secure remote access
### Desktop Environment
- Custom Niri window manager (Wayland compositor)
- Using forked version with auto-centering feature
- Stylix for consistent theming
### Development Setup
- Nix flakes for reproducible builds
- deploy-rs for automated deployments
- Podman for containerization
- Complete AI tooling integration

View file

@ -1,15 +1,11 @@
age-encryption.org/v1
-> ssh-ed25519 Kfdnog HMpl/3mb59SsUvkDXXxO+odBNSc1dZS1nQtC8/BPlGI
4fPk0YtGxOoqXDfTN9kQlH0Pg2iaJXUZE5es6f317L4
-> ssh-ed25519 SP9f6A p1kh6UOFJ4xwulLY9IpbNZIJ7JSouR27j6HgK/XRegM
rJCzN+RCdQgo/xCkAmcdN6GfXsoQhpmE1HuGwYs/2CI
-> ssh-ed25519 8YSAiw cCbMOE3PMa3bzGGQSeQZuq074iwt4p4HLDu8uiHhWRY
U6wR/DuBdMKfbmQfUZ8XLdTBxNsUMR2lOueYucR5+bY
-> ssh-ed25519 7cojTQ iLDzC79YtZcrqldzCyIFHrpsEapOXYD5AXuNoQ+3ulI
v2NiE3pA+J8Po+PqTTUU9XYKy37AIyj5KWdlh7FOPG8
-> ssh-ed25519 J6tVTA Jw1pSpF1J2Ud46BDhdRCPErgUeim8uwWxiB1E3BiJB8
hGdGFi46iqKJN0QviG1xRNf2kwlls0rM5k3LkAiw8jY
-> ssh-ed25519 Kl5yTQ yXnKCsJNjTSQYiPuv6dAF6raB3EFcg2oag1cBVkdvwk
0hwjrZpclTrFWtr5JqAbwXImYzZwTJOJPkhNnlHmPeo
--- k97ZU6FfTWVqBwNcrF9QeEbnqnuQUQ9pR1qM/Sgjh7A
#Ž©L-qï¹hr­÷&§ý*Åáh¢¡NÂb®qÒܦHÅ G=@öâ¿uak”u™r^£BOoÔ}:Æ5ju€Å$%®¼éË".A1ÿäqŽP\Œ2CÏä RŽÜ¤¨¶_ Sû²‰=”(Æ%sÞ¨†ó§Çï£ß
-> ssh-ed25519 Kfdnog IHXv4c5we36dCUsB1v8uEF23tIRlDQ/8WR1hX4GQ+Uc
Cwccw64BYBdSZUdkSqKESIU7E17cLNtiAZZ3Y1xV87A
-> ssh-ed25519 8YSAiw Ce3vdMG111ubjcFgd3+q2Qw2+7dsoUz7SiudtuLDr0Y
JUodwFsKfOTZXxFyRrEk/4gxJ4goPkwvYeThi893M0U
-> ssh-ed25519 J6tVTA bExFuITTGXkTvhW25nushN7zT/PJGDoezsqu7fLKemI
4a90v0F4wgcZeqWBQ/EpqOZ9OCgT7qruwVvlGZeFmN8
-> ssh-ed25519 Qt3Q+A j1oo46pNh1+yPEtxpgj+QPQPf5m82jL0DHGMacY8UFA
vy52Hl1WLTdKNA8+4p7A48Sg9+QkMXbECf/uxVMCLYk
--- 429vzgFnmFbEqDMwdvC0/EYDJlKU64YEGgE0AqPqlBs
čď¬<E280BA>÷€b‰/!8Očô3Df®/ľŹ&kNQhuůr“t¤%&]ł˛ÎŐŇÖucÚjŮHĆ]Ż_łž¨ë5@D$<1C>>éN8Ϧ >Ť9:®CvĐѦ69W'X·]X^çŰĆ»$Ť§}|cš÷ă/ž ߸={ľuÉłs

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,29 +1,35 @@
let
io-user = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO3Y0PVpGfJHonqDS7qoCFhqzUvqGq9I9sax+F9e/5cs";
io-host = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKCIrKJk5zWzWEHvLMPMK8T3PyeBjsCsqzxPN+OrXfhA";
io = [
io-user
io-host
];
io-user = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO3Y0PVpGfJHonqDS7qoCFhqzUvqGq9I9sax+F9e/5cs user@io";
io = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKCIrKJk5zWzWEHvLMPMK8T3PyeBjsCsqzxPN+OrXfhA root@io";
rotterdam-user = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL";
rotterdam-host = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIjXcqQqlu03x2VVTdWOyxtKRszXAKX0AxTkGvF1oeJL";
rotterdam = [
rotterdam-user
rotterdam-host
];
rotterdam-user = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL user@rotterdam";
rotterdam = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIjXcqQqlu03x2VVTdWOyxtKRszXAKX0AxTkGvF1oeJL root@rotterdam";
alexandria-host = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK95QueW+jp1ZmF299Xr3XkgHJ6dL7aZVsfWxqbOKVKA";
alexandria = [ alexandria-host ];
alexandria = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK95QueW+jp1ZmF299Xr3XkgHJ6dL7aZVsfWxqbOKVKA root@alexandria";
trantor-host = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINkGuGLZPnYJbCGY4BhJ9uTupp6ruuR1NZ7FEYEaLPA7";
trantor = [ trantor-host ];
desktops = io ++ rotterdam;
servers = alexandria ++ trantor;
all-hosts = desktops ++ servers;
trantor = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIh/2u5pr/iPVeavlsor5hbTtsgUfP1JpzZVco2YQAo3 root@trantor";
in
{
"cloudflare.age".publicKeys = all-hosts;
"webdav.age".publicKeys = all-hosts;
"cloudflare.age".publicKeys = [
io-user
rotterdam-user
alexandria
trantor
];
"nextcloud-adminpass.age".publicKeys = [
io-user
rotterdam-user
alexandria
];
"nextcloud-secrets.json.age".publicKeys = [
io-user
rotterdam-user
alexandria
];
"forgejo-root-password.age".publicKeys = [
io-user
rotterdam-user
trantor
];
}

View file

@ -1,15 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 Kfdnog 9oKx6Oz/J/QJ0mmgoLX5AUx0sFdxnPVnjF42bElPSXA
BJ6h4lHGDsf1Npc4bwkvz5htGRT/x/b2bs9WFM2W/pc
-> ssh-ed25519 SP9f6A T5t4apynXLYN/4YEvaHRCI28rrKzet4r6LrbAye5VGk
BsXkZYBxG9zcfLYCd9H0+LW078oCDyYx9zG+DPfE7bA
-> ssh-ed25519 8YSAiw RY0YR30qyJPvhy7eTJLoj2JXpH9qHP43fJaHilJykXM
E5/P0Egz/LKwEhYLYd5Cnrat47gnYn93yDSeYgLi934
-> ssh-ed25519 7cojTQ qTCTw7CjilThFLmXYph4YhVBhnk1DpnFCGwgioo/XB0
N31nZ8nInQuddLD3b0bxI5Es/pTvTQD8nz0f/AZtNFg
-> ssh-ed25519 J6tVTA 7OawDsWwtVxu76ZgF0dFclMr19sBNdtu7H+Tr7Pd+SQ
hhVKcscIKIH1WChhRo/RYqUWy1rgs/EKnlHr9uY7QrQ
-> ssh-ed25519 Kl5yTQ +i2Q3uNHw1jAVH76NHy4QbjCc6sBBYjsbr7w4mLaHW4
JOJ02zU0+IxlbXMBsW4UrvzvLUbifdzABBNL+bc0bBs
--- W40oEFdBUKbi0teNTc6B1sX0ReHDvkIJcBm1dlROnk8
zÒ¼ÆCnçç®±àÈeÓ­ù7{ïÛé{Nðì§ä³6ê•azÁ"ÒÉE¯HB/¢BYbD

48
shared/services.nix Normal file
View file

@ -0,0 +1,48 @@
# Shared service definitions for cross-host configuration
# Used by:
# - alexandria: DNS server (LAN) + service hosting (vaultwarden, nextcloud, jellyfin, kanidm)
# - trantor: DNS server (Tailnet) + service hosting (forgejo)
{
services = [
{
name = "kanidm";
domain = "auth.baduhai.dev";
host = "alexandria";
lanIP = "192.168.15.142";
tailscaleIP = "100.76.19.50";
port = 8443;
}
{
name = "vaultwarden";
domain = "pass.baduhai.dev";
host = "alexandria";
lanIP = "192.168.15.142";
tailscaleIP = "100.76.19.50";
port = 8222;
}
{
name = "forgejo";
domain = "git.baduhai.dev";
host = "trantor";
public = true;
tailscaleIP = "100.108.5.90";
port = 3000;
}
{
name = "nextcloud";
domain = "cloud.baduhai.dev";
host = "alexandria";
lanIP = "192.168.15.142";
tailscaleIP = "100.76.19.50";
port = 443;
}
{
name = "jellyfin";
domain = "jellyfin.baduhai.dev";
host = "alexandria";
lanIP = "192.168.15.142";
tailscaleIP = "100.76.19.50";
port = 8096;
}
];
}

View file

@ -0,0 +1,86 @@
# 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
inherit (import ../../shared/services.nix) 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

258
terranix/oci/trantor.nix Normal file
View file

@ -0,0 +1,258 @@
# 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";
};
};
}

View file

@ -0,0 +1,43 @@
# 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"
];
};
};
}

View file

@ -0,0 +1,27 @@
{ 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;
};
};
};
}

7
users/modules/comma.nix Normal file
View file

@ -0,0 +1,7 @@
{ inputs, ... }:
{
imports = [ inputs.nix-index-database.homeModules.nix-index ];
programs.nix-index-database.comma.enable = true;
}

View file

@ -3,7 +3,10 @@
{
programs.fish = {
enable = true;
interactiveShellInit = "${lib.getExe pkgs.nix-your-shell} fish | source";
interactiveShellInit = ''
set fish_greeting
${lib.getExe pkgs.nix-your-shell} fish | source
'';
loginShellInit = "${lib.getExe pkgs.nix-your-shell} fish | source";
plugins = [
{
@ -15,24 +18,15 @@
sha256 = "sha256-A8ydBX4LORk+nutjHurqNNWFmW6LIiBPQcxS3x4nbeQ=";
};
}
{
name = "sponge";
src = pkgs.fetchFromGitHub {
owner = "meaningful-ooo";
repo = "sponge";
rev = "384299545104d5256648cee9d8b117aaa9a6d7be";
sha256 = "sha256-MdcZUDRtNJdiyo2l9o5ma7nAX84xEJbGFhAVhK+Zm1w=";
};
}
{
name = "z";
src = pkgs.fetchFromGitHub {
owner = "jethrokuan";
repo = "z";
rev = "85f863f20f24faf675827fb00f3a4e15c7838d76";
sha256 = "sha256-+FUBM7CodtZrYKqU542fQD+ZDGrd2438trKM0tIESs0=";
rev = "067e867debee59aee231e789fc4631f80fa5788e";
sha256 = "sha256-emmjTsqt8bdI5qpx1bAzhVACkg0MNB/uffaRjjeuFxU=";
};
}
];
};
}
}

View file

@ -1,56 +0,0 @@
{ inputs, pkgs, ... }:
{
imports = [ inputs.dms.homeModules.dankMaterialShell.default ];
fonts.fontconfig.enable = true;
programs = {
dankMaterialShell = {
enable = true;
enableVPN = false;
};
rio = {
enable = true;
settings = {
theme = "catppuccin-mocha";
fonts = {
family = "FiraCode Nerd Font";
size = 16.0;
emoji.family = "Noto Color Emoji";
};
confirm-before-quit = false;
window = {
width = 1121;
height = 633;
};
};
};
password-store = {
enable = true;
package = pkgs.pass-wayland;
};
};
xdg.portal = {
enable = true;
xdgOpenUsePortal = true;
extraPortals = with pkgs; [
kdePackages.xdg-desktop-portal-kde
xdg-desktop-portal-gtk
xdg-desktop-portal-gnome
];
};
gtk = {
enable = true;
gtk3.extraConfig = {
gtk-decoration-layout = "appmenu:";
};
gtk4.extraConfig = {
gtk-decoration-layout = "appmenu:";
};
};
}

View file

@ -0,0 +1,132 @@
{
inputs,
pkgs,
...
}:
{
imports = [ inputs.vicinae.homeManagerModules.default ];
fonts.fontconfig.enable = true;
home.packages = with pkgs; [ xwayland-satellite ];
services.vicinae = {
enable = true;
autoStart = true;
};
programs = {
ghostty = {
enable = true;
settings = {
cursor-style = "block";
shell-integration-features = "no-cursor";
cursor-style-blink = false;
custom-shader = "${builtins.fetchurl {
url = "https://raw.githubusercontent.com/hackr-sh/ghostty-shaders/cb6eb4b0d1a3101c869c62e458b25a826f9dcde3/cursor_blaze.glsl";
sha256 = "sha256:0g2lgqjdrn3c51glry7x2z30y7ml0y61arl5ykmf4yj0p85s5f41";
}}";
bell-features = "";
gtk-titlebar-style = "tabs";
keybind = [ "shift+enter=text:\\x1b\\r" ];
};
};
password-store = {
enable = true;
package = pkgs.pass-wayland;
};
};
xdg = {
enable = true;
userDirs.enable = true;
mimeApps = {
enable = true;
defaultApplications = {
"text/html" = [
"re.sonny.Junction.desktop"
"zen-browser.desktop"
"torbrowser.desktop"
];
"x-scheme-handler/http" = [
"re.sonny.Junction.desktop"
"zen-browser.desktop"
"torbrowser.desktop"
];
"x-scheme-handler/https" = [
"re.sonny.Junction.desktop"
"zen-browser.desktop"
"torbrowser.desktop"
];
"x-scheme-handler/about" = [
"re.sonny.Junction.desktop"
"zen-browser.desktop"
"torbrowser.desktop"
];
"x-scheme-handler/unknown" = [
"re.sonny.Junction.desktop"
"zen-browser.desktop"
"torbrowser.desktop"
];
"image/jpeg" = "org.gnome.Loupe.desktop";
"image/png" = "org.gnome.Loupe.desktop";
"image/gif" = "org.gnome.Loupe.desktop";
"image/webp" = "org.gnome.Loupe.desktop";
"image/bmp" = "org.gnome.Loupe.desktop";
"image/svg+xml" = "org.gnome.Loupe.desktop";
"image/tiff" = "org.gnome.Loupe.desktop";
"video/mp4" = "io.bassi.Showtime.desktop";
"video/x-matroska" = "io.bassi.Showtime.desktop";
"video/webm" = "io.bassi.Showtime.desktop";
"video/mpeg" = "io.bassi.Showtime.desktop";
"video/x-msvideo" = "io.bassi.Showtime.desktop";
"video/quicktime" = "io.bassi.Showtime.desktop";
"video/x-flv" = "io.bassi.Showtime.desktop";
"audio/mpeg" = "io.bassi.Showtime.desktop";
"audio/flac" = "io.bassi.Showtime.desktop";
"audio/ogg" = "io.bassi.Showtime.desktop";
"audio/wav" = "io.bassi.Showtime.desktop";
"audio/mp4" = "io.bassi.Showtime.desktop";
"audio/x-opus+ogg" = "io.bassi.Showtime.desktop";
"application/pdf" = [
"org.gnome.Papers.desktop"
"zen-browser.desktop"
];
"text/plain" = "Helix.desktop";
"text/markdown" = "Helix.desktop";
"text/x-log" = "Helix.desktop";
"application/x-shellscript" = "Helix.desktop";
"application/vnd.openxmlformats-officedocument.wordprocessingml.document" =
"onlyoffice-desktopeditors.desktop"; # DOCX
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" =
"onlyoffice-desktopeditors.desktop"; # XLSX
"application/vnd.openxmlformats-officedocument.presentationml.presentation" =
"onlyoffice-desktopeditors.desktop"; # PPTX
"application/vnd.oasis.opendocument.text" = "onlyoffice-desktopeditors.desktop"; # ODT
"application/vnd.oasis.opendocument.spreadsheet" = "onlyoffice-desktopeditors.desktop"; # ODS
"application/vnd.oasis.opendocument.presentation" = "onlyoffice-desktopeditors.desktop"; # ODP
"application/msword" = "onlyoffice-desktopeditors.desktop"; # DOC
"application/vnd.ms-excel" = "onlyoffice-desktopeditors.desktop"; # XLS
"application/vnd.ms-powerpoint" = "onlyoffice-desktopeditors.desktop"; # PPT
"application/zip" = "org.gnome.FileRoller.desktop";
"application/x-tar" = "org.gnome.FileRoller.desktop";
"application/x-compressed-tar" = "org.gnome.FileRoller.desktop";
"application/x-bzip-compressed-tar" = "org.gnome.FileRoller.desktop";
"application/x-xz-compressed-tar" = "org.gnome.FileRoller.desktop";
"application/x-7z-compressed" = "org.gnome.FileRoller.desktop";
"application/x-rar" = "org.gnome.FileRoller.desktop";
"application/gzip" = "org.gnome.FileRoller.desktop";
"application/x-bzip" = "org.gnome.FileRoller.desktop";
"inode/directory" = "org.gnome.Nautilus.desktop";
};
};
};
# Set Ghostty as default terminal
home.sessionVariables = {
TERMINAL = "ghostty";
};
}

View file

@ -0,0 +1,229 @@
{
inputs,
lib,
pkgs,
hostname ? null,
...
}:
let
isRotterdam = hostname == "rotterdam";
in
{
imports = [ inputs.noctalia.homeModules.default ];
services.kanshi = {
enable = true;
settings = [
{
profile.name = "default";
profile.outputs = [
{
criteria = "*";
scale = 1.0;
}
];
}
];
};
home = {
packages = with pkgs; [
xwayland-satellite
inputs.noctalia.packages.${pkgs.system}.default
];
sessionVariables.QT_QPA_PLATFORMTHEME = "gtk3";
};
xdg.configFile."niri/config.kdl".text = ''
input {
keyboard {
xkb {
layout "us"
variant "altgr-intl"
}
}
touchpad {
tap
dwt
drag true
drag-lock
natural-scroll
accel-speed 0.2
accel-profile "flat"
scroll-method "two-finger"
middle-emulation
}
mouse {
natural-scroll
accel-speed 0.2
accel-profile "flat"
}
warp-mouse-to-focus mode="center-xy"
focus-follows-mouse
}
layout {
gaps 8
center-focused-column "never"
auto-center-when-space-available
preset-column-widths {
${
if isRotterdam then
''
proportion 0.33333
proportion 0.5
proportion 0.66667
''
else
''
proportion 0.5
proportion 1.0
''
}
}
default-column-width { proportion ${if isRotterdam then "0.33333" else "0.5"}; }
focus-ring {
off
}
border {
width 4
active-color "#ffc87f"
inactive-color "#505050"
urgent-color "#9b0000"
}
tab-indicator {
width 4
gap 4
place-within-column
}
}
overview {
zoom 0.65
}
spawn-at-startup "noctalia-shell" "-d"
layer-rule {
match namespace="^wallpaper$"
place-within-backdrop true
}
layer-rule {
match namespace="^quickshell-overview$"
place-within-backdrop true
}
hotkey-overlay {
skip-at-startup
}
prefer-no-csd
screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png"
animations {
slowdown 0.3
}
window-rule {
match app-id="zen"
default-column-width { proportion ${if isRotterdam then "0.5" else "1.0"}; }
}
window-rule {
geometry-corner-radius 12
clip-to-geometry true
}
config-notification {
disable-failed
}
binds {
Alt+Space repeat=false { spawn "vicinae" "toggle"; }
XF86AudioRaiseVolume allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "volume" "increase"; }
XF86AudioLowerVolume allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "volume" "decrease"; }
XF86AudioMute allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "volume" "muteOutput"; }
XF86MonBrightnessUp allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "brightness" "increase"; }
XF86MonBrightnessDown allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "brightness" "decrease"; }
XF86AudioPlay allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "play-pause"; }
XF86AudioStop allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "stop"; }
XF86AudioPrev allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "previous"; }
XF86AudioNext allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "next"; }
Mod+V repeat=false { spawn "vicinae" "vicinae://extensions/vicinae/clipboard/history"; }
Mod+Shift+L repeat=false { spawn "noctalia-shell" "ipc" "call" "lockScreen" "lock"; }
Mod+Return { spawn "ghostty"; }
Ctrl+Alt+Shift+A allow-when-locked=true { spawn "toggleaudiosink"; }
Mod+W repeat=false { toggle-overview; }
Mod+Q { close-window; }
Alt+Shift+Q { close-window;}
Mod+Shift+Q { close-window; }
Alt+F4 { close-window; }
Mod+Left { focus-column-left; }
Mod+Down { focus-window-or-workspace-down; }
Mod+Up { focus-window-or-workspace-up; }
Mod+Right { focus-column-right; }
Mod+H { focus-column-left; }
Mod+L { focus-column-right; }
Mod+J { focus-window-or-workspace-down; }
Mod+K { focus-window-or-workspace-up; }
Mod+Ctrl+Left { move-column-left; }
Mod+Ctrl+Down { move-window-down-or-to-workspace-down; }
Mod+Ctrl+Up { move-window-up-or-to-workspace-up; }
Mod+Ctrl+Right { move-column-right; }
Mod+Ctrl+H { move-column-left; }
Mod+Ctrl+J { move-window-down-or-to-workspace-down; }
Mod+Ctrl+K { move-window-up-or-to-workspace-up; }
Mod+Ctrl+L { move-column-right; }
Mod+Home { focus-column-first; }
Mod+End { focus-column-last; }
Mod+Ctrl+Home { move-column-to-first; }
Mod+Ctrl+End { move-column-to-last; }
Mod+Alt+Left { focus-monitor-left; }
Mod+Alt+Down { focus-monitor-down; }
Mod+Alt+Up { focus-monitor-up; }
Mod+Alt+Right { focus-monitor-right; }
Mod+Alt+H { focus-monitor-left; }
Mod+Alt+J { focus-monitor-down; }
Mod+Alt+K { focus-monitor-up; }
Mod+Alt+L { focus-monitor-right; }
Mod+Alt+Ctrl+Left { move-column-to-monitor-left; }
Mod+Alt+Ctrl+Down { move-column-to-monitor-down; }
Mod+Alt+Ctrl+Up { move-column-to-monitor-up; }
Mod+Alt+Ctrl+Right { move-column-to-monitor-right; }
Mod+Alt+Ctrl+H { move-column-to-monitor-left; }
Mod+Alt+Ctrl+J { move-column-to-monitor-down; }
Mod+Alt+Ctrl+K { move-column-to-monitor-up; }
Mod+Alt+Ctrl+L { move-column-to-monitor-right; }
Mod+Ctrl+U { move-workspace-down; }
Mod+Ctrl+I { move-workspace-up; }
Mod+WheelScrollDown cooldown-ms=150 { focus-workspace-down; }
Mod+WheelScrollUp cooldown-ms=150 { focus-workspace-up; }
Mod+Ctrl+WheelScrollDown cooldown-ms=150 { move-column-to-workspace-down; }
Mod+Ctrl+WheelScrollUp cooldown-ms=150 { move-column-to-workspace-up; }
Mod+Shift+WheelScrollDown { focus-column-right; }
Mod+Shift+WheelScrollUp { focus-column-left; }
Mod+Ctrl+Shift+WheelScrollDown { move-column-right; }
Mod+Ctrl+Shift+WheelScrollUp { move-column-left; }
Mod+BracketLeft { consume-or-expel-window-left; }
Mod+BracketRight { consume-or-expel-window-right; }
Mod+Comma { consume-window-into-column; }
Mod+Period { expel-window-from-column; }
Mod+R { switch-preset-column-width; }
Mod+F { maximize-column; }
Mod+Ctrl+F { fullscreen-window; }
Mod+C { center-visible-columns; }
Mod+Ctrl+C { center-column; }
Mod+Space { toggle-window-floating; }
Mod+Ctrl+Space { switch-focus-between-floating-and-tiling; }
Mod+T { toggle-column-tabbed-display; }
Print { screenshot-screen; }
Mod+Print { screenshot; }
Ctrl+Print { screenshot-window; }
Mod+Backspace allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; }
Mod+Alt+E { spawn "noctalia-shell" "ipc" "call" "sessionMenu" "toggle"; }
Ctrl+Alt+Delete { spawn "noctalia-shell" "ipc" "call" "sessionMenu" "toggle"; }
Mod+Ctrl+P { power-off-monitors; }
}
'';
}

View file

@ -8,13 +8,12 @@
programs.helix = {
enable = true;
settings = {
theme = "base16_transparent";
editor = {
file-picker.hidden = false;
idle-timeout = 0;
line-number = "relative";
cursor-shape = {
normal = "block";
normal = "underline";
insert = "bar";
select = "underline";
};
@ -47,4 +46,4 @@
];
};
};
}
}

View file

@ -13,10 +13,10 @@
'';
right_format = "$cmd_duration$character";
hostname = {
ssh_symbol = " ";
ssh_symbol = "󰖟 ";
};
character = {
error_symbol = "[](red)";
error_symbol = "[](red)";
success_symbol = "[󱐋](green)";
};
cmd_duration = {
@ -25,7 +25,7 @@
min_time = 500;
};
git_branch = {
symbol = " ";
symbol = " ";
style = "purple";
};
git_status.style = "red";
@ -37,4 +37,4 @@
};
};
};
}
}

69
users/modules/stylix.nix Normal file
View file

@ -0,0 +1,69 @@
{
config,
inputs,
pkgs,
...
}:
{
imports = [
inputs.stylix.homeModules.stylix
inputs.zen-browser.homeModules.beta
];
stylix = {
enable = true;
polarity = "dark";
base16Scheme = "${pkgs.base16-schemes}/share/themes/tokyodark.yaml";
cursor = {
package = pkgs.kdePackages.breeze;
name = "breeze_cursors";
size = 24;
};
icons = {
enable = true;
package = pkgs.morewaita-icon-theme;
light = "MoreWaita";
dark = "MoreWaita";
};
opacity = {
applications = 1.0;
desktop = 0.8;
popups = config.stylix.opacity.desktop;
terminal = 1.0;
};
fonts = {
serif = {
package = pkgs.source-serif;
name = "Source Serif 4 Display";
};
sansSerif = {
package = pkgs.inter;
name = "Inter";
};
monospace = {
package = pkgs.nerd-fonts.fira-code;
name = "FiraCode Nerd Font";
};
emoji = {
package = pkgs.noto-fonts-color-emoji;
name = "Noto Color Emoji";
};
sizes = {
applications = 10;
desktop = config.stylix.fonts.sizes.applications;
popups = config.stylix.fonts.sizes.applications;
terminal = 12;
};
};
targets.zen-browser = {
enable = true;
profileNames = [ "william" ];
};
};
programs.zen-browser = {
enable = true;
profiles.william = { };
};
}

View file

@ -1,10 +1,17 @@
{ pkgs, ... }:
{
programs.git = {
enable = true;
diff-so-fancy.enable = true;
userName = "William";
userEmail = "baduhai@proton.me";
programs = {
git = {
enable = true;
settings.user = {
name = "William";
email = "baduhai@proton.me";
};
};
diff-so-fancy = {
enable = true;
enableGitIntegration = true;
};
};
}
}

View file

@ -1,4 +1,5 @@
{ inputs, lib }:
let
inherit (inputs)
self
@ -7,8 +8,14 @@ let
home-manager
agenix
;
# Import shared service definitions
sharedServices = import ./shared/services.nix;
in
{
# Re-export shared services for use in host configs
inherit (sharedServices) services;
# Tag-based host configuration system
mkHost =
{
@ -97,9 +104,10 @@ in
};
# Tag-based user configuration system
mkUser =
mkHome =
{
username,
hostname ? null,
homeDirectory ? "/home/${username}",
tags ? [ ],
extraModules ? [ ],
@ -163,7 +171,7 @@ in
home-manager.lib.homeManagerConfiguration {
inherit pkgs;
extraSpecialArgs = {
inherit inputs;
inherit inputs hostname;
userTags = allTags;
};
modules = allModules ++ [
@ -175,16 +183,41 @@ in
# Nginx virtual host utilities
mkNginxVHosts =
{
acmeHost,
domains,
}:
{ domains }:
let
commonVHostConfig = {
useACMEHost = acmeHost;
forceSSL = true;
kTLS = true;
};
# Extract domain name and apply it as useACMEHost
mkVHostConfig = domain: config:
lib.recursiveUpdate {
useACMEHost = domain;
forceSSL = true;
kTLS = true;
} config;
in
lib.mapAttrs (_: lib.recursiveUpdate commonVHostConfig) domains;
lib.mapAttrs mkVHostConfig domains;
# Split DNS utilities for unbound
# Generates unbound view config from a list of DNS entries
mkSplitDNS =
entries:
let
# Generate local-data entries for all domains
tailscaleData = map (e: ''"${e.domain}. IN A ${e.tailscaleIP}"'') entries;
lanData = map (e: ''"${e.domain}. IN A ${e.lanIP}"'') entries;
in
[
# Single Tailscale view with all domains
{
name = "tailscale";
view-first = true;
local-zone = ''"baduhai.dev." transparent'';
local-data = tailscaleData;
}
# Single LAN view with all domains
{
name = "lan";
view-first = true;
local-zone = ''"baduhai.dev." transparent'';
local-data = lanData;
}
];
}