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

@ -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;