feat: deployed frontend, postgres, rev-proxy, tailscale config, initialisation scripts

This commit is contained in:
Luka Dekanozishvili 2026-01-31 14:28:52 +01:00
parent f48059e37e
commit a24fd5bd93
20 changed files with 413 additions and 262 deletions

View file

@ -9,6 +9,7 @@
environment.systemPackages = with pkgs; [
hexname-backend
deno
];
users.users = {
@ -21,6 +22,7 @@
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM/4F45h/xkq+MIRDzhHqDm5uWM4KTpYi3Tv/DtSo28t luka@gram"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF7OvW6MffYFshZyarEaWvWjEmhodn/P+NLcnqbbMpma luka@conway"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIT+vMzh2ngUeqnVJS8Zl1m1HQMBkDOqoGdoARPyJgDM u0_a380@localhost" # s
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAmMXGO8HuFS9SRbIDRDGMVgyiR0hy7uL9VkL5BOcgkw luka@thinkway" # w
];
};
root = {

132
flake.lock generated
View file

@ -1,5 +1,24 @@
{
"nodes": {
"deno2nix": {
"inputs": {
"flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1767824708,
"narHash": "sha256-UL8Jdh4UoBc25nyq9xkAMnqT1886DzymPbhI4/+/KUQ=",
"owner": "Makesesama",
"repo": "deno2nix",
"rev": "e1b0a16c6148991f3d9e902b68aa1cb532173b8a",
"type": "github"
},
"original": {
"owner": "Makesesama",
"repo": "deno2nix",
"type": "github"
}
},
"fenix": {
"inputs": {
"nixpkgs": [
@ -41,6 +60,24 @@
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"hexname-backend": {
"inputs": {
"flake-utils": "flake-utils",
@ -48,11 +85,11 @@
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1769444495,
"narHash": "sha256-8dC6d0XedjH+3YIxUb9PMzr1WhHzwxi5tsFLTkM0bss=",
"lastModified": 1769526729,
"narHash": "sha256-/ew2cd+lz9xOkTLsYZLqYKfnOoxqlAhpRR7jAqOUljc=",
"ref": "refs/heads/main",
"rev": "5be98605494183210469cf5ad3be211dd0e3f18e",
"revCount": 20,
"rev": "59180721d3b95f28c17eff9e3a18e54b0a1fa588",
"revCount": 23,
"type": "git",
"url": "ssh://forgejo@git.lukadeka.com:6968/LukaDeka/HexName-Backend.git"
},
@ -61,6 +98,25 @@
"url": "ssh://forgejo@git.lukadeka.com:6968/LukaDeka/HexName-Backend.git"
}
},
"hexname-frontend": {
"inputs": {
"deno2nix": "deno2nix",
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1769709099,
"narHash": "sha256-Y5uALgdWMSRp8rqFFiv+iQCcs/HLoYvl0KxFaqNqlGE=",
"ref": "refs/heads/main",
"rev": "bbbb5e9f5ba8f5c18415b4ca5c03d57e45937095",
"revCount": 18,
"type": "git",
"url": "ssh://forgejo@git.lukadeka.com:6968/LukaDeka/HexName-Frontend.git"
},
"original": {
"type": "git",
"url": "ssh://forgejo@git.lukadeka.com:6968/LukaDeka/HexName-Frontend.git"
}
},
"naersk": {
"inputs": {
"fenix": "fenix",
@ -85,11 +141,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1769330179,
"narHash": "sha256-yxgb4AmkVHY5OOBrC79Vv6EVd4QZEotqv+6jcvA212M=",
"lastModified": 1769527094,
"narHash": "sha256-xV20Alb7ZGN7qujnsi5lG1NckSUmpIb05H2Xar73TDc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "48698d12cc10555a4f3e3222d9c669b884a49dfe",
"rev": "afce96367b2e37fc29afb5543573cd49db3357b7",
"type": "github"
},
"original": {
@ -101,11 +157,11 @@
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1769318308,
"narHash": "sha256-Mjx6p96Pkefks3+aA+72lu1xVehb6mv2yTUUqmSet6Q=",
"lastModified": 1769598131,
"narHash": "sha256-e7VO/kGLgRMbWtpBqdWl0uFg8Y2XWFMdz0uUJvlML8o=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "1cd347bf3355fce6c64ab37d3967b4a2cb4b878c",
"rev": "fa83fd837f3098e3e678e6cf017b2b36102c7211",
"type": "github"
},
"original": {
@ -117,11 +173,43 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1769170682,
"narHash": "sha256-oMmN1lVQU0F0W2k6OI3bgdzp2YOHWYUAw79qzDSjenU=",
"lastModified": 1767767207,
"narHash": "sha256-Mj3d3PfwltLmukFal5i3fFt27L6NiKXdBezC1EBuZs4=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "c5296fdd05cfa2c187990dd909864da9658df755",
"rev": "5912c1772a44e31bf1c63c0390b90501e5026886",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1769461804,
"narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1769461804,
"narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d",
"type": "github"
},
"original": {
@ -134,7 +222,8 @@
"root": {
"inputs": {
"hexname-backend": "hexname-backend",
"nixpkgs": "nixpkgs_2",
"hexname-frontend": "hexname-frontend",
"nixpkgs": "nixpkgs_4",
"nixpkgs-stable": "nixpkgs-stable"
}
},
@ -169,6 +258,21 @@
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",

View file

@ -6,13 +6,14 @@
nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-25.11";
hexname-backend.url = "git+ssh://forgejo@git.lukadeka.com:6968/LukaDeka/HexName-Backend.git";
hexname-frontend.url = "git+ssh://forgejo@git.lukadeka.com:6968/LukaDeka/HexName-Frontend.git";
};
outputs = { nixpkgs, nixpkgs-stable, hexname-backend, ... } @ inputs: {
outputs = { nixpkgs, nixpkgs-stable, hexname-backend, hexname-frontend, ... } @ inputs: {
nixosConfigurations = {
hexname-ns1 = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = { inherit inputs; inherit hexname-backend; };
specialArgs = { inherit inputs hexname-backend hexname-frontend; };
modules = [
######## Boilerplate ########
./configuration.nix
@ -21,15 +22,18 @@
./pkgs/extra.nix
######## HexName configuration ########
./pkgs/powerdns.nix
# ./pkgs/reverse-proxy.nix
./pkgs/nginx.nix
./pkgs/backend.nix
# ./pkgs/postgres.nix
./pkgs/powerdns.nix
./pkgs/postgres.nix
######## Networking ########
./pkgs/server-ssh.nix
./pkgs/nginx.nix
./pkgs/ssh.nix
./pkgs/tailscale.nix
./pkgs/virtualisation.nix
# ./pkgs/stalwart.nix
./pkgs/stalwart.nix
######## Sysadmin ########
./pkgs/neovim.nix
@ -39,8 +43,8 @@
######## etc. ########
######## Scripts ########
#./scripts/virtualisation/update-containers.nix # Runs podman pull weekly
#./scripts/virtualisation/restart-pihole.nix
./services/update-containers.nix # Runs podman pull weekly
./services/restart-powerdns.nix
];
};
};

View file

@ -27,6 +27,7 @@
User = "hexname-backend";
Group = "hexname";
Type = "simple";
Restart = "always";
ExecStart = "${pkgs.hexname-backend}/bin/dns-backend";
};
};

View file

@ -44,7 +44,7 @@
gc = {
automatic = true;
dates = "Mon *-*-* 16:00:00";
dates = "Sat *-*-* 10:00:00";
options = "--delete-older-than 90d";
};
};

42
pkgs/frontend.nix Normal file
View file

@ -0,0 +1,42 @@
{ pkgs, hexname-frontend, ... }:
{
nixpkgs.overlays = [
(self: super: {
hexname-frontend = hexname-frontend.packages.${super.stdenv.hostPlatform.system}.default;
})
];
users.groups.hexname = {};
users.users = {
hexname-frontend = {
group = "hexname";
isSystemUser = true;
createHome = true;
home = "/var/lib/hexname/frontend";
};
};
systemd.services.hexname-frontend = {
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
environment = {
ENV_PATH = "/etc/env/hexname/frontend.env";
NODE_ENV = "production";
};
serviceConfig = {
User = "hexname-backend";
Group = "hexname";
Type = "simple";
Restart = "always";
# ExecStart = "${hexname-frontend.packages.${pkgs.system}.default}/bin/hexname-frontend";
ExecStart = "env $(cat $ENV_PATH | xargs) ${pkgs.hexname-frontend}/bin/hexname-frontend";
};
# script = ''
# source /etc/env/hexname/frontend.env
# ${hexname-frontend.packages.${pkgs.system}.default}/bin/hexname-frontend
# '';
};
}

View file

@ -3,30 +3,49 @@
{
services.postgresql = {
enable = true;
settings = {
# Set hashing algorithm
password_encryption = "scram-sha-256";
# settings = {
# listen_addresses = lib.mkForce "127.0.0.1,10.89.0.10";
# };
# Replication conf
wal_level = "logical";
max_wal_senders = "5";
max_replication_slots = "5";
};
# Allow root to log in as postgres in the DB (for the PowerDNS container)
identMap = ''
postgres root postgres
'';
# identMap = ''
# postgres root postgres
# '';
authentication = lib.mkForce ''
# TYPE DATABASE USER ADDRESS AUTH-METHOD [auth-options]
host hexname-backend hexname-backend 127.0.0.1/24 scram-sha-256
# host all powerdns-user 127.0.0.1/24 scram-sha-256
# local all root trust
'';
ensureUsers = [ { name = "hexname-backend"; } ];
# No need to define the DB since `diesel` creates everything
# authentication = lib.mkForce ''
# # TYPE DATABASE USER ADDRESS AUTH-METHOD [auth-options]
# # host hexname-backend hexname-backend 127.0.0.1/24 scram-sha-256
# # host postgres postgres 127.0.0.1/24 scram-sha-256
# host all all 127.0.0.1/24 scram-sha-256
# # host all powerdns-user 127.0.0.1/24 scram-sha-256
# # local all root trust
# '';
# This password is only the initial one - don't get too excited
initialScript = pkgs.writeText "set-initial-password-script" ''
alter user hexname-backend with password 'shuaze-gagyof';
'';
initialScript = "/etc/env/hexname/init-db-dns.sql";
# initialScript = pkgs.writeText "set-initial-password-script" ''
# CREATE USER powerdns WITH PASSWORD 'shuaze-gagyof';
# CREATE USER hexname_backend WITH PASSWORD 'shuaze-gagyof2' CREATEDB;
# CREATE USER replication_user SUPERUSER WITH PASSWORD 'shuaze-gagyof3';
# CREATE DATABASE powerdns OWNER "powerdns";
# CREATE DATABASE hexname_backend OWNER "hexname-backend";
# CREATE DATABASE hexname_backend OWNER "hexname-backend";
# \c powerdns;
# CREATE PUBLICATION powerdns_pub FOR ALL TABLES;
# CREATE SUBSCRIPTION hexname_ns2
# CONNECTION 'host=publisher_ip_address port=5432 user=replication_user password=' ' dbname=powerdns'
# PUBLICATION powerdns_pub;
# '';
# ALTER USER "postgres" WITH PASSWORD 'shuaze-gagyof';
};
}

View file

@ -2,39 +2,17 @@
let
domain = "hexname.com";
dbIp = "10.89.0.25";
pdnsIp = "10.89.0.53";
# pdnsIp = "10.89.0.53";
in
{
virtualisation.oci-containers.containers = {
hexname-postgres = {
hostname = "pgsql";
image = "postgres:18-alpine";
ports = [
"127.0.0.1:5432:5432"
];
volumes = [
"pgsql:/var/lib/postgresql/data:Z"
"/etc/localtime:/etc/localtime:ro"
];
environment = {
POSTGRES_USER = "hexname-backend";
POSTGRES_PASSWORD = "EZQVObWjoEM7bldX2wu5oyJkgBIMfoU8OZZf";
};
networks = [ "hexname-net" ];
extraOptions = [
"--dns=10.89.0.1"
"--ip=${dbIp}"
];
};
hexname-powerdns = {
image = "pschiffe/pdns-pgsql:latest";
hostname = "ns1.${domain}";
ports = [
"127.0.0.1:8081:8081/tcp"
];
networks = [ "hexname-net" ];
# ports = [
# "127.0.0.1:8081:8081/tcp"
# ];
# networks = [ "hexname-net" ];
volumes = [
"/etc/localtime:/etc/localtime:ro"
@ -46,62 +24,60 @@ in
PDNS_api = "yes";
PDNS_disable_axfr = "yes";
#PDNS_webserver = "yes";
PDNS_webserver_address = "0.0.0.0";
PDNS_webserver_address = "127.0.0.1";
PDNS_webserver_port = "8081";
PDNS_local_address = "${pdnsIp}:53";
PDNS_webserver_allow_from = "10.89.0.0/24";
PDNS_local_address = "0.0.0.0:53";
PDNS_webserver_allow_from = "127.0.0.1/24";
PDNS_version_string = "anonymous";
PDNS_default_ttl = "3600";
# PDNS_gpgsql_password=...
# PDNS_api_key=...
# PDNS_gpgsql_host = "127.0.0.1";
# PDNS_gpgsql_port = "5432";
# PDNS_gpgsql_dbname = "powerdns";
# PDNS_gpgsql_user = "postgres";
# PDNS_gpgsql_password = "powerdns";
PDNS_gpgsql_host = "127.0.0.1";
PDNS_gpgsql_port = "5432";
PDNS_gpgsql_dbname = "powerdns";
PDNS_gpgsql_user = "powerdns";
PDNS_gpgsql_dnssec = "yes";
};
extraOptions = [
# "--network=host"
"--ip=${pdnsIp}"
"--add-host=pgsql:${dbIp}"
"--network=host"
];
dependsOn = [ "hexname-postgres" ];
# dependsOn = [ "hexname-postgres" ];
};
};
systemd.services.podman-network-hexname = {
description = "Podman network for HexName/PowerDNS";
after = [ "podman.service" ];
wantedBy = [ "multi-user.target" "podman-hexname-postgres.target" "podman-hexname-powerdns.target" ];
serviceConfig.Type = "oneshot";
path = [ pkgs.podman ] ;
script = ''
podman network inspect hexname-net >/dev/null 2>&1 || \
podman network create hexname-net --subnet 10.89.0.0/24
'';
};
# systemd.services.podman-network-hexname = {
# description = "Podman network for HexName/PowerDNS";
# after = [ "podman.service" ];
# wantedBy = [ "multi-user.target" "podman-hexname-postgres.target" "podman-hexname-powerdns.target" ];
# serviceConfig.Type = "oneshot";
# path = [ pkgs.podman ] ;
# script = ''
# podman network inspect hexname-net >/dev/null 2>&1 || \
# podman network create hexname-net --subnet 10.89.0.0/24
# '';
# };
# Bind port 53 and send all requests to the container
networking.nftables.enable = true;
networking.nftables.tables.dns = {
family = "inet";
content = ''
chain prerouting {
type nat hook prerouting priority -100;
# networking.nftables.enable = true;
# networking.nftables.tables.dns = {
# family = "inet";
# content = ''
# chain prerouting {
# type nat hook prerouting priority -100;
udp dport 53 dnat ip to ${pdnsIp}:53
tcp dport 53 dnat ip to ${pdnsIp}:53
}
# udp dport 53 dnat ip to ${pdnsIp}:53
# tcp dport 53 dnat ip to ${pdnsIp}:53
# }
chain postrouting {
type nat hook postrouting priority 100;
ip saddr 10.89.0.0/24 masquerade
}
'';
};
# chain postrouting {
# type nat hook postrouting priority 100;
# ip saddr 10.89.0.0/24 masquerade
# }
# '';
# };
networking.firewall.allowedTCPPorts = [ 53 ];
networking.firewall.allowedUDPPorts = [ 53 ];

33
pkgs/reverse-proxy.nix Normal file
View file

@ -0,0 +1,33 @@
{ config, pkgs, lib, ... }:
let
domain = "hexname.com";
in
{
services.nginx.virtualHosts = {
"${domain}" = {
forceSSL = true;
enableACME = true;
locations."/api" = {
proxyPass = "http://127.0.0.1:8080";
proxyWebsockets = true;
extraConfig = ''
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# add_header Strict-Transport-Security 'max-age=300; includeSubDomains; preload; always;'
'';
};
locations."/" = {
root = "/var/www/hexname/build";
tryFiles = "$uri $uri.html $uri/ /200.html";
};
};
"www.${domain}" = { # Redirect www to root
forceSSL = true;
enableACME = true;
globalRedirect = domain;
};
};
}

View file

@ -8,7 +8,7 @@
settings = {
PasswordAuthentication = false;
AllowUsers = [ "luka" ];
UseDns = false; # Disable checking of rDNS records to speed up login
UseDns = false; # Disable checking of rDNS records
X11Forwarding = false;
PermitRootLogin = "prohibit-password";
};
@ -20,11 +20,6 @@
# ignoreIP = [ ];
};
networking.firewall = {
enable = true;
# allowedTCPPorts = [ ];
# allowedUDPPorts = [];
};
networking.firewall.enable = true;
}

View file

@ -2,7 +2,7 @@
let
domain = "hexname.com";
stalwartDomain = "mail.${domain}";
stalwartDomain = "mx.${domain}";
roundcubeDomain = "email.${domain}";
dataDir = "/var/lib/stalwart-mail";
@ -59,22 +59,22 @@ in
principals = [
{
name = "contact-us@${domain}";
email = [ "contact-us@${domain}" "@${domain}" ];
secret = "$6$E8AhTdIdgl2ag6/x$reYvoPByjvkPK/Uwm3/481BBBkuBKQxd3rgSgQw3PawJ4G8TOt0jlIXdOo5xuDv1DQAdn52lUAgx0U9GSVoc7/";
email = [ "contact-us@${domain}" "privacy@${domain}" ];
secret = "$6$iyUwAnKuGTz31jeu$QPfoaUQPccVDWjCWs4PY43dBI6oG4eNb7buNlGBlnNJrvQOePYKyF8RXN8FI5H6y2x191kOa4U8aDD4K/ssKn/";
class = "individual";
}
{
name = "no-reply@${domain}";
email = [ "no-reply@${domain}" ];
secret = "$6$V/u1LImVZAyynuLO$l/mMaLWQ5t0jWz6XWNlHcha8nuTQbjQfES.Nj73mNS0xQjv3vu5z03fLMAt3hxAb5BwE3jgtfmh.PknBjM1M//";
secret = "$6$FpTIF6mjoBRXyZAO$9lqf/u3NyJNHYNutFY0WmPkbfkq8J.SIkhzya3izl7AbCRE72TlyKeGx/OOyPuI1QTMV10NgOEGzL8jboOWhZ1";
class = "individual";
}
];
};
authentication.fallback-admin = {
user = "superdupermegaadmin";
secret = "$6$LPDx0LFqtpAVJO2s$GPR/4Rguhmspy8OLLKI2oZxVgvWrlHRckd6WN2RZNMxkSN9YMiPJ/pfq.XD/VTKsqCu2GCnzerQOv5bivBCph.";
user = "unguessable-username";
secret = "$6$1sRTqTbiXuGNE3zt$oLcXi.kPsy72W5SDMwWSitpJyKlZSKSzhr1QO3DBn6Q9LSE.YpWUbT2Thu5Kbs0bmTMvqAPFI7x/qa1wm9Bj91";
};
email.folders = let
@ -92,28 +92,6 @@ in
trash = mkFolder "Trash";
};
session.rcpt = {
catch-all = true;
script = "'reject-addresses'";
};
sieve.trusted.scripts.reject-addresses.contents = ''
require ["envelope", "reject"];
if anyof (
envelope :is "to" "no-reply@${domain}"
envelope :is "to" "info@${domain}",
envelope :is "to" "contact@${domain}",
envelope :is "to" "support@${domain}"
envelope :is "to" "marketing@${domain}",
envelope :is "to" "sales@${domain}"
) {
reject "403 This address does not accept incoming mails.";
}
redirect "contact-us@${domain}";
'';
# Change the DNS records manually to these addresses to
# keep postmaster free for non-automated emails
# https://github.com/stalwartlabs/mail-server/discussions/877
@ -164,7 +142,7 @@ in
storage.blob = "fs";
# We have DANE and don't want a certificate for each domain
# session.mta-sts.mode = "none";
session.mta-sts.mode = "none";
certificate.default = {
cert = "%{file:${credPath}/cert.pem}%";
@ -249,24 +227,9 @@ in
security.acme.certs.${stalwartDomain} = {
# Keep a stable private key for TLSA records (DANE)
# https://community.letsencrypt.org/t/please-avoid-3-0-1-and-3-0-2-dane-tlsa-records-with-le-certificates/7022/14
# extraLegoRenewFlags = [ "--reuse-key" ];
extraLegoRenewFlags = [ "--reuse-key" ];
# Restart Stalwart to apply new certificates
reloadServices = [ "stalwart-mail.service" ];
};
# services.restic = {
# backupPrepareCommand = ''
# ${pkgs.coreutils}/bin/install -b -m 700 -d /tmp/stalwart-db-secondary /tmp/stalwart-db-backup
# ${lib.getExe' rocksdb.tools "ldb"} --db=${dataDir}/db --secondary_path=/tmp/stalwart-db-secondary backup --backup_dir=/tmp/stalwart-db-backup
# '';
# backupCleanupCommand = ''
# rm -rf /tmp/stalwart-db-secondary
# rm -rf /tmp/stalwart-db-backup
# '';
# paths = [
# "/tmp/stalwart-db-backup"
# "${dataDir}/blobs"
# ];
# };
}

View file

@ -1,23 +1,19 @@
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [ tailscale ];
services.tailscale = {
enable = true;
openFirewall = true;
useRoutingFeatures = "both"; # Act as a client and a server (exit node)
# extraSetFlags = [
# "--advertise-exit-node"
# ];
useRoutingFeatures = "client";
disableUpstreamLogging = true;
disableTaildrop = true;
};
environment.systemPackages = with pkgs; [ tailscale ];
# Enable IP forwarding for subnet routers
boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
# boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
# TODO: this fixes MagicDNS but breaks DNS resolution on LAN (Pihole)
# services.resolved.enable = true;

View file

@ -4,11 +4,6 @@
virtualisation.podman = {
enable = true;
# Disable netavark
# defaultNetwork.settings = {
# dns_enabled = false;
# };
# Auto-prune old containers
autoPrune = {
enable = true;

10
scripts/deploy-frontend.sh Executable file
View file

@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
cd /home/luka/HexName-Frontend
git pull
deno task build
sudo rm -rf /var/www/hexname/build
sudo cp -r build/ /var/www/hexname/

96
scripts/pdns-init-config-dns.sh Executable file
View file

@ -0,0 +1,96 @@
#!/usr/bin/env bash
set -euo pipefail
API_URL="http://127.0.0.1:8081/api/v1/servers/localhost/zones/hexname.com."
API_KEY="${API_KEY:?API_KEY not set}"
declare -A RRSETS
add_record() {
local type="$1"
local ttl="$2"
local name="$3"
local content="$4"
local key="${name}|${type}|${ttl}"
RRSETS["$key"]+="${content}"$'\n'
}
flush_rrsets() {
local rrsets_json="[]"
for key in "${!RRSETS[@]}"; do
IFS='|' read -r name type ttl <<<"$key"
local records_json
records_json=$(printf '%s' "${RRSETS[$key]}" \
| sed '/^$/d' \
| jq -R '{content: ., disabled: false}' \
| jq -s '.')
rrsets_json=$(jq \
--arg name "$name" \
--arg type "$type" \
--argjson ttl "$ttl" \
--argjson records "$records_json" \
'. + [{
name: $name,
type: $type,
ttl: $ttl,
changetype: "REPLACE",
records: $records
}]' <<<"$rrsets_json")
done
jq -n --argjson rrsets "$rrsets_json" '{ rrsets: $rrsets }' \
| curl -sS -X PATCH \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- \
"$API_URL"
}
add_record "NS" 604800 "hexname.com." "ns1.hexname.com."
add_record "NS" 604800 "hexname.com." "ns2.hexname.com."
add_record "A" 604800 "hexname.com." "188.245.239.209"
add_record "A" 604800 "ns1.hexname.com." "188.245.239.209"
add_record "A" 604800 "ns2.hexname.com." "91.99.69.65"
# Mailserver records
add_record "A" 3600 "mx.hexname.com." "188.245.239.209"
add_record "A" 3600 "email.hexname.com." "188.245.239.209"
add_record "A" 3600 "mta-sts.hexname.com." "188.245.239.209"
add_record "CNAME" 3600 "mail.hexname.com." "mx.hexname.com."
add_record "MX" 3600 "hexname.com." "10 mx.hexname.com."
add_record "TXT" 3600 "_mta-sts.hexname.com." "\"v=STSv1; id=20260127182600Z;\""
add_record "TXT" 3600 "202601e._domainkey.hexname.com." "\"v=DKIM1; k=ed25519; h=sha256; p=C30gZd1CbkUpIGInw/wZgZQD0pmUEnwTp+svCLm1oCk=\""
add_record "TXT" 3600 "202601r._domainkey.hexname.com." "\"v=DKIM1; k=rsa; h=sha256; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnyQRHisJtMpgRCAKAE5mfq63n1hvguiNheRrGWcLjEziA9r3M8oaxM71gDNeDEZj19yXlYBWlZZiPsdkMNsumFaElTt3E810JjZxvWslvRgCQ9qMK6lE4ytJZHXJD1a+g82/j4Pfu3C0iz0GfMvngXf03pDl5jWeScwfSFgvKx/0tRdzCAzwkSZfZaSKCh5bcvVwoxzXqHjz3zxwxDJGlUPoERymd18/7NkdRRfJZoqAo/aHdsh5JsYa8APtNIHjSjp2vUBPQnNrtx9+lI0qRnwdyrim8v8CRKin+QUW0sstWGuyqZxgxOGXO2Ek2fqTrpzVu2fu6pzGqJdbTVf5BQIDAQAB\""
add_record "TXT" 3600 "mx.hexname.com." "\"v=spf1 a ra=spf-reports -all\""
add_record "TXT" 3600 "hexname.com." "\"v=spf1 mx ra=spf-reports -all\""
add_record "TXT" 3600 "_dmarc.hexname.com." "\"v=DMARC1; p=reject; rua=mailto:dmarc-reports@hexname.com; ruf=mailto:dmarc-reports@hexname.com\""
add_record "TXT" 3600 "_smtp._tls.hexname.com." "\"v=TLSRPTv1; rua=mailto:tls-reports@hexname.com\""
add_record "SRV" 3600 "_imaps._tcp.hexname.com." "0 1 993 mx.hexname.com."
add_record "SRV" 3600 "_imap._tcp.hexname.com." "0 1 143 mx.hexname.com."
add_record "SRV" 3600 "_submissions._tcp.hexname.com." "0 1 465 mx.hexname.com."
add_record "SRV" 3600 "_submission._tcp.hexname.com." "0 1 587 mx.hexname.com."
add_record "TLSA" 3600 "_25._tcp.mx.hexname.com." "3 1 1 88151fff33b6c5b820d83b3030d55376f57085a154652a27089d9d9a71fe6a7e"
# Create the zone
curl -d '{
"name": "hexname.com.",
"kind": "Native",
"masters": [],
"nameservers": [
"ns1.hexname.com.",
"ns2.hexname.com."
]
}' -X POST -H "X-API-Key: $API_KEY" http://127.0.0.1:8081/api/v1/servers/localhost/zones
flush_rrsets
# Secure/update DDNSEC
sudo podman exec -it hexname-powerdns pdnsutil zone secure hexname.com

View file

@ -1,18 +0,0 @@
{ pkgs, ... }:
{
systemd.timers.restart-netbird-relay = {
timerConfig = {
Unit = "update-containers.service";
OnCalendar = "Tue 02:40"; # 10 mins after podman pull
};
wantedBy = [ "timers.target" ];
};
systemd.services.restart-netbird-relay = {
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.systemd}/bin/systemctl try-restart podman-netbird-relay.service";
};
};
}

View file

@ -1,38 +0,0 @@
{ config, pkgs, ... }:
let
scriptPath = "${config.vars.homeDir}/nixos/scripts";
after = [ "network.target" "NetworkManager.service" "uptime-kuma.service" ];
environment = {
VAR_IP = config.vars.privateIp;
};
in
{
systemd.services = {
"zfs-uptime-kuma" = {
inherit environment after;
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
User = "root";
};
path = with pkgs; [ bash curl zfs jq ];
script = ''
bash ${scriptPath}/zfs-healthcheck/uptime-kuma.sh
'';
};
};
systemd.timers = {
"zfs-uptime-kuma" = {
wantedBy = [ "timers.target" ];
partOf = [ "zfs-uptime-kuma.service" ];
timerConfig = {
Persistent = true; # Execute immediately if missed
OnUnitActiveSec = "7m"; # Run every x minutes
Unit = "zfs-uptime-kuma.service";
};
};
};
}

View file

@ -1,29 +0,0 @@
#! /bin/sh
set -euo pipefail
set -x
push_token=$(< /etc/env/zfs/push-token);
start_time=$(date -u +%s%3N)
health=$(zpool list -H -o health)
status="up"
echo "$health" | while IFS= read -r line; do
if [ "$line" != "ONLINE" ]; then
status="down"
break
fi
done
end_time=$(date -u +%s%3N)
duration=$(("$end_time" - "$start_time"))
msg=$(printf '%s' "$health" | tr '\n' ',' | tr -d "'" | jq -sRr @uri)
url="http://$VAR_IP:4000/api/push/$push_token?ping=$duration&status=$status&msg='$msg'"
output=$(curl --fail --no-progress-meter --retry 1 $url 2>&1)
if [ $? -ne 0 ]; then
echo "Ping failed: $output" >&2
fi

View file

@ -1,17 +1,17 @@
{ pkgs, ... }:
{
systemd.timers.restart-pihole = {
systemd.timers.restart-powerdns = {
timerConfig = {
Unit = "update-containers.service";
OnCalendar = "Tue 02:40"; # 10 mins after podman pull
OnCalendar = "Sat 10:51"; # 10 mins after podman pull
};
wantedBy = [ "timers.target" ];
};
systemd.services.restart-pihole = {
systemd.services.restart-powerdns = {
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.systemd}/bin/systemctl try-restart podman-pihole.service";
ExecStart = "${pkgs.systemd}/bin/systemctl try-restart podman-powerdns.service";
};
};
}

View file

@ -4,7 +4,7 @@
systemd.timers.update-containers = {
timerConfig = {
Unit = "update-containers.service";
OnCalendar = "Mon 02:30";
OnCalendar = "Sat 10:41";
};
wantedBy = [ "timers.target" ];
};