+22
-22
flake.lock
+22
-22
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": 1758427187,
260
-
"narHash": "sha256-pHpxZ/IyCwoTQPtFIAG2QaxuSm8jWzrzBGjwQZIttJc=",
259
+
"lastModified": 1767379071,
260
+
"narHash": "sha256-EgE0pxsrW9jp9YFMkHL9JMXxcqi/OoumPJYwf+Okucw=",
261
261
"owner": "nixos",
262
262
"repo": "nixpkgs",
263
-
"rev": "554be6495561ff07b6c724047bdd7e0716aa7b46",
263
+
"rev": "fb7944c166a3b630f177938e478f0378e64ce108",
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": 1767683698,
358
+
"narHash": "sha256-MFrfNmTKTdOOsyXUvvqPwH6zqvDZZpURnd7QdJkVOgU=",
359
359
"ref": "refs/heads/master",
360
-
"rev": "a17d65a1a78d8889e0b971be2bc5d32be445ce10",
361
-
"revCount": 1666,
360
+
"rev": "b31a2a3590fefc4c70817f94a20076df2428b4d3",
361
+
"revCount": 1791,
362
362
"type": "git",
363
363
"url": "https://tangled.org/@tangled.org/core"
364
364
},
+30
flake.nix
+30
flake.nix
···
29
29
};
30
30
nixosConfigurations.pds = nixpkgs.lib.nixosSystem {
31
31
system = "x86_64-linux";
32
+
specialArgs = {
33
+
commonArgs = import ./common/ssh.nix;
34
+
};
32
35
modules = [
33
36
disko.nixosModules.disko
34
37
./hosts/pds/configuration.nix
38
+
];
39
+
};
40
+
nixosConfigurations.appview = nixpkgs.lib.nixosSystem {
41
+
system = "x86_64-linux";
42
+
specialArgs = {
43
+
commonArgs = import ./common/ssh.nix;
44
+
};
45
+
modules = [
46
+
disko.nixosModules.disko
47
+
./hosts/appview/configuration.nix
35
48
];
36
49
};
37
50
···
50
63
environment.systemPackages = [
51
64
pkgs.curl
52
65
];
66
+
};
67
+
appview = { pkgs, ... }: {
68
+
deployment = {
69
+
targetHost = "alpha.tangled.sh";
70
+
targetPort = 22;
71
+
targetUser = "tangler";
72
+
buildOnTarget = true;
73
+
};
74
+
nixpkgs.system = "x86_64-linux";
75
+
imports = [
76
+
disko.nixosModules.disko
77
+
tangled.nixosModules.appview
78
+
./hosts/appview/configuration.nix
79
+
./hosts/appview/services/appview.nix
80
+
./hosts/appview/services/nginx-alpha.nix
81
+
];
82
+
time.timeZone = "Europe/Helsinki";
53
83
};
54
84
pds = { pkgs, ... }: {
55
85
deployment = {
+57
hosts/appview/configuration.nix
+57
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
+
};
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" ];
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/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
+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
+
}
+93
hosts/appview/services/nginx.nix
+93
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
+
virtualHosts = {
11
+
# Redirect tangled.sh → tangled.org
12
+
"tangled.sh" = {
13
+
serverAliases = [ "www.tangled.sh" ];
14
+
locations."/" = {
15
+
return = "301 https://tangled.org$request_uri";
16
+
};
17
+
forceSSL = true;
18
+
enableACME = true;
19
+
};
20
+
21
+
# Redirect strings.tangled.sh → tangled.org/strings/*
22
+
"strings.tangled.sh" = {
23
+
locations."/" = {
24
+
return = "301 https://tangled.org/strings$request_uri";
25
+
};
26
+
forceSSL = true;
27
+
enableACME = true;
28
+
};
29
+
30
+
# Redirect strings.tangled.org → tangled.org/strings/*
31
+
"strings.tangled.org" = {
32
+
locations."/" = {
33
+
return = "301 https://tangled.org/strings$request_uri";
34
+
};
35
+
forceSSL = true;
36
+
enableACME = true;
37
+
};
38
+
39
+
# Main app on tangled.org
40
+
"tangled.org" = {
41
+
serverAliases = [ "www.tangled.org" ];
42
+
43
+
forceSSL = true;
44
+
enableACME = true;
45
+
46
+
extraConfig = ''
47
+
# Redirect www → bare domain
48
+
if ($host = www.tangled.org) {
49
+
return 301 https://tangled.org$request_uri;
50
+
}
51
+
52
+
client_max_body_size 100M;
53
+
'';
54
+
55
+
locations."~ ^/@tangled\\.sh(/.*)?$" = {
56
+
return = "301 https://tangled.org/@tangled.org$1$is_args$args";
57
+
};
58
+
59
+
locations."~ ^/tangled\\.sh(/.*)?$" = {
60
+
return = "301 https://tangled.org/tangled.org$1$is_args$args";
61
+
};
62
+
63
+
locations."~ /logs$" = {
64
+
proxyPass = "http://127.0.0.1:3000";
65
+
proxyWebsockets = true;
66
+
extraConfig = ''
67
+
proxy_read_timeout 86400;
68
+
'';
69
+
};
70
+
71
+
locations."/" = {
72
+
proxyPass = "http://127.0.0.1:3000";
73
+
extraConfig = ''
74
+
proxy_set_header Host $host;
75
+
proxy_set_header X-Real-IP $remote_addr;
76
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
77
+
proxy_set_header X-Forwarded-Proto $scheme;
78
+
include ${config.services.nginx.package}/conf/mime.types;
79
+
'';
80
+
};
81
+
};
82
+
};
83
+
};
84
+
85
+
# Open firewall ports
86
+
networking.firewall.allowedTCPPorts = [ 80 443 ];
87
+
88
+
# ACME configuration for Let's Encrypt
89
+
security.acme = {
90
+
acceptTerms = true;
91
+
defaults.email = "team@tangled.org";
92
+
};
93
+
}