+24
-24
flake.lock
+24
-24
flake.lock
···
45
45
]
46
46
},
47
47
"locked": {
48
-
"lastModified": 1751854533,
49
-
"narHash": "sha256-U/OQFplExOR1jazZY4KkaQkJqOl59xlh21HP9mI79Vc=",
48
+
"lastModified": 1766150702,
49
+
"narHash": "sha256-P0kM+5o+DKnB6raXgFEk3azw8Wqg5FL6wyl9jD+G5a4=",
50
50
"owner": "nix-community",
51
51
"repo": "disko",
52
-
"rev": "16b74a1e304197248a1bc663280f2548dbfcae3c",
52
+
"rev": "916506443ecd0d0b4a0f4cf9d40a3c22ce39b378",
53
53
"type": "github"
54
54
},
55
55
"original": {
···
108
108
"systems": "systems"
109
109
},
110
110
"locked": {
111
-
"lastModified": 1694529238,
112
-
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
111
+
"lastModified": 1731533236,
112
+
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
113
113
"owner": "numtide",
114
114
"repo": "flake-utils",
115
-
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
115
+
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
116
116
"type": "github"
117
117
},
118
118
"original": {
···
130
130
]
131
131
},
132
132
"locked": {
133
-
"lastModified": 1754078208,
134
-
"narHash": "sha256-YVoIFDCDpYuU3riaDEJ3xiGdPOtsx4sR5eTzHTytPV8=",
133
+
"lastModified": 1763982521,
134
+
"narHash": "sha256-ur4QIAHwgFc0vXiaxn5No/FuZicxBr2p0gmT54xZkUQ=",
135
135
"owner": "nix-community",
136
136
"repo": "gomod2nix",
137
-
"rev": "7f963246a71626c7fc70b431a315c4388a0c95cf",
137
+
"rev": "02e63a239d6eabd595db56852535992c898eba72",
138
138
"type": "github"
139
139
},
140
140
"original": {
···
225
225
"nixery-flake": {
226
226
"flake": false,
227
227
"locked": {
228
-
"lastModified": 1745149613,
229
-
"narHash": "sha256-rcSnsnSWA0IUjmbG2iSpvVB0702tcR3zIyU3iFJBo0g=",
228
+
"lastModified": 1762501370,
229
+
"narHash": "sha256-WO2NvvFB3KkFfChE5F6ghog7mvBAVKpMsQMqwadZT4k=",
230
230
"owner": "tazjin",
231
231
"repo": "nixery",
232
-
"rev": "c6d4692b1b6eb105c9abce0411d2ef4b8708a6e1",
232
+
"rev": "be8a4005de3f27f95e677e7b61abef387d4a840d",
233
233
"type": "github"
234
234
},
235
235
"original": {
···
256
256
},
257
257
"nixpkgs_2": {
258
258
"locked": {
259
-
"lastModified": 1764522689,
260
-
"narHash": "sha256-SqUuBFjhl/kpDiVaKLQBoD8TLD+/cTUzzgVFoaHrkqY=",
259
+
"lastModified": 1767634882,
260
+
"narHash": "sha256-2GffSfQxe3sedHzK+sTKlYo/NTIAGzbFCIsNMUPAAnk=",
261
261
"owner": "nixos",
262
262
"repo": "nixpkgs",
263
-
"rev": "8bb5646e0bed5dbd3ab08c7a7cc15b75ab4e1d0f",
263
+
"rev": "3c9db02515ef1d9b6b709fc60ba9a540957f661c",
264
264
"type": "github"
265
265
},
266
266
"original": {
···
272
272
},
273
273
"nixpkgs_3": {
274
274
"locked": {
275
-
"lastModified": 1751984180,
276
-
"narHash": "sha256-LwWRsENAZJKUdD3SpLluwDmdXY9F45ZEgCb0X+xgOL0=",
275
+
"lastModified": 1766070988,
276
+
"narHash": "sha256-G/WVghka6c4bAzMhTwT2vjLccg/awmHkdKSd2JrycLc=",
277
277
"owner": "nixos",
278
278
"repo": "nixpkgs",
279
-
"rev": "9807714d6944a957c2e036f84b0ff8caf9930bc0",
279
+
"rev": "c6245e83d836d0433170a16eb185cefe0572f8b8",
280
280
"type": "github"
281
281
},
282
282
"original": {
···
354
354
"sqlite-lib-src": "sqlite-lib-src"
355
355
},
356
356
"locked": {
357
-
"lastModified": 1763358301,
358
-
"narHash": "sha256-i2fc5A2qoHvubTWhcpG5S6Hy42DlYOyEgJjR6TaQvxg=",
357
+
"lastModified": 1767767073,
358
+
"narHash": "sha256-BSZJ1TY5lGt7xNgFRtcKwYcSOI6VC2CHLfm7y/GgHwU=",
359
359
"ref": "refs/heads/master",
360
-
"rev": "a17d65a1a78d8889e0b971be2bc5d32be445ce10",
361
-
"revCount": 1666,
360
+
"rev": "6dc86ffbed5a290ca6a4890caa2dadea5c8b8a81",
361
+
"revCount": 1792,
362
362
"type": "git",
363
-
"url": "https://tangled.org/@tangled.org/core"
363
+
"url": "https://tangled.org/tangled.org/core"
364
364
},
365
365
"original": {
366
366
"type": "git",
367
-
"url": "https://tangled.org/@tangled.org/core"
367
+
"url": "https://tangled.org/tangled.org/core"
368
368
}
369
369
}
370
370
},
+96
-53
flake.nix
+96
-53
flake.nix
···
1
1
{
2
2
description = "nix infra for tangled";
3
+
3
4
inputs = {
4
5
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
5
-
tangled.url = "git+https://tangled.org/@tangled.org/core";
6
+
tangled.url = "git+https://tangled.org/tangled.org/core";
6
7
colmena.url = "github:zhaofengli/colmena/release-0.4.x";
7
8
disko = {
8
9
url = "github:nix-community/disko";
···
16
17
};
17
18
};
18
19
19
-
outputs =
20
-
{ nixpkgs, disko, colmena, nixery-flake, tangled, ... }:
21
-
{
22
-
nixosConfigurations.nixery = nixpkgs.lib.nixosSystem {
23
-
system = "x86_64-linux";
24
-
modules = [
25
-
disko.nixosModules.disko
26
-
tangled.nixosModules.spindle
27
-
./hosts/nixery/configuration.nix
28
-
];
29
-
};
30
-
nixosConfigurations.pds = nixpkgs.lib.nixosSystem {
31
-
system = "x86_64-linux";
32
-
modules = [
33
-
disko.nixosModules.disko
34
-
./hosts/pds/configuration.nix
35
-
];
36
-
};
20
+
outputs = { nixpkgs, disko, colmena, nixery-flake, tangled, ... }:
21
+
let
22
+
system = "x86_64-linux";
23
+
commonArgs = import ./common/ssh.nix;
37
24
38
-
colmenaHive = colmena.lib.makeHive {
39
-
meta = {
40
-
nixpkgs = nixpkgs.legacyPackages.x86_64-linux;
41
-
specialArgs = {
42
-
nixery-pkgs = import nixery-flake.outPath {
43
-
pkgs = import nixpkgs { system = "x86_64-linux"; };
44
-
};
45
-
commonArgs = import ./common/ssh.nix;
46
-
};
25
+
# Helper function to create nixosConfiguration
26
+
mkHost = hostname: extraModules:
27
+
nixpkgs.lib.nixosSystem {
28
+
inherit system;
29
+
specialArgs = { inherit commonArgs; };
30
+
modules = [
31
+
disko.nixosModules.disko
32
+
./hosts/${hostname}/configuration.nix
33
+
] ++ extraModules;
47
34
};
48
35
49
-
defaults = { pkgs, ... }: {
50
-
environment.systemPackages = [
51
-
pkgs.curl
52
-
];
53
-
};
54
-
pds = { pkgs, ... }: {
36
+
# Helper function to create colmena host
37
+
mkColmenaHost = hostname: targetHost: targetPort: extraModules:
38
+
{
55
39
deployment = {
56
-
targetHost = "tngl.sh";
57
-
targetPort = 22;
40
+
inherit targetHost;
41
+
inherit targetPort;
58
42
targetUser = "tangler";
59
43
buildOnTarget = true;
60
44
};
61
-
nixpkgs.system = "x86_64-linux";
62
-
45
+
nixpkgs.system = system;
46
+
time.timeZone = "Europe/Helsinki";
63
47
imports = [
64
48
disko.nixosModules.disko
65
-
./hosts/pds/configuration.nix
49
+
./hosts/${hostname}/configuration.nix
50
+
] ++ extraModules;
51
+
};
52
+
53
+
# Host configurations
54
+
hosts = {
55
+
appview = {
56
+
modules = [
57
+
tangled.nixosModules.appview
58
+
./hosts/appview/services/appview.nix
59
+
./hosts/appview/services/nginx.nix
60
+
];
61
+
target = "95.111.205.38";
62
+
};
63
+
64
+
pds = {
65
+
modules = [
66
66
./hosts/pds/services/nginx.nix
67
67
./hosts/pds/services/pds.nix
68
68
];
69
-
time.timeZone = "Europe/Helsinki";
69
+
target = "tngl.sh";
70
70
};
71
71
72
-
nixery = { pkgs, ... }: {
73
-
deployment = {
74
-
targetHost = "nixery.tangled.sh";
75
-
targetPort = 22;
76
-
targetUser = "tangler";
77
-
buildOnTarget = true;
78
-
};
79
-
nixpkgs.system = "x86_64-linux";
80
-
81
-
imports = [
82
-
disko.nixosModules.disko
72
+
nixery = {
73
+
modules = [
83
74
tangled.nixosModules.spindle
84
-
./hosts/nixery/configuration.nix
85
75
./hosts/nixery/services/nginx.nix
86
76
./hosts/nixery/services/openbao/openbao.nix
87
77
./hosts/nixery/services/openbao/proxy.nix
88
78
./hosts/nixery/services/nixery.nix
89
79
];
90
-
time.timeZone = "Europe/Helsinki";
80
+
target = "nixery.tangled.sh";
91
81
};
82
+
83
+
spindle = {
84
+
modules = [
85
+
tangled.nixosModules.spindle
86
+
./hosts/spindle/services/openbao/openbao.nix
87
+
./hosts/spindle/services/openbao/proxy.nix
88
+
./hosts/spindle/services/spindle.nix
89
+
./hosts/spindle/services/nginx.nix
90
+
];
91
+
target = "spindle.alpha.tangled.sh";
92
+
};
93
+
94
+
knot1 = {
95
+
modules = [
96
+
tangled.nixosModules.knot
97
+
./hosts/knot1/services/knot.nix
98
+
./hosts/knot1/services/nginx.nix
99
+
];
100
+
target = "knot1.alpha.tangled.sh";
101
+
};
102
+
};
103
+
in
104
+
{
105
+
# nixos-anywhere and nixos-rebuild use these
106
+
nixosConfigurations = {
107
+
appview = mkHost "appview" hosts.appview.modules;
108
+
pds = mkHost "pds" hosts.pds.modules;
109
+
nixery = mkHost "nixery" hosts.nixery.modules;
110
+
spindle = mkHost "spindle" hosts.spindle.modules;
111
+
knot1 = mkHost "knot1" hosts.knot1.modules;
112
+
};
113
+
114
+
# colmena uses this
115
+
colmenaHive = colmena.lib.makeHive {
116
+
meta = {
117
+
nixpkgs = nixpkgs.legacyPackages.${system};
118
+
specialArgs = {
119
+
inherit commonArgs;
120
+
nixery-pkgs = import nixery-flake.outPath {
121
+
pkgs = import nixpkgs { inherit system; };
122
+
};
123
+
};
124
+
};
125
+
126
+
defaults = { pkgs, ... }: {
127
+
environment.systemPackages = [ pkgs.curl ];
128
+
};
129
+
130
+
appview = mkColmenaHost "appview" hosts.appview.target 2222 hosts.appview.modules;
131
+
pds = mkColmenaHost "pds" hosts.pds.target 22 hosts.pds.modules;
132
+
nixery = mkColmenaHost "nixery" hosts.nixery.target 22 hosts.nixery.modules;
133
+
spindle = mkColmenaHost "spindle" hosts.spindle.target 22 hosts.spindle.modules;
134
+
knot1 = mkColmenaHost "knot1" hosts.knot1.target 22 hosts.knot1.modules;
92
135
};
93
136
};
94
137
}
+62
hosts/appview/configuration.nix
+62
hosts/appview/configuration.nix
···
1
+
{ modulesPath
2
+
, lib
3
+
, pkgs
4
+
, ...
5
+
} @ args:
6
+
{
7
+
imports = [
8
+
(modulesPath + "/installer/scan/not-detected.nix")
9
+
(modulesPath + "/profiles/qemu-guest.nix")
10
+
./disk-config.nix
11
+
];
12
+
boot.loader.grub = {
13
+
# no need to set devices, disko will add all devices that have a EF02 partition to the list already
14
+
# devices = [ ];
15
+
efiSupport = true;
16
+
efiInstallAsRemovable = true;
17
+
};
18
+
19
+
networking.hostName = "appview-arn";
20
+
services = {
21
+
openssh.enable = true;
22
+
openssh.ports = [2222];
23
+
};
24
+
25
+
# networking.extraHosts = ''
26
+
# 85.9.211.103 knot1.tangled.sh
27
+
# '';
28
+
29
+
30
+
nix = {
31
+
extraOptions = ''
32
+
experimental-features = nix-command flakes ca-derivations
33
+
warn-dirty = false
34
+
keep-outputs = false
35
+
'';
36
+
};
37
+
38
+
environment.systemPackages = map lib.lowPrio [
39
+
pkgs.curl
40
+
pkgs.gitMinimal
41
+
];
42
+
43
+
users.users.tangler = {
44
+
extraGroups = [ "networkmanager" "wheel" ];
45
+
openssh.authorizedKeys.keys = args.commonArgs.sshKeys;
46
+
isNormalUser = true;
47
+
};
48
+
49
+
security.sudo.extraRules = [
50
+
{
51
+
users = [ "tangler" ];
52
+
commands = [
53
+
{
54
+
command = "ALL";
55
+
options = [ "NOPASSWD" ];
56
+
}
57
+
];
58
+
}
59
+
];
60
+
61
+
system.stateVersion = "25.05";
62
+
}
+56
hosts/appview/disk-config.nix
+56
hosts/appview/disk-config.nix
···
1
+
# Example to create a bios compatible gpt partition
2
+
{ lib, ... }:
3
+
{
4
+
disko.devices = {
5
+
disk.disk1 = {
6
+
device = lib.mkDefault "/dev/vda";
7
+
type = "disk";
8
+
content = {
9
+
type = "gpt";
10
+
partitions = {
11
+
boot = {
12
+
name = "boot";
13
+
size = "1M";
14
+
type = "EF02";
15
+
};
16
+
esp = {
17
+
name = "ESP";
18
+
size = "500M";
19
+
type = "EF00";
20
+
content = {
21
+
type = "filesystem";
22
+
format = "vfat";
23
+
mountpoint = "/boot";
24
+
};
25
+
};
26
+
root = {
27
+
name = "root";
28
+
size = "100%";
29
+
content = {
30
+
type = "lvm_pv";
31
+
vg = "pool";
32
+
};
33
+
};
34
+
};
35
+
};
36
+
};
37
+
lvm_vg = {
38
+
pool = {
39
+
type = "lvm_vg";
40
+
lvs = {
41
+
root = {
42
+
size = "100%FREE";
43
+
content = {
44
+
type = "filesystem";
45
+
format = "ext4";
46
+
mountpoint = "/";
47
+
mountOptions = [
48
+
"defaults"
49
+
];
50
+
};
51
+
};
52
+
};
53
+
};
54
+
};
55
+
};
56
+
}
+11
hosts/appview/services/appview.nix
+11
hosts/appview/services/appview.nix
+6
hosts/appview/services/litestream.nix
+6
hosts/appview/services/litestream.nix
+53
hosts/appview/services/nginx-alpha.nix
+53
hosts/appview/services/nginx-alpha.nix
···
1
+
{ config, pkgs, ... }:
2
+
{
3
+
services.nginx = {
4
+
enable = true;
5
+
recommendedTlsSettings = true;
6
+
recommendedOptimisation = true;
7
+
recommendedGzipSettings = true;
8
+
9
+
# Fix proxy headers hash warnings
10
+
appendHttpConfig = ''
11
+
proxy_headers_hash_max_size 1024;
12
+
proxy_headers_hash_bucket_size 128;
13
+
'';
14
+
15
+
virtualHosts = {
16
+
# AppView service on alpha.tangled.sh
17
+
"alpha.tangled.sh" = {
18
+
forceSSL = true;
19
+
enableACME = true;
20
+
21
+
locations."/" = {
22
+
proxyPass = "http://127.0.0.1:3000";
23
+
extraConfig = ''
24
+
proxy_http_version 1.1;
25
+
proxy_set_header Host $host;
26
+
proxy_set_header X-Real-IP $remote_addr;
27
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
28
+
proxy_set_header X-Forwarded-Proto $scheme;
29
+
client_max_body_size 100M;
30
+
'';
31
+
};
32
+
33
+
# WebSocket support for /logs endpoint
34
+
locations."~ /logs$" = {
35
+
proxyPass = "http://127.0.0.1:3000";
36
+
proxyWebsockets = true;
37
+
extraConfig = ''
38
+
proxy_read_timeout 86400;
39
+
'';
40
+
};
41
+
};
42
+
};
43
+
};
44
+
45
+
# Open firewall ports
46
+
networking.firewall.allowedTCPPorts = [ 80 443 ];
47
+
48
+
# ACME configuration for Let's Encrypt
49
+
security.acme = {
50
+
acceptTerms = true;
51
+
defaults.email = "team@tangled.org";
52
+
};
53
+
}
+123
hosts/appview/services/nginx.nix
+123
hosts/appview/services/nginx.nix
···
1
+
{ config, pkgs, ... }:
2
+
{
3
+
services.nginx = {
4
+
enable = true;
5
+
recommendedProxySettings = true;
6
+
recommendedTlsSettings = true;
7
+
recommendedOptimisation = true;
8
+
recommendedGzipSettings = true;
9
+
10
+
# bot blocking
11
+
appendHttpConfig = ''
12
+
map $http_user_agent $block_bot {
13
+
default 0;
14
+
~*PerplexityBot 1;
15
+
~*GPTBot 1;
16
+
~*ChatGPT-User 1;
17
+
~*CCBot 1;
18
+
~*anthropic-ai 1;
19
+
~*Claude-Web 1;
20
+
}
21
+
'';
22
+
23
+
streamConfig = ''
24
+
upstream knot-sailor {
25
+
server 94.237.110.185:22;
26
+
}
27
+
28
+
server {
29
+
listen 22;
30
+
listen [::]:22;
31
+
proxy_pass knot-sailor;
32
+
}
33
+
'';
34
+
35
+
virtualHosts = {
36
+
# Redirect tangled.sh โ tangled.org
37
+
"tangled.sh" = {
38
+
serverAliases = [ "www.tangled.sh" ];
39
+
locations."/" = {
40
+
return = "301 https://tangled.org$request_uri";
41
+
};
42
+
forceSSL = true;
43
+
enableACME = true;
44
+
};
45
+
46
+
# Redirect strings.tangled.sh โ tangled.org/strings/*
47
+
"strings.tangled.sh" = {
48
+
locations."/" = {
49
+
return = "301 https://tangled.org/strings$request_uri";
50
+
};
51
+
forceSSL = true;
52
+
enableACME = true;
53
+
};
54
+
55
+
# Redirect strings.tangled.org โ tangled.org/strings/*
56
+
"strings.tangled.org" = {
57
+
locations."/" = {
58
+
return = "301 https://tangled.org/strings$request_uri";
59
+
};
60
+
forceSSL = true;
61
+
enableACME = true;
62
+
};
63
+
64
+
# Main app on tangled.org
65
+
"tangled.org" = {
66
+
serverAliases = [ "www.tangled.org" ];
67
+
68
+
forceSSL = true;
69
+
enableACME = true;
70
+
71
+
extraConfig = ''
72
+
if ($block_bot) {
73
+
return 403;
74
+
}
75
+
76
+
# Redirect www โ bare domain
77
+
if ($host = www.tangled.org) {
78
+
return 301 https://tangled.org$request_uri;
79
+
}
80
+
81
+
client_max_body_size 100M;
82
+
'';
83
+
84
+
locations."~ ^/@tangled\\.sh(/.*)?$" = {
85
+
extraConfig = ''
86
+
rewrite ^/@tangled\.sh(.*)$ https://tangled.org/@tangled.org$1 permanent;
87
+
'';
88
+
};
89
+
90
+
locations."~ ^/tangled\\.sh(/.*)?$" = {
91
+
extraConfig = ''
92
+
rewrite ^/tangled\.sh(.*)$ https://tangled.org/tangled.org$1 permanent;
93
+
'';
94
+
};
95
+
96
+
97
+
locations."~ /logs$" = {
98
+
proxyPass = "http://127.0.0.1:3000";
99
+
proxyWebsockets = true;
100
+
extraConfig = ''
101
+
proxy_read_timeout 86400;
102
+
'';
103
+
};
104
+
105
+
locations."/" = {
106
+
proxyPass = "http://127.0.0.1:3000";
107
+
extraConfig = ''
108
+
client_max_body_size 100M;
109
+
'';
110
+
};
111
+
};
112
+
};
113
+
};
114
+
115
+
# Open firewall ports
116
+
networking.firewall.allowedTCPPorts = [ 80 443 2222 22 ];
117
+
118
+
# ACME configuration for Let's Encrypt
119
+
security.acme = {
120
+
acceptTerms = true;
121
+
defaults.email = "team@tangled.org";
122
+
};
123
+
}
+57
hosts/knot1/configuration.nix
+57
hosts/knot1/configuration.nix
···
1
+
{ modulesPath
2
+
, lib
3
+
, pkgs
4
+
, ...
5
+
} @ args:
6
+
{
7
+
imports = [
8
+
(modulesPath + "/installer/scan/not-detected.nix")
9
+
(modulesPath + "/profiles/qemu-guest.nix")
10
+
./disk-config.nix
11
+
];
12
+
boot.loader.grub = {
13
+
# no need to set devices, disko will add all devices that have a EF02 partition to the list already
14
+
# devices = [ ];
15
+
efiSupport = true;
16
+
efiInstallAsRemovable = true;
17
+
};
18
+
19
+
networking.hostName = "knot1-ams";
20
+
services = {
21
+
openssh.enable = true;
22
+
};
23
+
24
+
25
+
nix = {
26
+
extraOptions = ''
27
+
experimental-features = nix-command flakes ca-derivations
28
+
warn-dirty = false
29
+
keep-outputs = false
30
+
'';
31
+
};
32
+
33
+
environment.systemPackages = map lib.lowPrio [
34
+
pkgs.curl
35
+
pkgs.gitMinimal
36
+
];
37
+
38
+
users.users.tangler = {
39
+
extraGroups = [ "networkmanager" "wheel" "docker" ];
40
+
openssh.authorizedKeys.keys = args.commonArgs.sshKeys;
41
+
isNormalUser = true;
42
+
};
43
+
44
+
security.sudo.extraRules = [
45
+
{
46
+
users = [ "tangler" ];
47
+
commands = [
48
+
{
49
+
command = "ALL";
50
+
options = [ "NOPASSWD" ];
51
+
}
52
+
];
53
+
}
54
+
];
55
+
56
+
system.stateVersion = "25.05";
57
+
}
+56
hosts/knot1/disk-config.nix
+56
hosts/knot1/disk-config.nix
···
1
+
# Example to create a bios compatible gpt partition
2
+
{ lib, ... }:
3
+
{
4
+
disko.devices = {
5
+
disk.disk1 = {
6
+
device = lib.mkDefault "/dev/vda";
7
+
type = "disk";
8
+
content = {
9
+
type = "gpt";
10
+
partitions = {
11
+
boot = {
12
+
name = "boot";
13
+
size = "1M";
14
+
type = "EF02";
15
+
};
16
+
esp = {
17
+
name = "ESP";
18
+
size = "500M";
19
+
type = "EF00";
20
+
content = {
21
+
type = "filesystem";
22
+
format = "vfat";
23
+
mountpoint = "/boot";
24
+
};
25
+
};
26
+
root = {
27
+
name = "root";
28
+
size = "100%";
29
+
content = {
30
+
type = "lvm_pv";
31
+
vg = "pool";
32
+
};
33
+
};
34
+
};
35
+
};
36
+
};
37
+
lvm_vg = {
38
+
pool = {
39
+
type = "lvm_vg";
40
+
lvs = {
41
+
root = {
42
+
size = "100%FREE";
43
+
content = {
44
+
type = "filesystem";
45
+
format = "ext4";
46
+
mountpoint = "/";
47
+
mountOptions = [
48
+
"defaults"
49
+
];
50
+
};
51
+
};
52
+
};
53
+
};
54
+
};
55
+
};
56
+
}
+11
hosts/knot1/services/knot.nix
+11
hosts/knot1/services/knot.nix
+35
hosts/knot1/services/nginx.nix
+35
hosts/knot1/services/nginx.nix
···
1
+
{
2
+
services.nginx = {
3
+
enable = true;
4
+
virtualHosts = {
5
+
"knot1.alpha.tangled.sh" = {
6
+
forceSSL = true;
7
+
enableACME = true;
8
+
locations."/" = {
9
+
proxyPass = "http://127.0.0.1:5555";
10
+
11
+
extraConfig = ''
12
+
proxy_set_header X-Forwarded-For $remote_addr;
13
+
proxy_set_header Host $host;
14
+
proxy_set_header X-Real-IP $remote_addr;
15
+
proxy_set_header X-Forwarded-Proto $scheme;
16
+
'';
17
+
};
18
+
locations."/events" = {
19
+
proxyPass = "http://127.0.0.1:5555";
20
+
extraConfig = ''
21
+
proxy_set_header X-Forwarded-For $remote_addr;
22
+
proxy_set_header Host $host;
23
+
proxy_set_header Upgrade $http_upgrade;
24
+
proxy_set_header Connection "upgrade";
25
+
'';
26
+
};
27
+
};
28
+
};
29
+
};
30
+
security.acme = {
31
+
acceptTerms = true;
32
+
defaults.email = "team@tangled.org";
33
+
};
34
+
networking.firewall.allowedTCPPorts = [ 80 443 ];
35
+
}
+11
hosts/nixery/services/nginx.nix
+11
hosts/nixery/services/nginx.nix
···
1
+
{ tangled-pkgs, pkgs, ... }:
2
+
1
3
{
2
4
services.nginx = {
3
5
enable = true;
4
6
virtualHosts = {
7
+
"docs.tangled.org" = {
8
+
forceSSL = true;
9
+
enableACME = true;
10
+
root = "${tangled-pkgs.docs}";
11
+
locations."/" = {
12
+
tryFiles = "$uri $uri/ =404";
13
+
index = "index.html";
14
+
};
15
+
};
5
16
"nixery.tangled.sh" = {
6
17
forceSSL = true;
7
18
enableACME = true;
+57
hosts/spindle/configuration.nix
+57
hosts/spindle/configuration.nix
···
1
+
{ modulesPath
2
+
, lib
3
+
, pkgs
4
+
, ...
5
+
} @ args:
6
+
{
7
+
imports = [
8
+
(modulesPath + "/installer/scan/not-detected.nix")
9
+
(modulesPath + "/profiles/qemu-guest.nix")
10
+
./disk-config.nix
11
+
];
12
+
boot.loader.grub = {
13
+
# no need to set devices, disko will add all devices that have a EF02 partition to the list already
14
+
# devices = [ ];
15
+
efiSupport = true;
16
+
efiInstallAsRemovable = true;
17
+
};
18
+
19
+
networking.hostName = "spindle-waw";
20
+
services = {
21
+
openssh.enable = true;
22
+
};
23
+
24
+
25
+
nix = {
26
+
extraOptions = ''
27
+
experimental-features = nix-command flakes ca-derivations
28
+
warn-dirty = false
29
+
keep-outputs = false
30
+
'';
31
+
};
32
+
33
+
environment.systemPackages = map lib.lowPrio [
34
+
pkgs.curl
35
+
pkgs.gitMinimal
36
+
];
37
+
38
+
users.users.tangler = {
39
+
extraGroups = [ "networkmanager" "wheel" "docker" ];
40
+
openssh.authorizedKeys.keys = args.commonArgs.sshKeys;
41
+
isNormalUser = true;
42
+
};
43
+
44
+
security.sudo.extraRules = [
45
+
{
46
+
users = [ "tangler" ];
47
+
commands = [
48
+
{
49
+
command = "ALL";
50
+
options = [ "NOPASSWD" ];
51
+
}
52
+
];
53
+
}
54
+
];
55
+
56
+
system.stateVersion = "25.05";
57
+
}
+56
hosts/spindle/disk-config.nix
+56
hosts/spindle/disk-config.nix
···
1
+
# Example to create a bios compatible gpt partition
2
+
{ lib, ... }:
3
+
{
4
+
disko.devices = {
5
+
disk.disk1 = {
6
+
device = lib.mkDefault "/dev/vda";
7
+
type = "disk";
8
+
content = {
9
+
type = "gpt";
10
+
partitions = {
11
+
boot = {
12
+
name = "boot";
13
+
size = "1M";
14
+
type = "EF02";
15
+
};
16
+
esp = {
17
+
name = "ESP";
18
+
size = "500M";
19
+
type = "EF00";
20
+
content = {
21
+
type = "filesystem";
22
+
format = "vfat";
23
+
mountpoint = "/boot";
24
+
};
25
+
};
26
+
root = {
27
+
name = "root";
28
+
size = "100%";
29
+
content = {
30
+
type = "lvm_pv";
31
+
vg = "pool";
32
+
};
33
+
};
34
+
};
35
+
};
36
+
};
37
+
lvm_vg = {
38
+
pool = {
39
+
type = "lvm_vg";
40
+
lvs = {
41
+
root = {
42
+
size = "100%FREE";
43
+
content = {
44
+
type = "filesystem";
45
+
format = "ext4";
46
+
mountpoint = "/";
47
+
mountOptions = [
48
+
"defaults"
49
+
];
50
+
};
51
+
};
52
+
};
53
+
};
54
+
};
55
+
};
56
+
}
+37
hosts/spindle/services/nginx.nix
+37
hosts/spindle/services/nginx.nix
···
1
+
{
2
+
services.nginx = {
3
+
enable = true;
4
+
virtualHosts = {
5
+
"spindle.alpha.tangled.sh" = {
6
+
forceSSL = true;
7
+
enableACME = true;
8
+
locations."/" = {
9
+
proxyPass = "http://127.0.0.1:6555";
10
+
};
11
+
locations."/events" = {
12
+
proxyPass = "http://127.0.0.1:6555";
13
+
extraConfig = ''
14
+
proxy_set_header X-Forwarded-For $remote_addr;
15
+
proxy_set_header Host $host;
16
+
proxy_set_header Upgrade $http_upgrade;
17
+
proxy_set_header Connection "upgrade";
18
+
'';
19
+
};
20
+
locations."/logs/" = {
21
+
proxyPass = "http://127.0.0.1:6555";
22
+
extraConfig = ''
23
+
proxy_set_header X-Forwarded-For $remote_addr;
24
+
proxy_set_header Host $host;
25
+
proxy_set_header Upgrade $http_upgrade;
26
+
proxy_set_header Connection "upgrade";
27
+
'';
28
+
};
29
+
};
30
+
};
31
+
};
32
+
security.acme = {
33
+
acceptTerms = true;
34
+
defaults.email = "team@tangled.org";
35
+
};
36
+
networking.firewall.allowedTCPPorts = [ 80 443 ];
37
+
}
+39
hosts/spindle/services/openbao/openbao.nix
+39
hosts/spindle/services/openbao/openbao.nix
···
1
+
{ config, pkgs, lib, ... }:
2
+
{
3
+
# Create openbao user and group
4
+
users.groups.openbao = {};
5
+
6
+
users.users.openbao = {
7
+
isSystemUser = true;
8
+
group = "openbao";
9
+
home = "/var/lib/openbao";
10
+
createHome = true;
11
+
description = "OpenBao service user";
12
+
};
13
+
14
+
systemd.services.openbao = {
15
+
serviceConfig = {
16
+
DynamicUser = lib.mkForce false;
17
+
User = "openbao";
18
+
Group = "openbao";
19
+
};
20
+
};
21
+
22
+
services.openbao = {
23
+
enable = true;
24
+
settings = {
25
+
ui = true;
26
+
27
+
listener.default = {
28
+
type = "tcp";
29
+
address = "127.0.0.1:8201";
30
+
tls_disable = true;
31
+
};
32
+
33
+
cluster_addr = "http://127.0.0.1:8202";
34
+
api_addr = "http://127.0.0.1:8201";
35
+
36
+
storage.raft.path = "/var/lib/openbao";
37
+
};
38
+
};
39
+
}
+100
hosts/spindle/services/openbao/proxy.nix
+100
hosts/spindle/services/openbao/proxy.nix
···
1
+
{ pkgs, ... }:
2
+
3
+
{
4
+
systemd.services.openbao-proxy = {
5
+
description = "OpenBao Proxy with Auto-Auth";
6
+
after = [ "network.target" ];
7
+
wantedBy = [ "multi-user.target" ];
8
+
serviceConfig = {
9
+
User = "root";
10
+
ExecStart = "${pkgs.openbao}/bin/bao proxy -config=/etc/openbao/proxy.hcl";
11
+
Restart = "always";
12
+
RestartSec = "5";
13
+
LimitNOFILE = "65536";
14
+
};
15
+
};
16
+
17
+
18
+
19
+
environment.etc."openbao/proxy.hcl".text = ''
20
+
vault {
21
+
address = "http://localhost:8201"
22
+
23
+
# Retry configuration
24
+
retry {
25
+
num_retries = 5
26
+
}
27
+
}
28
+
29
+
# Auto-Auth using AppRole
30
+
auto_auth {
31
+
method "approle" {
32
+
mount_path = "auth/approle"
33
+
config = {
34
+
role_id_file_path = "/etc/openbao/role-id"
35
+
secret_id_file_path = "/etc/openbao/secret-id"
36
+
remove_secret_id_file_after_reading = false
37
+
}
38
+
}
39
+
40
+
# Write authenticated token to file
41
+
sink "file" {
42
+
config = {
43
+
path = "/var/lib/openbao/token"
44
+
mode = 0640
45
+
}
46
+
}
47
+
}
48
+
49
+
# API Proxy listener for Spindle
50
+
listener "tcp" {
51
+
address = "127.0.0.1:8200"
52
+
tls_disable = true
53
+
54
+
# Security headers
55
+
require_request_header = false
56
+
57
+
# Enable proxy API for management
58
+
proxy_api {
59
+
enable_quit = true
60
+
}
61
+
}
62
+
63
+
# Enable API proxy with auto-auth token
64
+
api_proxy {
65
+
use_auto_auth_token = true
66
+
}
67
+
68
+
cache {
69
+
}
70
+
71
+
# Logging configuration
72
+
log_level = "info"
73
+
log_format = "standard"
74
+
log_file = "/var/log/openbao/proxy.log"
75
+
log_rotate_duration = "24h"
76
+
log_rotate_max_files = 30
77
+
78
+
# Process management
79
+
pid_file = "/var/lib/openbao/proxy.pid"
80
+
81
+
# Disable idle connections for reliability
82
+
disable_idle_connections = ["auto-auth", "proxying"]
83
+
'';
84
+
85
+
# Create necessary directories and files
86
+
systemd.tmpfiles.rules = [
87
+
# Directories
88
+
"d /var/lib/openbao 0755 root root -"
89
+
"d /var/lib/openbao/cache 0755 root root -"
90
+
"d /var/log/openbao 0755 root root -"
91
+
"d /etc/openbao 0755 root root -"
92
+
93
+
# Credential files (content must be populated externally)
94
+
"f /etc/openbao/role-id 0600 root root -"
95
+
"f /etc/openbao/secret-id 0600 root root -"
96
+
97
+
# Configuration file
98
+
"f /etc/openbao/proxy.hcl 0644 root root -"
99
+
];
100
+
}
+19
hosts/spindle/services/spindle.nix
+19
hosts/spindle/services/spindle.nix
···
1
+
{ config, pkgs, ... }:
2
+
{
3
+
services.tangled.spindle = {
4
+
enable = true;
5
+
server = {
6
+
owner = "did:plc:wshs7t2adsemcrrd4snkeqli"; # @tangled.sh
7
+
hostname = "spindle.alpha.tangled.sh";
8
+
listenAddr = "127.0.0.1:6555";
9
+
queueSize = 100;
10
+
maxJobCount = 2;
11
+
secrets = {
12
+
provider = "openbao";
13
+
};
14
+
};
15
+
pipelines = {
16
+
workflowTimeout = "15m";
17
+
};
18
+
};
19
+
}