Compare commits
1 Commits
master
...
4c954eab6e
Author | SHA1 | Date |
---|---|---|
Jaculabilis | 4c954eab6e |
|
@ -1,2 +1,4 @@
|
|||
# nixos-configs
|
||||
|
||||
Individual machine configs are branched off of `master`.
|
||||
|
||||
|
|
131
flake.lock
131
flake.lock
|
@ -1,143 +1,24 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1673956053,
|
||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"intake": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"flake-compat"
|
||||
],
|
||||
"nixos-shell": "nixos-shell",
|
||||
"nixpkgs": [
|
||||
"nixpkgs-2405"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1730957384,
|
||||
"narHash": "sha256-cnldNpKvL1aZ9XcvD5gL8/7iHgKx+JOM9WkV5HqNm8A=",
|
||||
"ref": "develop",
|
||||
"rev": "bbe3f53cd4e056bcbd29352a50dd62f090f4a765",
|
||||
"revCount": 107,
|
||||
"type": "git",
|
||||
"url": "ssh://gitea@git.alogoulogoi.com/Jaculabilis/intake.git"
|
||||
},
|
||||
"original": {
|
||||
"ref": "develop",
|
||||
"type": "git",
|
||||
"url": "ssh://gitea@git.alogoulogoi.com/Jaculabilis/intake.git"
|
||||
}
|
||||
},
|
||||
"intake-sources": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs-2405"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1719589502,
|
||||
"narHash": "sha256-jdG/Z4Rctp2uqjcHkAN0l1423yPwRxAGLfAJsw+EF+I=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "c94a31206c1b07a85bf43493c602c5b42afd27c5",
|
||||
"revCount": 28,
|
||||
"type": "git",
|
||||
"url": "ssh://gitea@git.alogoulogoi.com/Jaculabilis/intake-sources.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "ssh://gitea@git.alogoulogoi.com/Jaculabilis/intake-sources.git"
|
||||
}
|
||||
},
|
||||
"nixos-shell": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"intake",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1686216465,
|
||||
"narHash": "sha256-0A4K6xVIyxUi2YZu4+156WwzAO1GDWGcKiMvsXpBQDQ=",
|
||||
"owner": "Mic92",
|
||||
"repo": "nixos-shell",
|
||||
"rev": "65489e7eeef8eeea43e1e4218ad1b99d58852c7c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "Mic92",
|
||||
"repo": "nixos-shell",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-2311": {
|
||||
"locked": {
|
||||
"lastModified": 1701282334,
|
||||
"narHash": "sha256-MxCVrXY6v4QmfTwIysjjaX0XUhqBbxTWWB4HXtDYsdk=",
|
||||
"lastModified": 1669052418,
|
||||
"narHash": "sha256-M1I4BKXBQm2gey1tScemEh5TpHHE3gKptL7BpWUvL8s=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "057f9aecfb71c4437d2b27d3323df7f93c010b7e",
|
||||
"rev": "20fc948445a6c22d4e8d5178e9a6bc6e1f5417c8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-2405": {
|
||||
"locked": {
|
||||
"lastModified": 1719838683,
|
||||
"narHash": "sha256-Zw9rQjHz1ilNIimEXFeVa1ERNRBF8DoXDhLAZq5B4pE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d032c1a6dfad4eedec7e35e91986becc699d7d69",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-24.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-unstable": {
|
||||
"locked": {
|
||||
"lastModified": 1723362943,
|
||||
"narHash": "sha256-dFZRVSgmJkyM0bkPpaYRtG/kRMRTorUIDj8BxoOt1T4=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "a58bc8ad779655e790115244571758e8de055e3d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "20fc948445a6c22d4e8d5178e9a6bc6e1f5417c8",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"intake": "intake",
|
||||
"intake-sources": "intake-sources",
|
||||
"nixpkgs-2311": "nixpkgs-2311",
|
||||
"nixpkgs-2405": "nixpkgs-2405",
|
||||
"nixpkgs-unstable": "nixpkgs-unstable"
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
86
flake.nix
86
flake.nix
|
@ -1,86 +1,16 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs-2311.url = "github:NixOS/nixpkgs/23.11";
|
||||
nixpkgs-2405.url = "github:NixOS/nixpkgs/nixos-24.05";
|
||||
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-compat = {
|
||||
url = "github:edolstra/flake-compat";
|
||||
flake = false;
|
||||
};
|
||||
intake = {
|
||||
url = "git+ssh://gitea@git.alogoulogoi.com/Jaculabilis/intake.git?ref=develop";
|
||||
inputs.nixpkgs.follows = "nixpkgs-2405";
|
||||
inputs.flake-compat.follows = "flake-compat";
|
||||
};
|
||||
intake-sources = {
|
||||
url = "git+ssh://gitea@git.alogoulogoi.com/Jaculabilis/intake-sources.git";
|
||||
inputs.nixpkgs.follows = "nixpkgs-2405";
|
||||
};
|
||||
nixpkgs.url = "github:NixOS/nixpkgs?rev=20fc948445a6c22d4e8d5178e9a6bc6e1f5417c8";
|
||||
};
|
||||
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs-2311,
|
||||
nixpkgs-2405,
|
||||
nixpkgs-unstable,
|
||||
flake-compat,
|
||||
intake,
|
||||
intake-sources,
|
||||
}@inputs: {
|
||||
nixosModules = {
|
||||
beatific = import ./modules/beatific.nix;
|
||||
tf2-gperftools = import ./modules/tf2-gperftools.nix { inherit inputs; };
|
||||
unstable-vscode = import ./modules/unstable-vscode.nix { inherit inputs; };
|
||||
outputs = { self, nixpkgs }: {
|
||||
nixosConfigurations.catacomb = nixpkgs.lib.nixosSystem {
|
||||
system = "aarch64-linux";
|
||||
modules = [ ./machine/catacomb ];
|
||||
};
|
||||
|
||||
nixosConfigurations = {
|
||||
backyard = nixpkgs-2405.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
self.nixosModules.beatific
|
||||
./machine/backyard
|
||||
];
|
||||
};
|
||||
catacomb = nixpkgs-2405.lib.nixosSystem {
|
||||
system = "aarch64-linux";
|
||||
modules = [
|
||||
self.nixosModules.beatific
|
||||
./machine/catacomb
|
||||
];
|
||||
};
|
||||
centroid = nixpkgs-2405.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
self.nixosModules.beatific
|
||||
./machine/centroid
|
||||
];
|
||||
};
|
||||
empyrean = nixpkgs-2405.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
self.nixosModules.beatific
|
||||
intake.nixosModules.default
|
||||
intake-sources.nixosModules.default
|
||||
./machine/empyrean
|
||||
];
|
||||
};
|
||||
imperium = nixpkgs-2405.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
self.nixosModules.beatific
|
||||
self.nixosModules.tf2-gperftools
|
||||
self.nixosModules.unstable-vscode
|
||||
./machine/imperium
|
||||
];
|
||||
};
|
||||
unfolder = nixpkgs-2405.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
self.nixosModules.beatific
|
||||
self.nixosModules.unstable-vscode
|
||||
./machine/unfolder
|
||||
];
|
||||
};
|
||||
nixosConfiguration.empyrean = nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [ ./machine/empyrean ];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
tvb = [
|
||||
./nix-on-droid.vagrant.pub
|
||||
./tvb.backyard.pub
|
||||
./tvb.catacomb.pub
|
||||
./tvb.centroid.pub
|
||||
./tvb.empyrean.pub
|
||||
./tvb.imperium.pub
|
||||
./tvb.palamas.pub
|
||||
./tvb.stagirite.pub
|
||||
./tvb.unfolder.pub
|
||||
./tvb.vagrant.pub
|
||||
];
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCzx37PqIaJVWdQs5meVgI4Cg1GRGk6srrix0AUvQeaBS9MOVtJLi+HfnNkcW4GPk9qVlz1E7ciQ7YUw+ny7QbHxcbib2Tawwfk3cx9xiNcN6UI9EzF/rTbNB2Cex8A4sEr5UvoE0BjT5yPaXyrjn8vLksGWq4dlZBM3xeJqe3KP+OxPL0vik3SVGOr/6ZQ7H9cwX5+/p6rCWQuVtwZMcaE6QyXYg5J5FQUaIrFvKbOVklJIkQSbXGzIYQO/QlQC0xWGBapJtGQw/lsQ3YqnFSMkkw8qrKbde07rg8p1FSuqTu+a1ePK+/F4klNel174+39YSobY2/6biPP3Uj/Yhorf4Tw141tIT75e3ebtK5faatQmNOyXcA7LULXK7XemJkZy8PmbNNTeBIKyoI6XQdzk95gpb2C4LEJmV040YMgXhOIiKsHQVgss9FuC+oP5jXWU/JuNXBRHa1IpJjcJhIhg7jnh6ZNZHyK0EpeUs3Zp7usv7mz6CGwb04yvTsWOhZRc+6EoHaHyrNvFPfkPeGsZzxhIbprCyDMtKWsI9GCtztcRhQWBgornUVEs5CurLJBbClQTrZLVv2fn9UnXWPYZTLYL7aFwRIGyKr8ZOOMFxbLOGdeFlqc5TGCP416e8PZvhE+BuDmxiKtQJ/dsQFqVzvOZb2WQRsYRPYvvXbvUw== monitor@isidore
|
|
@ -1 +0,0 @@
|
|||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEpvV9dKUVBlv5VU3LU0XIGTQK/McPf3H31HHD/vINGG nix-on-droid@vagrant
|
|
@ -1 +0,0 @@
|
|||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGYv5vs78+UAeRagopi4BuvmmK1l3zZwQPY3R4rnp7oV tvb@backyard
|
|
@ -1 +0,0 @@
|
|||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDitOuQeddhGh3Zg/fnawTrIdomMhgR6rJchbfAAEUz7JDWyrwZoU0/kMBcn9qZZBFE0MDeUSbQbF+voA7/dwZKB+3GBOurg75KSxtwDLHw4urC5U9VCZnbOrFnl5K51oopduxE7vqZdtTzJztcDVKwJILSFPS2hDC3Zt7+pnB1z0aMOJIMyqfogSk29dxREHO130tbrRWI6bCrAJKXWMFSEx6N1pGoOvOKZu4YVdiDSqTPdSYW4D4ivC5Wtt74rGz8/su5xvZKHgNf/d/hILlg/zhnGzH5gn8HvN5pqRksh2fiteGxDQoXgaRGEb93RLe6KV7XPy60vmI+uE06lsow0C7hLrSWorhLQOuLG1J5JzzF0SmFRUOYQoc6BbOLLVXVBa1VcmpupHMJiw6ldJv9yD410bXd+IwIDS9IkW1MIfvN5j35AvnaJCEHVUSrkEjgqCpkNxNPl7V3h7YRw6F/AljTvgEER91mPUvwfJrC0sMo/+DWNwIbnK+jjioD2szHXz2EpXlVhkMSwey/rNZffQpzFHWsm3Za/+4KxWBUO/2MRz2x1haDvvD37hN2kC5w0DSC6MsJucDVlyEjgDQkVEBKujkBv4fpYLpN4VoqVDYytpgnRTm0QIb+ISStG19Fq1uj3UtHFyWI5d8P3jiev4DTtqCpQo9NWa4zu/mbCw== tvb@catacomb
|
|
@ -1 +0,0 @@
|
|||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC364peKQVWeqFNzhJJkvHumKerKPkczeX2I/e9FFZyL tvb@centroid
|
|
@ -1 +1 @@
|
|||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCuAlVTZ4g7x8Fv3YoHn4KRr5GHfylgJjkC6lujti7Fd3JhZ34OB5L/FuCKLo0rv/1qpIcGHk01FMNT/hDcbyBRPN5QG1s7x39Bt8yBVePoJK0+malGkI90z4zV1b5LEjvRhr7+KuOskt3eVbhKcEXiJpDdqOOgqvppmQZOb6jb03+q01rPLzz0S20jUDLRSdnmlcNDv16lMXTX9zgWDeVIVErTvoLAI8RloqKUgienheLJSS6sdEk4AjL2PKldKE6mIOxZWiYSTS9+2ClqV8u3l1UTZ7+DOw8FWASmMYaaBvJRDEUzDKA/iOAjpfPO7WOn+yjRyiT7IFVFoz2XtXwZD0OEQhbgLZtPlhOHh5wn++YNnvzLYd5cYSWVya0FYzVis24hbaGjrwB5tzD0riL2lRzo3ZjktpL7RlCSLfO/2Cb14hLOxZTZZcgdM6Ef/1YatJiEpRQ7FLP45Di3hKc9QEsqQP1BrhhYQOCWwEHAgVXM8W1ncEBXiCnrelegVy0= tvb@empyrean
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1h/6CedtyFIjFTT7M5e0dEKJkhPbCQ1RLhtj/83H//AK6bzRbWfnKzSH0VXpsHjaU/Ipc1Jl2fQ23r8i/QyKHUKK7xPeGcY5J7oIHVggkEKW2n9R27Ml9BriKxx6ltButnwSOVYk7dyNhz93GYTTEF3ydh4X7HP2Cv7rh5fbca3s69GXRjOVGmIuuVbaJiaMmiWhBI4LYtqwpo1zGXMjfNlXcMFw7VA4EG2UpkJkcWeyN/AI3ZS/YybcTQNCAg+Xnk94CVys/b5wTuGWRplDrRlNR00MUWpr94+u/xk+sC4/6vT7je2W4GjA1jTq4XmewTEV4cxOu+l1jtHZBgvHho5X0fOogdN52MkjuaXzByZB/Br5xTkBRv0tDf5haX4HzuBC29yU9rt62SEQRzvZxObCCGDcIYR/1HTgjDZkRuwgO/1RoRh5SvwbptvPwpBMvx25S//ZJESLO++lqxjgRZSr/05YpZ5diffEIGd1J0Jz0NGv4XBPcMBnSMKFmdwOy+5jnBbW2OjPQaPslXHEKYTfOByzCA8LgppkxvmL08GIjxYfEljioHR5by+Z6SjG1VvifMFA6FN/+DN6ZH0LmeOMa5YM1Zl3bx5RaANpnSNvi6rmxkQa1oMaK0l482FvpVkg6o1h9si/AeNTEbiX9ozHdjekfuzBSk6Jfo6xw+Q== tvb@empyrean
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHGUvJ7Gd1mN2mF/hy12dizwEw64zn+jT0vFpkhGF07s tvb@imperium
|
|
@ -1 +0,0 @@
|
|||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCom6c/UrhM6KrzDcm8kJGZJ5ugR4wRfsFUhTJ5F4oLNQcNspvqlUfxT4Hjv4xHA5hCjvPYi7JxVWxBsOEmmIs/LAjFXRNw9Kz8m7TCf/lct+JUpf6eCn6a/orhA0OdUv4c9aiH2Dzp4ob3lR6xYvYUOH3LuffqypSXP0k5zCSetROUgTZibEpa0oE2GevcyjQAExpCjx02ZRIGkGOM20CXtm3EJsTzIs6uk4+2F9hB+HMqePFKCzsgOlFfVCNWiKNywLavXo7Gn0O9pWidufXZ9s8nCBiOEzU1n6T8pNQBat4z7G1uKFKKWNDPL6/HNEmCq0JxUuXSSjg8LIk+uqPH49Ubpf8EORON8z8nVFAAqbuI6rdYc7J9DllQ7hb7EBT9w9w+mcz3XH0BsGzJUOMD9r0P96pWOn+I6A9jPmOqoOZDzGpfYS18+zYWET/ohH4U4pABcW4nwGx0Jz7Fj6iQW3tyjOefuXcz+sJoYKo/9FOh44KYf4pgu3hfoMlGC0M= tvb@unfolder
|
|
@ -1,124 +0,0 @@
|
|||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
./fileserver.nix
|
||||
./jellyfin.nix
|
||||
./samba.nix
|
||||
];
|
||||
|
||||
# Use the systemd-boot EFI boot loader.
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
|
||||
# ZFS support
|
||||
boot.supportedFilesystems = [ "zfs" ];
|
||||
networking.hostId = "64cc144d";
|
||||
# https://old.reddit.com/r/zfs/comments/1826lgs/psa_its_not_block_cloning_its_a_data_corruption/
|
||||
boot.kernelParams = [ "zfs.zfs_dmu_offset_next_sync=0" ];
|
||||
boot.zfs.extraPools = [ "pool" ];
|
||||
|
||||
beatific.hostName = "backyard";
|
||||
|
||||
nix.channel.enable = false;
|
||||
|
||||
# Enable networking
|
||||
networking.networkmanager.enable = true;
|
||||
|
||||
networking.firewall = {
|
||||
enable = true;
|
||||
allowedTCPPorts = [
|
||||
7474 # mirror revproxy
|
||||
7475 # http serve tvb pool
|
||||
7476 # tvb catacomb host server
|
||||
];
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts = {
|
||||
default = {
|
||||
default = true;
|
||||
rejectSSL = true;
|
||||
locations."/".return = "444";
|
||||
};
|
||||
"pool.backyard.home" = {
|
||||
listen = [
|
||||
{ addr = "10.22.20.8"; }
|
||||
# Alternative port to ensure the right vhost connects
|
||||
{ addr = "10.22.20.8"; port = 7475; }
|
||||
];
|
||||
root = "/pool/tvb";
|
||||
locations."/".extraConfig = ''
|
||||
autoindex on;
|
||||
autoindex_exact_size off;
|
||||
'';
|
||||
};
|
||||
"mirror.backyard.home" = {
|
||||
listen = [
|
||||
{ addr = "10.22.20.8"; }
|
||||
# Alternative port to ensure the right vhost connects
|
||||
{ addr = "10.22.20.8"; port = 7474; }
|
||||
];
|
||||
root = "/pool/tvb/doc/website/mirror";
|
||||
};
|
||||
"files.backyard.home" = {
|
||||
listen = [
|
||||
{ addr = "10.22.20.8"; port = 7476; }
|
||||
];
|
||||
locations."/" = {
|
||||
root = "/pool/tvb";
|
||||
tryFiles = "\$uri @indexer";
|
||||
};
|
||||
locations."@indexer".proxyPass = "http://localhost:5000";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
pv # zfs send progress meter
|
||||
smartmontools # provides smartctl drive inspector
|
||||
];
|
||||
programs.screen.enable = true;
|
||||
|
||||
services.zfs = {
|
||||
autoScrub = {
|
||||
enable = true;
|
||||
pools = [ "pool" ];
|
||||
interval = "monthly";
|
||||
};
|
||||
};
|
||||
|
||||
services.cron.enable = true;
|
||||
|
||||
users.users = {
|
||||
tvb = {
|
||||
extraGroups = [ "networkmanager" ];
|
||||
packages = [
|
||||
(pkgs.writeShellScriptBin "yt-dlp" ''exec $HOME/.yt-dlp/bin/yt-dlp "$@"'')
|
||||
];
|
||||
};
|
||||
katydid = {
|
||||
uid = 1102;
|
||||
isNormalUser = true;
|
||||
group = "katydid";
|
||||
initialPassword = "katydid";
|
||||
};
|
||||
};
|
||||
|
||||
users.groups = {
|
||||
katydid.gid = 1102;
|
||||
tvbpoolro = {
|
||||
gid = 1201;
|
||||
members = [ "tvb" "jellyfin" "nginx" ];
|
||||
};
|
||||
};
|
||||
|
||||
# This value governs how some stateful data, like databases, are handled
|
||||
# across different versions of NixOS. This should not be changed to a new
|
||||
# release unless the sysadmin has determined that no services would be
|
||||
# adversely affected by changing this.
|
||||
system.stateVersion = "23.05";
|
||||
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
# nas indexer server module
|
||||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
# Build the catacomb server package
|
||||
catacombServerSource = builtins.fetchGit {
|
||||
url = "https://git.alogoulogoi.com/Jaculabilis/catacomb-server.git";
|
||||
ref = "develop-nix";
|
||||
rev = "3d6fb16948c377f94d030648849f120c8ada3884";
|
||||
};
|
||||
catacombServer = pkgs.callPackage catacombServerSource {
|
||||
pkgs = import (fetchTarball {
|
||||
url = "https://github.com/NixOS/nixpkgs/archive/405d762a1a05ffed2ac820eb4bae4bc49bc3abf2.tar.gz";
|
||||
sha256 = "6c835ea038bdfe170029a8bd4276c9d3a95c275159ec05426672fa8092c7947d";
|
||||
}) {
|
||||
system = "x86_64-linux";
|
||||
};
|
||||
};
|
||||
|
||||
# Host-mode server run script
|
||||
hostRun = pkgs.writeShellScriptBin "catacomb-run-host.sh" ''
|
||||
${catacombServer}/bin/gunicorn \
|
||||
--bind=localhost:5000 \
|
||||
--workers=3 \
|
||||
--log-level=debug \
|
||||
--env CATACOMB_ROOT=/pool/tvb \
|
||||
--env CATACOMB_MODE=host \
|
||||
--env CATACOMB_TOKENS=/var/empty \
|
||||
--env CATACOMB_GUEST_HOST=catacomb.alogoulogoi.com \
|
||||
"catacomb.server:wsgi()"
|
||||
'';
|
||||
in
|
||||
{
|
||||
# Set up the host mode service
|
||||
systemd.services."catacomb-host" = {
|
||||
enable = true;
|
||||
description = "catapool host-mode index server";
|
||||
script = "${hostRun}/bin/catacomb-run-host.sh";
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = "nginx";
|
||||
};
|
||||
requires = [ "zfs.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
};
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ (modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" "sr_mod" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-intel" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" =
|
||||
{ device = "/dev/disk/by-uuid/75addc56-2a0d-431e-a0c5-f6ee0e370e61";
|
||||
fsType = "ext4";
|
||||
};
|
||||
|
||||
fileSystems."/boot" =
|
||||
{ device = "/dev/disk/by-uuid/610F-1EB7";
|
||||
fsType = "vfat";
|
||||
};
|
||||
|
||||
swapDevices =
|
||||
[ { device = "/dev/disk/by-uuid/cc464bb4-e1c8-46c0-adbb-ea1a3cfa5b03"; }
|
||||
];
|
||||
|
||||
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||
# still possible to use this option, but it's recommended to use it in conjunction
|
||||
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
|
||||
networking.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.eno1.useDHCP = lib.mkDefault true;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
# Enable jellyfin
|
||||
services.jellyfin.enable = true;
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
recommendedProxySettings = true;
|
||||
virtualHosts = {
|
||||
# Create a default vhost to deny traffic, so traffic has to actually match a vhost
|
||||
default = {
|
||||
default = true;
|
||||
locations."/".return = "444";
|
||||
};
|
||||
"jellyfin.home.ktvb.site" = {
|
||||
listen = [
|
||||
# The router should have a static lease for this IP and a host entry naming it
|
||||
{ addr = "192.168.1.236"; port = 80; }
|
||||
# beatific module sends traffic over the vpn
|
||||
{ addr = "10.22.20.8"; port = 80; }
|
||||
# Also available on an extra port in case of port 80 troubles
|
||||
{ addr = "10.22.20.8"; port = 8096; }
|
||||
];
|
||||
locations."/".extraConfig = ''
|
||||
proxy_buffering off;
|
||||
proxy_pass http://localhost:8096/;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
80 # http
|
||||
8096 # jellyfin
|
||||
];
|
||||
|
||||
users.users.tvb.extraGroups = [ "jellyfin" ];
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
{ pkgs, lib, ... }:
|
||||
{
|
||||
# This is mostly to get smbpasswd
|
||||
environment.systemPackages = [ pkgs.samba ];
|
||||
|
||||
services.samba-wsdd = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
};
|
||||
|
||||
services.samba = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
securityType = "user";
|
||||
extraConfig = ''
|
||||
workgroup = beatific
|
||||
server string = backyard smb server
|
||||
netbios name = backyard
|
||||
deadtime = 300
|
||||
|
||||
local master = yes
|
||||
domain master = yes
|
||||
preferred master = yes
|
||||
|
||||
guest account = nobody
|
||||
map to guest = bad user
|
||||
|
||||
case sensitive = yes
|
||||
veto files = /^.DS_Store$/^.Trash-1000$/
|
||||
|
||||
load printers = no
|
||||
printcap name = /dev/null
|
||||
printing = bsd
|
||||
|
||||
log file = /var/log/samba/client-%m.log
|
||||
log level = 2
|
||||
max log size = 64
|
||||
|
||||
hide dot files = no
|
||||
hosts allow = 10.22.20., 192.168.1.
|
||||
map archive = no
|
||||
# this must be set to false to make symlinks outside /home work
|
||||
# could potentially be fixed by mounting pool to /home, bind mounting to /pool, and setting both nofail
|
||||
unix extensions = no
|
||||
|
||||
ntlm auth = yes
|
||||
'';
|
||||
shares = let
|
||||
homeShare = user: {
|
||||
path = "/home/${user}";
|
||||
comment = "${user}'s home folder";
|
||||
browseable = "yes";
|
||||
"read only" = "no";
|
||||
"guest okay" = "no";
|
||||
"create mask" = "0640";
|
||||
"force create mode" = "0640";
|
||||
"directory mask" = "0750";
|
||||
"force directory mode" = "0750";
|
||||
"valid users" = "${user}";
|
||||
"follow symlinks" = "yes";
|
||||
"wide links" = "yes";
|
||||
};
|
||||
in {
|
||||
tvb = homeShare "tvb";
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,14 +1,11 @@
|
|||
{ pkgs, lib, ... }:
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
./mopidy.nix
|
||||
./fileserver.nix
|
||||
];
|
||||
|
||||
beatific.hostName = "catacomb";
|
||||
beatific.defaults.tvbSync = false;
|
||||
|
||||
boot = {
|
||||
loader = {
|
||||
# Use the extlinux boot loader. (NixOS wants to enable GRUB by default)
|
||||
|
@ -16,83 +13,202 @@
|
|||
# Enables the generation of /boot/extlinux/extlinux.conf
|
||||
generic-extlinux-compatible.enable = true;
|
||||
};
|
||||
supportedFilesystems = ["zfs"];
|
||||
zfs.enableUnstable = true;
|
||||
};
|
||||
|
||||
system.stateVersion = "22.11"; # Read the usual warning
|
||||
|
||||
swapDevices = [ { device = "/swap"; size = 1024; } ];
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
lsof # list open files
|
||||
mpv # cli media player
|
||||
smartmontools # provides smartctl
|
||||
usbutils # provides lsusb
|
||||
console.keyMap = "us";
|
||||
i18n.defaultLocale = "en_US.UTF-8";
|
||||
|
||||
environment.systemPackages = with pkgs;
|
||||
let
|
||||
py3-packages = python-packages: with python-packages; [
|
||||
flask
|
||||
];
|
||||
py3-with-packages = python3.withPackages py3-packages;
|
||||
in [
|
||||
wget vim curl git htop bash tmux psmisc man-pages pv lsof
|
||||
zip unzip
|
||||
py3-with-packages
|
||||
usbutils
|
||||
hdparm sdparm smartmontools gptfdisk gnufdisk
|
||||
dosfstools
|
||||
mkpasswd samba
|
||||
tinc_pre
|
||||
#file-rename
|
||||
rsync
|
||||
rclone gnupg
|
||||
];
|
||||
|
||||
networking = {
|
||||
hostId = "beeeeee5"; # this must be consistent for ZFS
|
||||
hostName = "catacomb";
|
||||
hostId = "beeeeee5";
|
||||
firewall = {
|
||||
enable = true;
|
||||
allowedTCPPorts = [ 80 139 445 ];
|
||||
allowPing = true;
|
||||
allowedTCPPorts = [ 22 139 445 ];
|
||||
allowedUDPPorts = [ 137 138 ];
|
||||
};
|
||||
wireless = {
|
||||
enable = true;
|
||||
networks."mysterious humming noise".psk = "@MHN_PSK@";
|
||||
environmentFile = "/root/wifi.env";
|
||||
};
|
||||
};
|
||||
|
||||
services.pipewire = {
|
||||
services.cron = {
|
||||
enable = true;
|
||||
alsa.enable = true;
|
||||
alsa.support32Bit = true;
|
||||
pulse.enable = true;
|
||||
# To avoid needing an active user session, run a single system instance
|
||||
systemWide = true;
|
||||
systemCronJobs =
|
||||
let
|
||||
reassertPerms = pkgs.writeShellScript "reassert-nas-permissions.sh" ''
|
||||
${pkgs.coreutils}/bin/chown -v -R tvb:nas /nas
|
||||
${pkgs.findutils}/bin/find /nas -type d -exec ${pkgs.coreutils}/bin/chmod -v 750 {} \;
|
||||
${pkgs.findutils}/bin/find /nas -type f -exec ${pkgs.coreutils}/bin/chmod -v 640 {} \;
|
||||
'';
|
||||
in [
|
||||
"0 20 * * 1 root ${reassertPerms}"
|
||||
"0 0 * * 1 tvb . /etc/profile; /home/tvb/gitea-backup"
|
||||
];
|
||||
};
|
||||
|
||||
services.openssh.settings.PasswordAuthentication = true;
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
passwordAuthentication = true;
|
||||
};
|
||||
|
||||
services.ntp = {
|
||||
enable = true;
|
||||
servers = ["time.nist.gov"];
|
||||
};
|
||||
|
||||
services.rsyncd.enable = true;
|
||||
|
||||
services.nginx = {
|
||||
/*services.samba =
|
||||
let
|
||||
sambaShare = path: validUsers: {
|
||||
path = path;
|
||||
comment = "Samba share for ${path}";
|
||||
browseable = "yes";
|
||||
"read only" = "no";
|
||||
"guest okay" = "no";
|
||||
"create mask" = "0640";
|
||||
"force create mode" = "0640";
|
||||
"directory mask" = "0750";
|
||||
"force directory mode" = "0750";
|
||||
"valid users" = validUsers;
|
||||
"force group" = ''nas'';
|
||||
};
|
||||
sambaShareRO = path: validUsers: {
|
||||
path = path;
|
||||
comment = "Read-only Samba share for ${path}";
|
||||
browseable = "yes";
|
||||
"read only" = "yes";
|
||||
"guest okay" = "no";
|
||||
"valid users" = validUsers;
|
||||
"force group" = ''nas'';
|
||||
};
|
||||
in
|
||||
{
|
||||
enable = true;
|
||||
securityType = "user";
|
||||
extraConfig = ''
|
||||
workgroup = beatific
|
||||
server string = Catacomb Nix SMB
|
||||
netbios name = catacomb
|
||||
deadtime = 300
|
||||
|
||||
local master = yes
|
||||
domain master = yes
|
||||
preferred master = yes
|
||||
|
||||
guest account = nobody
|
||||
map to guest = bad user
|
||||
|
||||
case sensitive = yes
|
||||
veto files = /^.DS_Store$/^.Trash-1000$/
|
||||
|
||||
load printers = no
|
||||
printcap name = /dev/null
|
||||
printing = bsd
|
||||
|
||||
log file = /var/log/samba/client-%m.log
|
||||
log level = 2
|
||||
max log size = 64
|
||||
|
||||
hide dot files = no
|
||||
hosts allow = 10.7.3.
|
||||
map archive = no
|
||||
unix extensions = yes
|
||||
|
||||
ntlm auth = yes
|
||||
'';
|
||||
shares = {
|
||||
audioRO = sambaShareRO "/nas/audio" ''@nas'';
|
||||
docRO = sambaShareRO "/nas/doc/" ''@nas'';
|
||||
gameRO = sambaShareRO "/nas/game/" ''@nas'';
|
||||
imageRO = sambaShareRO "/nas/image" ''@nas'';
|
||||
videoRO = sambaShareRO "/nas/video" ''@nas'';
|
||||
#audio = sambaShare "/nas/audio" ''@nas'';
|
||||
#doc = sambaShare "/nas/doc/" ''@nas'';
|
||||
#game = sambaShare "/nas/game/" ''@nas'';
|
||||
#image = sambaShare "/nas/image" ''@nas'';
|
||||
#video = sambaShare "/nas/video" ''@nas'';
|
||||
};
|
||||
};*/
|
||||
|
||||
services.nebula.networks.beatific = {
|
||||
enable = true;
|
||||
recommendedProxySettings = true;
|
||||
virtualHosts = {
|
||||
default = {
|
||||
default = true;
|
||||
locations."/".return = "444";
|
||||
};
|
||||
"mopidy.home.ktvb.site" = {
|
||||
listen = [
|
||||
{ addr = "10.22.20.2"; }
|
||||
{ addr = "catacomb.lan"; }
|
||||
];
|
||||
locations."/" = {
|
||||
proxyWebsockets = true;
|
||||
proxyPass = "http://localhost:6680";
|
||||
};
|
||||
};
|
||||
|
||||
# Network certificate and host credentials
|
||||
ca = "/etc/nebula/beatific/beatific.crt";
|
||||
cert = "/etc/nebula/beatific/catacomb.crt";
|
||||
key = "/etc/nebula/beatific/catacomb.key";
|
||||
|
||||
listen.port = 4242;
|
||||
|
||||
# Connect to the lighthouse at empyrean
|
||||
# Note that this is a VPN address, not a public address
|
||||
lighthouses = [ "10.22.20.1" ];
|
||||
|
||||
# Map the lighthouse address to its public address
|
||||
staticHostMap = { "10.22.20.1" = [ "vpn.alogoulogoi.com:4242" ]; };
|
||||
|
||||
# Don't filter anything at the VPN level
|
||||
firewall.outbound = [ { port = "any"; proto = "any"; host = "any"; } ];
|
||||
firewall.inbound = [ { port = "any"; proto = "any"; host = "any"; } ];
|
||||
|
||||
settings = {
|
||||
# Enable UDP holepunching both ways, which allows nodes to establish more direct connections with each other
|
||||
punchy = { punch = true; response = true; };
|
||||
};
|
||||
};
|
||||
|
||||
users.users.tvb = {
|
||||
uid = 1001;
|
||||
extraGroups = [
|
||||
"pipewire"
|
||||
];
|
||||
packages = [
|
||||
(pkgs.writeShellScriptBin "yt-dlp" ''
|
||||
exec $HOME/.env/bin/yt-dlp "$@"
|
||||
'')
|
||||
];
|
||||
services.zfs = {
|
||||
autoScrub = {
|
||||
enable = true;
|
||||
pools = ["catapool"];
|
||||
interval = "monthly";
|
||||
};
|
||||
};
|
||||
|
||||
users.users.katydid = {
|
||||
isNormalUser = true;
|
||||
uid = 1002;
|
||||
users.groups = {
|
||||
nas = { gid = 1600; };
|
||||
};
|
||||
|
||||
users.users.tvb = {
|
||||
isNormalUser = true;
|
||||
uid = 1001;
|
||||
password = "badpassword";
|
||||
extraGroups = ["wheel" "nas"];
|
||||
openssh.authorizedKeys.keyFiles = [
|
||||
../../keys/tvb.palamas.pub
|
||||
../../keys/tvb.stagirite.pub
|
||||
../../keys/tvb.vagrant.pub
|
||||
../../keys/monitor.isidore.pub
|
||||
../../keys/inquisitor.conduit.pub
|
||||
];
|
||||
};
|
||||
#./keys/tvb.empyrean.pub
|
||||
|
||||
nix.settings.cores = 4;
|
||||
nix.extraOptions = "experimental-features = nix-command flakes";
|
||||
}
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
# nas indexer server module
|
||||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
# Build the catacomb server package
|
||||
catacombServerSource = builtins.fetchGit {
|
||||
url = "https://git.alogoulogoi.com/Jaculabilis/catacomb-server.git";
|
||||
ref = "develop-nix";
|
||||
rev = "63574bb39cc777deb56a76548f08789d238fcfec";
|
||||
};
|
||||
catacombServer = pkgs.callPackage catacombServerSource {};
|
||||
|
||||
catacombUser = "tvb";
|
||||
|
||||
# Define the service directory, which pretty much only stores tokens
|
||||
catacombServerDir = "/var/lib/nas-indexer/";
|
||||
|
||||
# The address to bind to
|
||||
bindAddr = "10.22.20.2";
|
||||
|
||||
# Create a setup script to ensure the token directory exists
|
||||
catacombSetup = pkgs.writeShellScriptBin "catacomb-setup.sh" ''
|
||||
${pkgs.coreutils}/bin/mkdir -p ${catacombServerDir}tokens
|
||||
chown -R ${catacombUser} ${catacombServerDir}
|
||||
'';
|
||||
|
||||
# Host-mode server run script
|
||||
hostRun = pkgs.writeShellScriptBin "catacomb-run-host.sh" ''
|
||||
cd ${catacombServerDir}
|
||||
${catacombServer}/bin/gunicorn \
|
||||
--bind=localhost:5000 \
|
||||
--workers=3 \
|
||||
--log-level=debug \
|
||||
--env CATACOMB_ROOT=/nas \
|
||||
--env CATACOMB_TOKENS=${catacombServerDir}tokens \
|
||||
--env CATACOMB_MODE=host \
|
||||
--env CATACOMB_GUEST_HOST=catacomb.alogoulogoi.com \
|
||||
"catacomb.server:wsgi()"
|
||||
'';
|
||||
|
||||
# Guest-mode server run script
|
||||
guestRun = pkgs.writeShellScriptBin "catacomb-run-guest.sh" ''
|
||||
cd ${catacombServerDir}
|
||||
${catacombServer}/bin/gunicorn \
|
||||
--bind=localhost:5001 \
|
||||
--workers=3 \
|
||||
--log-level=debug \
|
||||
--env CATACOMB_ROOT=/nas \
|
||||
--env CATACOMB_TOKENS=${catacombServerDir}tokens \
|
||||
--env CATACOMB_MODE=guest \
|
||||
"catacomb.server:wsgi()"
|
||||
'';
|
||||
|
||||
# Guest-mode auth server for direct nginx file serving
|
||||
accessRun = pkgs.writeShellScriptBin "catacomb-run-access.sh" ''
|
||||
cd ${catacombServerDir}
|
||||
${catacombServer}/bin/gunicorn \
|
||||
--bind=localhost:5002 \
|
||||
--workers=3 \
|
||||
--log-level=debug \
|
||||
--env CATACOMB_TOKENS=${catacombServerDir}tokens \
|
||||
"catacomb.access.nginx:wsgi()"
|
||||
'';
|
||||
|
||||
in
|
||||
{
|
||||
# Run the setup script on activation
|
||||
system.activationScripts.catacombSetup = "${catacombSetup}/bin/catacomb-setup.sh";
|
||||
|
||||
# Set up the host mode service
|
||||
systemd.services."catacomb-host" = {
|
||||
enable = true;
|
||||
description = "catapool host-mode index server";
|
||||
script = "${hostRun}/bin/catacomb-run-host.sh";
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
WorkingDirectory = "${catacombServerDir}";
|
||||
};
|
||||
requires = [ "zfs.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
};
|
||||
|
||||
# Set up the guest mode service
|
||||
systemd.services."catacomb-guest" = {
|
||||
enable = true;
|
||||
description = "catapool guest-mode index server";
|
||||
script = "${guestRun}/bin/catacomb-run-guest.sh";
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = "${catacombUser}";
|
||||
WorkingDirectory = "${catacombServerDir}";
|
||||
};
|
||||
requires = [ "zfs.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
};
|
||||
|
||||
# Set up the access server service
|
||||
systemd.services."catacomb-access" = {
|
||||
enable = true;
|
||||
description = "catapool access token authenticator";
|
||||
script = "${accessRun}/bin/catacomb-run-access.sh";
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = "${catacombUser}";
|
||||
WorkingDirectory = "${catacombServerDir}";
|
||||
};
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 80 7470 7471 7472 ];
|
||||
|
||||
# Set up nginx to reverse proxy to these services
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
|
||||
# Serve the host server over the internal ip at the default port
|
||||
virtualHosts."catacomb-host-server" = {
|
||||
listen = [ { addr = bindAddr; } ];
|
||||
root = "/nas";
|
||||
locations."/".tryFiles = "\$uri @indexer";
|
||||
locations."@indexer".proxyPass = "http://localhost:5000";
|
||||
};
|
||||
|
||||
# Serve the guest server over the internal ip at a custom port
|
||||
virtualHosts."catacomb-guest-server" = {
|
||||
listen = [ { addr = bindAddr; port = 7472; } ];
|
||||
extraConfig = ''
|
||||
access_log /var/log/nginx/access.guest-server.log;
|
||||
'';
|
||||
locations."/".proxyPass = "http://localhost:5001";
|
||||
};
|
||||
|
||||
# Serve the auth server at a custom port internally
|
||||
virtualHosts."catacomb-auth" = {
|
||||
listen = [ { addr = bindAddr; port = 7471; } ];
|
||||
extraConfig = ''
|
||||
access_log /var/log/nginx/access.guest-auth.log;
|
||||
'';
|
||||
locations."/".proxyPass = "http://localhost:5002";
|
||||
};
|
||||
|
||||
# Serve files at a custom port internally
|
||||
virtualHosts."catacomb-guest-files" = {
|
||||
listen = [ { addr = bindAddr; port = 7470; } ];
|
||||
extraConfig = ''
|
||||
access_log /var/log/nginx/access.guest-files.log;
|
||||
'';
|
||||
locations."/".root = "/nas";
|
||||
};
|
||||
};
|
||||
|
||||
# Allow nginx to read catapool files
|
||||
users.users.nginx.extraGroups = ["nas"];
|
||||
}
|
|
@ -18,13 +18,14 @@
|
|||
fsType = "ext4";
|
||||
};
|
||||
|
||||
swapDevices = [ ];
|
||||
|
||||
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||
# still possible to use this option, but it's recommended to use it in conjunction
|
||||
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
|
||||
networking.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.eth0.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.nebula.beatific.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.wlan0.useDHCP = lib.mkDefault true;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
users.users.tvb.extraGroups = [
|
||||
"mopidy"
|
||||
];
|
||||
|
||||
users.groups.mopidy = {}; # rw group for media directory
|
||||
users.users.mopidy.extraGroups = [
|
||||
"mopidy"
|
||||
"pipewire" # necessary to allow the system service to play sound
|
||||
];
|
||||
services.mopidy = let
|
||||
mopidyPackages' = pkgs.mopidyPackages.overrideScope (prev: final: { extraPkgs = pkgs: [ pkgs.yt-dlp ]; });
|
||||
in {
|
||||
enable = true;
|
||||
extensionPackages = with mopidyPackages'; [
|
||||
mopidy-bandcamp
|
||||
mopidy-jellyfin
|
||||
mopidy-musicbox-webclient
|
||||
mopidy-youtube
|
||||
];
|
||||
configuration = ''
|
||||
[file]
|
||||
media_dirs =
|
||||
/media/music|Music
|
||||
|
||||
[jellyfin]
|
||||
hostname = jellyfin.home.ktvb.site
|
||||
username = mopidy
|
||||
password = mopidy
|
||||
libraries = Music,Weird Song Halftime
|
||||
album_format = {Name} ({ProductionYear})
|
||||
|
||||
[youtube]
|
||||
youtube_dl_package = yt_dlp
|
||||
'';
|
||||
};
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
];
|
||||
|
||||
boot.loader.grub = {
|
||||
efiSupport = true;
|
||||
efiInstallAsRemovable = true;
|
||||
device = "nodev";
|
||||
};
|
||||
|
||||
beatific.hostName = "centroid";
|
||||
beatific.defaults = {
|
||||
tvbSync = false;
|
||||
};
|
||||
|
||||
networking.networkmanager.enable = true;
|
||||
|
||||
services.pipewire = {
|
||||
enable = true;
|
||||
alsa.enable = true;
|
||||
alsa.support32Bit = true;
|
||||
pulse.enable = true;
|
||||
# To avoid needing an active user session, run a single system instance
|
||||
systemWide = true;
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
mpv # cli media player
|
||||
];
|
||||
|
||||
users.users.tvb.extraGroups = [
|
||||
"networkmanager"
|
||||
"pipewire"
|
||||
];
|
||||
|
||||
system.stateVersion = "23.11";
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ (modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usbhid" "sd_mod" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" =
|
||||
{ device = "/dev/disk/by-uuid/a08e9b3c-8ac7-433e-bf2c-6da234a2fb4a";
|
||||
fsType = "ext4";
|
||||
};
|
||||
|
||||
fileSystems."/boot" =
|
||||
{ device = "/dev/disk/by-uuid/5D60-DD0E";
|
||||
fsType = "vfat";
|
||||
};
|
||||
|
||||
swapDevices =
|
||||
[ { device = "/dev/disk/by-uuid/6dce2950-f8dd-49eb-b4d3-fdcf06cf920b"; }
|
||||
];
|
||||
|
||||
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||
# still possible to use this option, but it's recommended to use it in conjunction
|
||||
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
|
||||
networking.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.eno1.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.wlp0s20f0u1.useDHCP = lib.mkDefault true;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
}
|
|
@ -12,18 +12,18 @@
|
|||
'';
|
||||
locations = {
|
||||
# Forwards to the index server
|
||||
"/browse/".proxyPass = "http://10.22.20.2:7472/browse/";
|
||||
"/browse/".proxyPass = "http://10.7.3.16:7472/browse/";
|
||||
# Forwards to nginx via catacomb auth server
|
||||
"/".extraConfig = ''
|
||||
auth_request /auth;
|
||||
proxy_buffering off;
|
||||
proxy_pass http://10.22.20.2:7470/;
|
||||
proxy_pass http://10.7.3.16:7470/;
|
||||
'';
|
||||
"= /auth".extraConfig = ''
|
||||
internal;
|
||||
proxy_buffering off;
|
||||
proxy_pass_request_body off;
|
||||
proxy_pass http://10.22.20.2:7471/;
|
||||
proxy_pass http://10.7.3.16:7471/;
|
||||
proxy_set_header Content-Length "";
|
||||
proxy_set_header X-Original-URI $request_uri;
|
||||
'';
|
||||
|
|
|
@ -8,19 +8,17 @@
|
|||
imports =
|
||||
[ # Include the results of the hardware scan.
|
||||
./hardware-configuration.nix
|
||||
#./amanuensis.nix
|
||||
./amanuensis.nix
|
||||
./redstring.nix
|
||||
./catacomb.nix
|
||||
./gitea.nix
|
||||
./sync-pipeline.nix
|
||||
./inquisitor.nix
|
||||
];
|
||||
|
||||
beatific.hostName = "empyrean";
|
||||
beatific.isLighthouse = true;
|
||||
beatific.defaults.tvbSync = true;
|
||||
|
||||
# Use the GRUB 2 boot loader.
|
||||
boot.loader.grub = {
|
||||
enable = true;
|
||||
version = 2;
|
||||
device = "/dev/xvda";
|
||||
extraConfig = "serial --unit=0 --speed=115200 ; terminal_input serial console ; terminal_output serial console";
|
||||
};
|
||||
|
@ -28,14 +26,15 @@
|
|||
|
||||
nix = {
|
||||
package = pkgs.nixFlakes;
|
||||
settings.max-jobs = 2;
|
||||
maxJobs = 2;
|
||||
extraOptions = ''
|
||||
experimental-features = nix-command flakes
|
||||
'';
|
||||
};
|
||||
|
||||
swapDevices = [ { device = "/swap"; size = 1024; } ];
|
||||
|
||||
services.journald.extraConfig = ''
|
||||
SystemMaxUse=500M
|
||||
'';
|
||||
networking.hostName = "empyrean";
|
||||
|
||||
# The global useDHCP flag is deprecated, therefore explicitly set to false here.
|
||||
# Per-interface useDHCP will be mandatory in the future, so this generated config
|
||||
|
@ -43,87 +42,137 @@
|
|||
networking.useDHCP = false;
|
||||
networking.interfaces.eth0.useDHCP = true;
|
||||
|
||||
# Configure network proxy if necessary
|
||||
# networking.proxy.default = "http://user:password@proxy:port/";
|
||||
# networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
|
||||
|
||||
# Select internationalisation properties.
|
||||
i18n.defaultLocale = "en_US.UTF-8";
|
||||
console = {
|
||||
font = "Lat2-Terminus16";
|
||||
keyMap = "us";
|
||||
};
|
||||
|
||||
# Set your time zone.
|
||||
time.timeZone = "UTC";
|
||||
|
||||
# List packages installed in system profile. To search, run:
|
||||
# $ nix search wget
|
||||
environment.systemPackages = with pkgs; [
|
||||
vim htop git tinc_pre python3
|
||||
gitea
|
||||
];
|
||||
environment.variables.EDITOR = "vim";
|
||||
|
||||
services.nginx = let
|
||||
static-site = srv-dir: {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
root = "/srv/${srv-dir}/";
|
||||
extraConfig = ''
|
||||
access_log /var/log/nginx/access_${srv-dir}.log;
|
||||
index index.html;
|
||||
'';
|
||||
};
|
||||
service-stub = {
|
||||
rejectSSL = true;
|
||||
locations."/".return = "403";
|
||||
};
|
||||
in {
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
recommendedProxySettings = true;
|
||||
virtualHosts = {
|
||||
# Static pages
|
||||
"home.ktvb.site" = static-site "home.ktvb.site";
|
||||
"wedding.ktvb.site" = static-site "wedding.ktvb.site";
|
||||
"www.ktvb.site" = static-site "www.ktvb.site";
|
||||
"www.alogoulogoi.com" = static-site "www.alogoulogoi.com";
|
||||
"ecumene.alogoulogoi.com" = static-site "ecumene.alogoulogoi.com";
|
||||
# Home service stub domains
|
||||
"mopidy.home.ktvb.site" = service-stub;
|
||||
"jellyfin.home.ktvb.site" = service-stub;
|
||||
# mirror revproxy
|
||||
"mirror.alogoulogoi.com" = {
|
||||
"www.ktvb.site" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
root = "/srv/wedding/";
|
||||
extraConfig = ''
|
||||
access_log /var/log/nginx/access_mirror.alogoulogoi.com.log;
|
||||
access_log /var/log/nginx/access.ktvb.log;
|
||||
index index.html;
|
||||
'';
|
||||
};
|
||||
"www.alogoulogoi.com" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
root = "/srv/www/";
|
||||
extraConfig = ''
|
||||
access_log /var/log/nginx/access.www.log;
|
||||
index index.html;
|
||||
'';
|
||||
locations."/".proxyPass = "http://mirror.backyard.home:7474/";
|
||||
};
|
||||
# Deny all other subdomains
|
||||
"alogoulogoi.com" = {
|
||||
default = true;
|
||||
rejectSSL = true;
|
||||
locations."/".return = "444";
|
||||
};
|
||||
};
|
||||
};
|
||||
security.acme = {
|
||||
defaults.email = "tim.vanbaak+alogoulogoi@gmail.com";
|
||||
email = "tim.vanbaak+alogoulogoi@gmail.com";
|
||||
acceptTerms = true;
|
||||
};
|
||||
|
||||
services.openssh = {
|
||||
settings.PasswordAuthentication = false;
|
||||
settings.PermitRootLogin = "prohibit-password";
|
||||
services.gitolite = {
|
||||
enable = true;
|
||||
adminPubkey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDkSvOcY0eFuYqewc73MNHGP/Owzfnt+BZDSOCwr4h+gJenOBmXol695sRKdIw8phgshb6LsNyWeEAr3YISwzjdOvWNKpSsdyH/79VFIffC+/RBhPFhIPHn1zpHIwgthXji8FMmnO6B1bhJvbJxD5bUqhdBLnUeMhNgUkDj4Qi42S8yK1VZkgWRuPOTGqlzkODEdzG6OST7ndL58jEQaK8R2KRC2cZfrjingmPL+ORyf1/lGwyF6MEAmbQuE6UdspMs8FWt2e8jQJS+ZQ8dl+NDFrC1QfPRFpBJWnQceBcfAVZTtDaJpRhc4ClZstBy/bVRjiKeQiNv5NasjKRvvIvot4+LXmBKrXJs81enExtMSHMPuqPRlyVZLMMCVmdLDP/HUYOASDzlUhV/v5Wp0jjY4Wy0IWC7nm7P8EKsp1ZofwU6rJ9XPLpQJt7UUURX71h1FMaqi+lylW6xkD3LqD8oT5Bdp+Vs0bUbPQVRw1Fenjc6G1URU94GOAggyNgsWms= root@empyrean";
|
||||
};
|
||||
|
||||
services.intake = {
|
||||
listen = { addr = "10.22.20.1"; };
|
||||
users.tvb.enable = true;
|
||||
users.tvb.extraPackages = [ pkgs.intakeSources pkgs.openssh ];
|
||||
services.ntp = {
|
||||
enable = true;
|
||||
servers = ["time.nist.gov"];
|
||||
};
|
||||
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
passwordAuthentication = false;
|
||||
permitRootLogin = "prohibit-password";
|
||||
};
|
||||
|
||||
services.tinc.networks.beatific = {
|
||||
listenAddress = "0.0.0.0";
|
||||
chroot = false;
|
||||
};
|
||||
|
||||
services.nebula.networks.beatific = {
|
||||
enable = true;
|
||||
|
||||
# Network certificate and host credentials
|
||||
ca = "/etc/nebula/beatific/beatific.crt";
|
||||
cert = "/etc/nebula/beatific/empyrean.crt";
|
||||
key = "/etc/nebula/beatific/empyrean.key";
|
||||
|
||||
# This host has a well-known IP at its VPS host, so it can function as a lighthouse/entry node
|
||||
isLighthouse = true;
|
||||
|
||||
# Listen to connection requests from the public Internet
|
||||
listen.port = 4242;
|
||||
listen.host = "vpn.alogoulogoi.com";
|
||||
|
||||
# Don't filter anything at the VPN level
|
||||
firewall.outbound = [ { port = "any"; proto = "any"; host = "any"; } ];
|
||||
firewall.inbound = [ { port = "any"; proto = "any"; host = "any"; } ];
|
||||
|
||||
settings = {
|
||||
# Enable UDP holepunching both ways, which allows nodes to establish more direct connections with each other
|
||||
punchy = { punch = true; response = true; };
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall = {
|
||||
enable = true;
|
||||
allowPing = true;
|
||||
allowedTCPPorts = [
|
||||
22 # ssh
|
||||
80 # http
|
||||
443 # https
|
||||
655 # tinc
|
||||
];
|
||||
allowedUDPPorts = [
|
||||
655 # tinc
|
||||
];
|
||||
};
|
||||
|
||||
users.users.tvb = {
|
||||
isNormalUser = true;
|
||||
group = "tvb";
|
||||
extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
|
||||
};
|
||||
users.groups.tvb = {};
|
||||
|
||||
# This value determines the NixOS release from which the default
|
||||
# settings for stateful data, like file locations and database versions
|
||||
# on your system were taken. It‘s perfectly fine and recommended to leave
|
||||
# this value at the release version of the first install of this system.
|
||||
# Before changing this value read the documentation for this option
|
||||
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
|
||||
system.stateVersion = "23.05"; # Did you read the comment?
|
||||
system.stateVersion = "20.03"; # Did you read the comment?
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -5,26 +5,26 @@
|
|||
{
|
||||
# Gitea configuration
|
||||
services.gitea = {
|
||||
# Enable Gitea and configure for reverse proxy
|
||||
enable = true;
|
||||
httpAddress = "127.0.0.1";
|
||||
httpPort = 3300;
|
||||
domain = "git.alogoulogoi.com";
|
||||
rootUrl = "https://git.alogoulogoi.com/";
|
||||
|
||||
# Private server
|
||||
disableRegistration = true;
|
||||
#useWizard = true; # Needed for first-time building
|
||||
|
||||
# Settings
|
||||
appName = "Horse Codes";
|
||||
lfs.enable = true;
|
||||
# Disabled until I figure out how to make this not take up multiple gigabytes
|
||||
dump = {
|
||||
enable = false;
|
||||
enable = true;
|
||||
interval = "weekly";
|
||||
};
|
||||
log.level = "Info";
|
||||
settings = {
|
||||
"server" = {
|
||||
# Configuration for reverse proxy
|
||||
ROOT_URL = "https://git.alogoulogoi.com/";
|
||||
HTTP_ADDR = "127.0.0.1";
|
||||
HTTP_PORT = 3300;
|
||||
DOMAIN = "git.alogoulogoi.com";
|
||||
};
|
||||
"repository" = {
|
||||
DEFAULT_PRIVATE = true;
|
||||
};
|
||||
|
@ -40,19 +40,11 @@
|
|||
"security" = {
|
||||
INSTALL_LOCK = true;
|
||||
};
|
||||
"session" = {
|
||||
SESSION_LIFE_TIME = 86400 * 7; # 1 week
|
||||
};
|
||||
"picture" = {
|
||||
DISABLE_GRAVATAR = true;
|
||||
};
|
||||
#"cron.archive_cleanup".ENABLED = false; # TODO: figure out why this was enabled
|
||||
"cron.archive_cleanup".ENABLED = false;
|
||||
"cron.sync_external_users".ENABLED = false;
|
||||
log.LEVEL = "Info";
|
||||
# Private server
|
||||
service.DISABLE_REGISTRATION = true;
|
||||
# Disable package manager functionality
|
||||
packages.ENABLED = false;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -72,8 +64,5 @@
|
|||
proxy_pass http://localhost:3300/;
|
||||
'';
|
||||
};
|
||||
|
||||
# Give tvb group access to gitea config
|
||||
users.users.tvb.extraGroups = [ "gitea" ];
|
||||
}
|
||||
|
||||
|
|
|
@ -18,5 +18,5 @@
|
|||
|
||||
swapDevices = [ ];
|
||||
|
||||
nix.settings.max-jobs = lib.mkDefault 1;
|
||||
nix.maxJobs = lib.mkDefault 1;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
{pkgs, ...}:
|
||||
|
||||
let
|
||||
# Import the inquisitor package and build it
|
||||
inquisitorSource = pkgs.fetchFromGitHub {
|
||||
owner = "Jaculabilis";
|
||||
repo = "Inquisitor";
|
||||
rev = "a6d961aba948d3a682dbde12dbaa8805eadbbd84";
|
||||
sha256 = "10n6c5zvi27f92b7am0rrdizxz0mlp3rw1y1jyd44b57ykk7x6fr";
|
||||
};
|
||||
inquisitor = pkgs.callPackage inquisitorSource {};
|
||||
|
||||
# Define the inquisitor data directory
|
||||
inquisiDir = "/var/lib/inquisitor";
|
||||
|
||||
# Define an scp helper for executing in cron jobs
|
||||
scp-helper = pkgs.writeShellScriptBin "scp-helper" ''
|
||||
${pkgs.openssh}/bin/scp -i ${inquisiDir}/inquisitor.key -oStrictHostKeyChecking=no "$@"
|
||||
'';
|
||||
|
||||
# Define the inquisitor service user
|
||||
inquisitorUser = {
|
||||
name = "inquisitor";
|
||||
group = "inquisitor";
|
||||
description = "Inquisitor service user";
|
||||
isSystemUser = true;
|
||||
shell = pkgs.bashInteractive;
|
||||
packages = [ inquisitor pkgs.cron ];
|
||||
};
|
||||
|
||||
# Create the inquisitor config file in the nix store, pointing to /var/lib/
|
||||
inquisitorConfig = pkgs.writeTextFile {
|
||||
name = "inquisitor.conf";
|
||||
text = ''
|
||||
DataPath = ${inquisiDir}/data/
|
||||
SourcePath = ${inquisiDir}/sources/
|
||||
CachePath = ${inquisiDir}/cache/
|
||||
Verbose = false
|
||||
LogFile = ${inquisiDir}/inquisitor.log
|
||||
'';
|
||||
};
|
||||
|
||||
# Create a setup script to ensure the service directory state
|
||||
inquisitorSetup = pkgs.writeShellScriptBin "inquisitor-setup.sh" ''
|
||||
# Ensure the service directory and the default source directory
|
||||
${pkgs.coreutils}/bin/mkdir -p ${inquisiDir}/data/inquisitor/
|
||||
${pkgs.coreutils}/bin/mkdir -p ${inquisiDir}/sources/
|
||||
${pkgs.coreutils}/bin/mkdir -p ${inquisiDir}/cache/
|
||||
if [ ! -f ${inquisiDir}/data/inquisitor/state ]; then
|
||||
${pkgs.coreutils}/bin/echo "{}" > ${inquisiDir}/data/inquisitor/state
|
||||
fi
|
||||
|
||||
# Ensure the service owns the folders
|
||||
chown -R ${inquisitorUser.name} ${inquisiDir}
|
||||
|
||||
# Ensure the scp helper is present
|
||||
if [ -f ${inquisiDir}/scp-helper ]; then
|
||||
rm ${inquisiDir}/scp-helper
|
||||
fi
|
||||
ln -s -t ${inquisiDir} ${scp-helper}/bin/scp-helper
|
||||
'';
|
||||
|
||||
# Create a run script for the server
|
||||
inquisitorRun = pkgs.writeShellScriptBin "inquisitor-run.sh" ''
|
||||
cd ${inquisiDir}
|
||||
${inquisitor}/bin/gunicorn \
|
||||
--bind=localhost:24133 \
|
||||
--workers=4 \
|
||||
--timeout 120 \
|
||||
--log-level debug \
|
||||
"inquisitor.app:wsgi()"
|
||||
'';
|
||||
|
||||
# Create a wrapper to execute the cli as the service user
|
||||
inquisitorWrapper = pkgs.writeShellScriptBin "inq" ''
|
||||
sudo --user=inquisitor ${inquisitor}/bin/inquisitor "$@"
|
||||
'';
|
||||
in
|
||||
{
|
||||
users.users.inquisitor = inquisitorUser;
|
||||
users.groups.inquisitor = {};
|
||||
|
||||
# Link the config in /etc to avoid envvar shenanigans
|
||||
environment.etc."inquisitor.conf".source = "${inquisitorConfig}";
|
||||
|
||||
# Give all users the inq wrapper
|
||||
environment.systemPackages = [ inquisitorWrapper ];
|
||||
|
||||
# Allow the sudo in the cli wrapper without password
|
||||
security.sudo.extraRules = [{
|
||||
commands = [{
|
||||
command = "${inquisitor}/bin/inquisitor";
|
||||
options = [ "NOPASSWD" ];
|
||||
}];
|
||||
runAs = "${inquisitorUser.name}";
|
||||
groups = [ "users" ];
|
||||
}];
|
||||
|
||||
# Run the setup script on activation
|
||||
system.activationScripts.inquisitorSetup = "${inquisitorSetup}/bin/inquisitor-setup.sh";
|
||||
|
||||
# Set up the inquisitor service
|
||||
systemd.services.inquisitor =
|
||||
{
|
||||
description = "Inquisitor server";
|
||||
script = "${inquisitorRun}/bin/inquisitor-run.sh";
|
||||
serviceConfig = {
|
||||
User = "${inquisitorUser.name}";
|
||||
Type = "simple";
|
||||
};
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
enable = true;
|
||||
};
|
||||
|
||||
# Set up nginx to reverse proxy from the beatific url to the inq server
|
||||
services.nginx.enable = true;
|
||||
services.nginx.virtualHosts.inquisitorHost = {
|
||||
listen = [ { addr = "10.7.3.1"; port = 80; } ];
|
||||
locations."/".extraConfig = ''
|
||||
access_log /var/log/nginx/access.inquisitor.log;
|
||||
proxy_buffering off;
|
||||
proxy_pass http://localhost:24133/;
|
||||
'';
|
||||
};
|
||||
|
||||
# Allow nginx through the firewall
|
||||
networking.firewall = {
|
||||
allowedTCPPorts = [
|
||||
80 # http
|
||||
443 # https
|
||||
];
|
||||
};
|
||||
|
||||
# Enable cron, but don't set up any system cron jobs
|
||||
# Inquisitor updates will be managed manually
|
||||
services.cron.enable = true;
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
# redstring server module
|
||||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
# Import package
|
||||
redstringSource = builtins.fetchGit {
|
||||
url = "https://git.alogoulogoi.com/Jaculabilis/redstring.git";
|
||||
ref = "master";
|
||||
rev = "91dd353ad1d48118452a949b15e100b3035bf297";
|
||||
};
|
||||
redstring = pkgs.callPackage redstringSource {};
|
||||
|
||||
# Define the data directory
|
||||
redstringDir = "/var/lib/redstring/";
|
||||
redstringData = "${redstringDir}docs/";
|
||||
|
||||
# Define the service user
|
||||
redstringUser = {
|
||||
name = "redstring";
|
||||
description = "redstring service user";
|
||||
group = "redstring";
|
||||
isSystemUser = true;
|
||||
};
|
||||
|
||||
# Create the public server config file in the nix store
|
||||
publicConfigAttrs = {
|
||||
root = redstringData;
|
||||
edit = false;
|
||||
};
|
||||
publicConfig = pkgs.writeTextFile { name = "redstring-config-external.json"; text = (builtins.toJSON publicConfigAttrs); };
|
||||
|
||||
# Create the private server config file in the nix store
|
||||
privateConfig = pkgs.writeTextFile {
|
||||
name = "redstring-config-internal.json";
|
||||
text = (builtins.toJSON {
|
||||
root = redstringData;
|
||||
edit = true;
|
||||
});
|
||||
};
|
||||
|
||||
# Create a setup script to ensure the data directory exists
|
||||
redstringSetup = pkgs.writeShellScriptBin "redstring-setup.sh" ''
|
||||
# Ensure the service directory
|
||||
${pkgs.coreutils}/bin/mkdir -p ${redstringData}
|
||||
|
||||
# Ensure ownership
|
||||
chown -R ${redstringUser.name} ${redstringDir}
|
||||
chmod 700 ${redstringDir}
|
||||
'';
|
||||
|
||||
# Create a run script for the public server
|
||||
publicRun = pkgs.writeShellScriptBin "redstring-run-external.sh" ''
|
||||
cd ${redstringDir}
|
||||
${redstring}/bin/gunicorn \
|
||||
--bind=localhost:24144 \
|
||||
--workers=3 \
|
||||
--log-level debug \
|
||||
--env REDSTRING_CONFIG=${publicConfig} \
|
||||
"redstring.server:wsgi()"
|
||||
'';
|
||||
|
||||
# Create a run script for the private server
|
||||
privateRun = pkgs.writeShellScriptBin "redstring-run-internal.sh" ''
|
||||
cd ${redstringDir};
|
||||
${redstring}/bin/gunicorn \
|
||||
--bind=10.7.3.1:24145 \
|
||||
--workers=3 \
|
||||
--log-level debug \
|
||||
--env REDSTRING_CONFIG=${privateConfig} \
|
||||
"redstring.server:wsgi()"
|
||||
'';
|
||||
in
|
||||
{
|
||||
users.users.redstring = redstringUser;
|
||||
users.groups.redstring = {};
|
||||
|
||||
# Run the setup script on activation
|
||||
system.activationScripts.redstringSetup = "${redstringSetup}/bin/redstring-setup.sh";
|
||||
|
||||
# Set up the public redstring service
|
||||
systemd.services."redstring-public" =
|
||||
{
|
||||
description = "redstring public read-only server";
|
||||
script = "${publicRun}/bin/redstring-run-external.sh";
|
||||
serviceConfig = {
|
||||
User = "${redstringUser.name}";
|
||||
Type = "simple";
|
||||
};
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
enable = true;
|
||||
};
|
||||
|
||||
# Set up the private redstring service
|
||||
systemd.services."redstring-private" =
|
||||
{
|
||||
description = "redstring private editable server";
|
||||
script = "${privateRun}/bin/redstring-run-internal.sh";
|
||||
serviceConfig = {
|
||||
User = redstringUser.name;
|
||||
Type = "simple";
|
||||
};
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
enable = true;
|
||||
};
|
||||
|
||||
# Configure nginx to forward to the public server at the docs subdomain
|
||||
services.nginx.virtualHosts."docs.alogoulogoi.com" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
extraConfig = ''
|
||||
access_log /var/log/nginx/access.docs.log;
|
||||
'';
|
||||
locations."/".proxyPass = "http://localhost:24144";
|
||||
};
|
||||
|
||||
# Open the firewall to the private server's port
|
||||
networking.firewall.allowedTCPPorts = [ 24145 ];
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
{ pkgs, ... }:
|
||||
|
||||
# exiftool config and script based on that of @numinit
|
||||
|
||||
let
|
||||
# An exiftool config that adds the OriginTimestamp property containing the best guess for file creation time
|
||||
exiftool-config = pkgs.writeText "exiftool.config" ''
|
||||
%Image::ExifTool::UserDefined = (
|
||||
'Image::ExifTool::Composite' => {
|
||||
OriginTimestamp => {
|
||||
Desire => {
|
||||
0 => 'CreateDate',
|
||||
1 => 'DateTimeOriginal',
|
||||
2 => 'FileModifyDate'
|
||||
},
|
||||
ValueConv => '$val[0] || $val[1] || $val[2] || undef',
|
||||
PrintConv => '$self->ConvertDateTime($val)',
|
||||
PrintConvInv => '$self->InverseDateTime($val)'
|
||||
}
|
||||
}
|
||||
)
|
||||
'';
|
||||
|
||||
# A tool to use `find` and `exiftool` to sort images into YMD folders
|
||||
sibd = pkgs.writeShellScriptBin "sort-images-by-date" ''
|
||||
set -euo pipefail
|
||||
|
||||
if [ $# -lt 3 ]; then
|
||||
echo "Usage: $0 [prefix] [src] [dest] [exiftool args...]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
prefix="$1"
|
||||
src="$2"
|
||||
dest="$3"
|
||||
# Remove $1, $2, $3 from $@ so the remainder can be passed to exiftool
|
||||
shift; shift; shift
|
||||
|
||||
# This find expression matches .jpg/.png modified 14+ days ago.
|
||||
# The -not (-name -prune) expressions exclude directories from the results by name.
|
||||
# The exiftool command will move matched files to $dest/$prefix/year/month/day/filename.ext.
|
||||
# -config loads the config defined above, which adds the OriginTimestamp composite property
|
||||
# -filename tells exiftool to move each file to a new filename, $OriginTimestamp
|
||||
# -d defines how the timestamp will be converted to a string, which ends up handling the pathing
|
||||
${pkgs.findutils}/bin/find $src \
|
||||
-not \( -name FalseKnees -prune \) \
|
||||
-not \( -name Background -prune \) \
|
||||
-type f \
|
||||
-mtime +14 \
|
||||
\( -name "*.jpg" -or -name "*.png" \) \
|
||||
-exec ${pkgs.exiftool}/bin/exiftool \
|
||||
-config ${exiftool-config} \
|
||||
-api largefilesupport=1 \
|
||||
-progress \
|
||||
-filename'<OriginTimestamp' \
|
||||
-d "''${dest}/''${prefix}/%Y-%m-%d/%%f%%-c.%%le" \
|
||||
"$@" \
|
||||
{} +
|
||||
'';
|
||||
|
||||
# Script for cron jobs that sends output to journalctl -t sync-pipeline
|
||||
sibd-cron = prefix: src: dest: pkgs.writeShellScript "sibd-cron" ''
|
||||
${pkgs.systemd}/bin/systemd-cat -t sync-pipeline ${sibd}/bin/sort-images-by-date ${prefix} ${src} ${dest}
|
||||
'';
|
||||
in {
|
||||
environment.systemPackages = [ sibd ];
|
||||
|
||||
services.cron = {
|
||||
enable = true;
|
||||
systemCronJobs = [
|
||||
"0 0 * * 1 tvb ${sibd-cron "nokia" "/home/tvb/phone-sync/DCIM" "/home/tvb/phone-sync/staging"}"
|
||||
"0 0 * * 1 tvb ${sibd-cron "nokia" "/home/tvb/phone-sync/Pictures" "/home/tvb/phone-sync/staging"}"
|
||||
];
|
||||
};
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[
|
||||
./hardware-configuration.nix
|
||||
];
|
||||
|
||||
beatific.hostName = "imperium";
|
||||
|
||||
boot.loader.grub = {
|
||||
enable = true;
|
||||
device = "/dev/sda";
|
||||
};
|
||||
|
||||
fileSystems."/home/tvb/backyard" = {
|
||||
device = "//backyard.home/tvb";
|
||||
fsType = "cifs";
|
||||
options = [
|
||||
"x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s,credentials=/home/tvb/.local/state/smb/backyard,uid=1000,gid=988"
|
||||
];
|
||||
};
|
||||
|
||||
networking.networkmanager.enable = true;
|
||||
|
||||
time.timeZone = "America/Los_Angeles";
|
||||
|
||||
services.xserver = {
|
||||
enable = true;
|
||||
displayManager.gdm.enable = true;
|
||||
desktopManager.gnome.enable = true;
|
||||
|
||||
# keyboard
|
||||
xkb.layout = "us";
|
||||
xkb.variant = "";
|
||||
};
|
||||
|
||||
# Enable sound with pipewire.
|
||||
sound.enable = true;
|
||||
hardware.pulseaudio.enable = false;
|
||||
security.rtkit.enable = true;
|
||||
services.pipewire = {
|
||||
enable = true;
|
||||
alsa.enable = true;
|
||||
alsa.support32Bit = true;
|
||||
pulse.enable = true;
|
||||
};
|
||||
|
||||
# This seems to be sufficient to autodetect the printing functionality of HP OfficeJet 6950
|
||||
services.printing.enable = true;
|
||||
services.printing.drivers = [ pkgs.hplip ];
|
||||
services.avahi = {
|
||||
enable = true;
|
||||
nssmdns4 = true;
|
||||
openFirewall = true;
|
||||
};
|
||||
|
||||
users.users.tvb = {
|
||||
extraGroups = [ "networkmanager" "docker" ];
|
||||
packages = [
|
||||
(pkgs.writeShellScriptBin "yt-dlp" ''exec $HOME/.yt-dlp/bin/yt-dlp "$@"'')
|
||||
];
|
||||
};
|
||||
|
||||
# Configs needed to run TF2 on integrated graphics
|
||||
programs.steam.enable = true;
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
services.xserver.videoDrivers = [ "i915" ];
|
||||
hardware.opengl.enable = true;
|
||||
hardware.opengl.driSupport32Bit = true;
|
||||
|
||||
beatific.extraPrograms = true;
|
||||
environment.systemPackages = with pkgs; [
|
||||
audacity
|
||||
bitwarden
|
||||
bitwarden-cli
|
||||
comic-mono
|
||||
firefox
|
||||
gnome.gnome-terminal
|
||||
gthumb
|
||||
libreoffice
|
||||
mpv
|
||||
obsidian
|
||||
unzip
|
||||
];
|
||||
programs.nix-ld.enable = true;
|
||||
|
||||
networking.firewall = {
|
||||
enable = false;
|
||||
};
|
||||
|
||||
# This value governs how some stateful data, like databases, are handled
|
||||
# across different versions of NixOS. This should not be changed to a new
|
||||
# release unless the sysadmin has determined that no services would be
|
||||
# adversely affected by changing this.
|
||||
system.stateVersion = "23.11";
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ (modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usb_storage" "usbhid" "sd_mod" "sr_mod" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-intel" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" =
|
||||
{ device = "/dev/disk/by-uuid/798089ca-f249-431d-aa08-65909b85a184";
|
||||
fsType = "ext4";
|
||||
};
|
||||
|
||||
swapDevices =
|
||||
[ { device = "/dev/disk/by-uuid/5d55f9b7-cde3-403d-9c91-61c4b68c71f9"; }
|
||||
];
|
||||
|
||||
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||
# still possible to use this option, but it's recommended to use it in conjunction
|
||||
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
|
||||
networking.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.eno1.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.nebula.beatific.useDHCP = lib.mkDefault true;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[
|
||||
./hardware-configuration.nix
|
||||
];
|
||||
|
||||
beatific.hostName = "unfolder";
|
||||
beatific.extraPrograms = true;
|
||||
|
||||
# Bootloader.
|
||||
boot.loader.grub = {
|
||||
enable = true;
|
||||
device = "/dev/sda";
|
||||
};
|
||||
|
||||
networking.networkmanager.enable = true;
|
||||
|
||||
fileSystems."/mnt/backyard" = {
|
||||
device = "//backyard.home/tvb";
|
||||
fsType = "cifs";
|
||||
options = [
|
||||
"x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s,credentials=/home/tvb/.local/state/smb/backyard"
|
||||
];
|
||||
};
|
||||
|
||||
# Override time zone to PST
|
||||
time.timeZone = "America/Los_Angeles";
|
||||
|
||||
# Enable Gnome because it has a virtual keyboard for tablet mode
|
||||
services.xserver = {
|
||||
enable = true;
|
||||
displayManager.gdm.enable = true;
|
||||
desktopManager.gnome.enable = true;
|
||||
|
||||
# keymap configuration
|
||||
xkb.layout = "us";
|
||||
xkb.variant = "";
|
||||
};
|
||||
|
||||
# Enable sound with pipewire.
|
||||
sound.enable = true;
|
||||
hardware.pulseaudio.enable = false;
|
||||
security.rtkit.enable = true;
|
||||
services.pipewire = {
|
||||
enable = true;
|
||||
alsa.enable = true;
|
||||
alsa.support32Bit = true;
|
||||
pulse.enable = true;
|
||||
};
|
||||
|
||||
systemd.user.services.yoga-rotate = {
|
||||
enable = false; # TODO
|
||||
description = "ThinkPad Yoga display rotation";
|
||||
#wantedBy = ["multi-user.target"];
|
||||
wantedBy = [ "graphical-session.target" ];
|
||||
#requires = ["display-manager.service"];
|
||||
partOf = [ "graphical-session.target" ];
|
||||
#after = ["display-manager.service"];
|
||||
path = [ pkgs.gnome-randr ];
|
||||
serviceConfig = {
|
||||
#Type = "simple";
|
||||
ExecStart = "${pkgs.python3}/bin/python /home/tvb/rotate.py";
|
||||
#KillMode = "process";
|
||||
#User = "tvb";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 5;
|
||||
};
|
||||
#environment = {
|
||||
# DISPLAY = ":0";
|
||||
# XAUTHORITY = "/home/tvb/.Xauthority";
|
||||
#};
|
||||
};
|
||||
|
||||
users.users.tvb = {
|
||||
extraGroups = [ "networkmanager" "docker" ];
|
||||
packages = with pkgs; [
|
||||
gnome-randr
|
||||
python3
|
||||
(writeShellScriptBin "single-file" ''
|
||||
exec ${single-file-cli}/bin/single-file --browser-executable-path ${chromium}/bin/chromium "$@"
|
||||
'')
|
||||
];
|
||||
};
|
||||
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
environment.systemPackages = with pkgs; [
|
||||
bitwarden-cli
|
||||
bitwarden-desktop
|
||||
comic-mono
|
||||
firefox
|
||||
gnome.gnome-terminal
|
||||
libreoffice
|
||||
obsidian
|
||||
mpv
|
||||
qutebrowser
|
||||
];
|
||||
|
||||
networking.firewall = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
# This seems to be sufficient to autodetect the printing functionality of HP OfficeJet 6950
|
||||
services.printing.enable = true;
|
||||
services.printing.drivers = [ pkgs.hplip ];
|
||||
services.avahi = {
|
||||
enable = true;
|
||||
nssmdns4 = true;
|
||||
openFirewall = true;
|
||||
};
|
||||
|
||||
# This value governs how some stateful data, like databases, are handled
|
||||
# across different versions of NixOS. This should not be changed to a new
|
||||
# release unless the sysadmin has determined that no services would be
|
||||
# adversely affected by changing this.
|
||||
system.stateVersion = "22.11";
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ (modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usb_storage" "sd_mod" "rtsx_pci_sdmmc" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" =
|
||||
{ device = "/dev/disk/by-uuid/3a4363d6-c437-45ab-9f35-6831eb4a2cd8";
|
||||
fsType = "ext4";
|
||||
};
|
||||
|
||||
swapDevices =
|
||||
[ { device = "/dev/disk/by-uuid/4a083b38-322e-4d35-9877-a8dc1cda21d5"; }
|
||||
];
|
||||
|
||||
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||
# still possible to use this option, but it's recommended to use it in conjunction
|
||||
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
|
||||
networking.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.wlp4s0.useDHCP = lib.mkDefault true;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
{
|
||||
beatific = ''
|
||||
____ ______ _______ _____ ______ _____ ______ ./|,,/|
|
||||
| _ \| ____| /\ |__ __|_ _| ____|_ _|/ ____/ < o o|
|
||||
| |_) | |__ / \ | | | | | |__ | | | | <\ ( |
|
||||
| _ <| __| / /\ \ | | | | | __| | | | | <\\ |\ |
|
||||
| |_) | |____/ ____ \ | | _| |_| | _| |_| |___<\\\ |(__)
|
||||
|____/|_____/_/ \_\|_| |_____|_| |_____|\_____|\\ |
|
||||
'';
|
||||
|
||||
backyard = ''
|
||||
____ ______ _ ____ __ _____ _____ ./|,,/|
|
||||
| _ \ /\ / ____/| | / /\ \ / / /\ | __ \| __ \ < o o|
|
||||
| |_) | / \ | | | |/ / \ \ / / / \ | |__) | | | |</ ( |
|
||||
| _ < / /\ \| | | < \ V / / /\ \ | _ /| | | |// |\ |
|
||||
| |_) / ____ | |____ | |\ \ | | / ____ \| | \ \| |__| |// |(__)
|
||||
|____/_/ \_\_____\|_| \_\ |_|/_/ \_|_| \_|_____//// |
|
||||
'';
|
||||
|
||||
catacomb = ''
|
||||
______ _______ ______ ____ __ __ ____ ./|,,/|
|
||||
/ ____/ /\ |__ __| /\ / ____// __ \| \ / | _ \ < o o|
|
||||
| | / \ | | / \ | | | | | | . \/ . | |_) |\ ( |
|
||||
| | / /\ \ | | / /\ \| | | | | | |\ /| | _ <\\ |\ |
|
||||
| |____ / ____ \ | | / ____ | |__ _| |__| | | \/ | | |_) |\ |(__)
|
||||
\_____/_/ \_\|_|/_/ \_\_____\\____/|_| |_|____/\\ |
|
||||
'';
|
||||
|
||||
centroid = ''
|
||||
______ _____ _ _ _______ _____ ____ _____ _____ ./|,,/|
|
||||
/ ____/| ___| \ | |__ __| __ \ / __ \|_ _| __ \ < o o|
|
||||
| | | |__ | \| | | | | |__) | | | | | | | | | |\ ( |
|
||||
| | | __|| . ' | | | | _ /| | | | | | | | | |\ |\ |
|
||||
| |____ | |___| |\ | | | | | \ \| |__| |_| |_| |__| |\ |(__)
|
||||
\_____\|_____|_| \_| |_| |_| \_\\____/|_____|_____/\\ |
|
||||
'';
|
||||
|
||||
empyrean = ''
|
||||
______ __ __ _______ _______ ______ _ _ ./|,,/|
|
||||
| ____| \ / | __ \ \ / | __ \| ____| /\ | \ | | < o o|
|
||||
| |__ | . \/ . | |__) \ \ / /| |__) | |__ / \ | \| |</ ( |
|
||||
| __| | |\ /| | ___/ \ V / | _ /| __| / /\ \ | . ' |// |\ |
|
||||
| |____| | \/ | | | | | | | \ \| |____ / ____ \| |\ |// |(__)
|
||||
|______|_| |_|_| |_| |_| \_|______/_/ \_|_| \_|// |
|
||||
'';
|
||||
|
||||
imperium = ''
|
||||
_____ __ __ ____ _____ _____ _____ _ _ __ __ ./|,,/|
|
||||
|_ _| \ / | __ \| ___| __ \|_ _| | | | \ / |< o o|
|
||||
| | | . \/ . | |__) | |__ | |__) | | | | | | | . \/ . |\ ( |
|
||||
| | | |\ /| | ___/| __|| _ / | | | | | | |\ /| |\ |\ |
|
||||
_| |_| | \/ | | | | |___| | \ \ _| |_| |__| | | \/ | |\ |(__)
|
||||
|_____|_| |_|_| |_____|_| \_|_____|\____/|_| <|_|\ |
|
||||
'';
|
||||
|
||||
unfolder = ''
|
||||
_ _ _ _ ______ ____ _ _____ ______ _____ ./|,,/|
|
||||
| | | | \ | | ____|/ __ \| | | __ \| ____| __ \ < o o|
|
||||
| | | | \| | |__ | | | | | | | | | |__ | |__) |\ ( |
|
||||
| | | | . ' | __| | | | | | | | | | __| | _ /\\ |\ |
|
||||
| |__| | |\ | | | |__| | |___| |__| | |____| | \ \\\ |(__)
|
||||
\____/|_| \_|_| \____/|_____|_____/|______|_| <\_\\ |
|
||||
'';
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
# Set the title bar to user@host: pwd
|
||||
_TITLE_BAR="\u@\h: \w"
|
||||
_SET_TITLE_BAR="\[\e]0;$_TITLE_BAR\a\]"
|
||||
# Shorten $HOME to ~ in PWD and shorten other path dir names to one letter
|
||||
_pwd() {
|
||||
if [[ "$PWD" =~ ^"$HOME"($) ]]; then
|
||||
printf "~"
|
||||
elif [[ "$PWD" = "/" ]]; then
|
||||
printf "/"
|
||||
else
|
||||
if [[ "$PWD" =~ ^"$HOME"/ ]]; then
|
||||
printf "~"
|
||||
DIR="${PWD#$HOME}"
|
||||
else
|
||||
DIR="$PWD"
|
||||
fi
|
||||
for path_elem in $(dirname "$DIR" | tr / '\n' | grep . | cut -c-1); do
|
||||
printf '/%s' $path_elem
|
||||
done
|
||||
printf "/$(basename "$DIR")"
|
||||
fi
|
||||
}
|
||||
_DIR='$(_pwd)'
|
||||
# Color codes
|
||||
_GREEN="\[\033[32;1m\]"
|
||||
_DIM="\[\e[32;2m\]"
|
||||
_OLIVE="\[\e[33;2m\]"
|
||||
_RESET="\[\e[0m\]"
|
||||
_HOST=$(if [ -z "$SSH_CLIENT" ]; then echo $_DIM; else echo $_OLIVE; fi)
|
||||
# Nested shell level
|
||||
_SHLVL=$(printf '\$%.0s' $(seq 1 $SHLVL))
|
||||
# SSH detection
|
||||
_SSH='$([ ! -z "$SSH_CLIENT" ] && echo "=>")'
|
||||
# Build prompt
|
||||
export PS1="$_SET_TITLE_BAR$_DIM[\A \u@$_RESET$_HOST\h$_DIM:$_RESET$_GREEN$_DIR$_RESET$_DIM]$_SHLVL$_RESET "
|
||||
|
||||
export HISTCONTROL=ignoreboth
|
|
@ -1,273 +0,0 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkDefault mkIf mkMerge mkOption mkOverride types;
|
||||
cfg = config.beatific;
|
||||
mkFlag = description: mkOption {
|
||||
type = types.bool;
|
||||
inherit description;
|
||||
default = true;
|
||||
};
|
||||
in {
|
||||
options = {
|
||||
beatific = {
|
||||
# The host name is reused for beatific-specific configuration.
|
||||
# The bulk of common config is handled in beatific.defaults below, but
|
||||
# having one option without a default ensures that the module cannot be
|
||||
# imported accidentally.
|
||||
hostName = mkOption {
|
||||
type = types.str;
|
||||
description = "Hostname";
|
||||
};
|
||||
|
||||
isLighthouse = mkOption {
|
||||
type = types.bool;
|
||||
description = "Whether this host is a Nebula lighthouse";
|
||||
default = false;
|
||||
};
|
||||
|
||||
extraPrograms = mkOption {
|
||||
type = types.bool;
|
||||
description = "Additional default programs";
|
||||
default = false;
|
||||
};
|
||||
|
||||
# Groups of related defaults can be disabled by flipping off the switches here:
|
||||
# beatific.defaults.${category} = false;
|
||||
# They default to true because the point is to do these things by default.
|
||||
defaults = {
|
||||
time = mkFlag "Default time zone and NTP";
|
||||
i18n = mkFlag "Default locale settings";
|
||||
programs = mkFlag "Default installed programs";
|
||||
ssh = mkFlag "Default sshd settings";
|
||||
nebula = mkFlag "Default beatific nebula settings";
|
||||
tvb = mkFlag "Default tvb account";
|
||||
tvbSync = mkFlag "Configure system syncthing for tvb";
|
||||
hosts = mkFlag "Default 10.22.20.* DNS host entries";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
{
|
||||
# Options to always set
|
||||
networking.hostName = cfg.hostName;
|
||||
nix.extraOptions = "experimental-features = nix-command flakes";
|
||||
nix.settings.trusted-users = [ "tvb" ];
|
||||
# Link /etc/nixos to the flake source
|
||||
environment.etc.nixos.source = ./..;
|
||||
environment.etc."bashrc.local".source = ./bashrc;
|
||||
environment.shellAliases = {
|
||||
# Shortcut for nixos-rebuild
|
||||
nr = "sudo nixos-rebuild --fast --flake $HOME/nixos-configs";
|
||||
# Always preserve mode, ownership, ts with copy
|
||||
cp = "cp -rp";
|
||||
xo = "xdg-open";
|
||||
scp = "scp -p";
|
||||
smv = "rsync -av --remove-source-files";
|
||||
ffprobe = "ffprobe -hide_banner";
|
||||
ffmpeg = "ffmpeg -hide_banner";
|
||||
".." = "cd ..";
|
||||
"..." = "cd ../..";
|
||||
"...." = "cd ../../..";
|
||||
"....." = "cd ../../../..";
|
||||
};
|
||||
security.sudo.extraRules = [{
|
||||
users = [ "tvb" ];
|
||||
commands = [ { command = "/run/current-system/sw/bin/nixos-rebuild"; options = [ "NOPASSWD" ]; } ];
|
||||
}];
|
||||
}
|
||||
|
||||
(mkIf cfg.defaults.time {
|
||||
# mkDefault time zone to make it easy to configure it to non-UTC
|
||||
time.timeZone = mkDefault "UTC";
|
||||
services.ntp.enable = true;
|
||||
services.ntp.servers = [ "time.nist.gov" ];
|
||||
})
|
||||
|
||||
(mkIf cfg.defaults.i18n {
|
||||
# en_US.UTF-8
|
||||
i18n.defaultLocale = "en_US.UTF-8";
|
||||
i18n.extraLocaleSettings = {
|
||||
LC_ADDRESS = "en_US.UTF-8";
|
||||
LC_IDENTIFICATION = "en_US.UTF-8";
|
||||
LC_MEASUREMENT = "en_US.UTF-8";
|
||||
LC_MONETARY = "en_US.UTF-8";
|
||||
LC_NAME = "en_US.UTF-8";
|
||||
LC_NUMERIC = "en_US.UTF-8";
|
||||
LC_PAPER = "en_US.UTF-8";
|
||||
LC_TELEPHONE = "en_US.UTF-8";
|
||||
LC_TIME = "en_US.UTF-8";
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf cfg.defaults.programs {
|
||||
environment.systemPackages = with pkgs; [
|
||||
bat # colorized and numbered `less`
|
||||
bc # Terminal calculator
|
||||
curl # omnipotent URL tool
|
||||
duf # disk-free checker
|
||||
exiftool # media tag tool
|
||||
ffmpeg # omnipotent media tool
|
||||
file # file type inspector
|
||||
htmlq # jq for html
|
||||
jq # jq for json
|
||||
nebula # vpn
|
||||
poppler_utils # provides pdfto* utils, allows lesspipe to read pdfs
|
||||
psmisc # provides killall
|
||||
python3 # second-best language for everything
|
||||
ripgrep # fast file searcher
|
||||
rsync # incremental remote copy
|
||||
sqlite # omnipotent database
|
||||
tree # directory tree view
|
||||
unzip # .zip archive tool
|
||||
vim # terminal editor
|
||||
viu # terminal image "viewer"
|
||||
wget # web fetcher
|
||||
zip # .zip archive tool
|
||||
(writeShellScriptBin "clip" ''
|
||||
${xclip}/bin/xclip -sel c < "$1"
|
||||
'')
|
||||
];
|
||||
programs = {
|
||||
git = {
|
||||
enable = true;
|
||||
config = {
|
||||
init.defaultBranch = "master";
|
||||
merge.conflictstyle = "diff3";
|
||||
alias = {
|
||||
amend = "commit --amend";
|
||||
fixup = "commit --amend --no-edit";
|
||||
pick = "cherry-pick";
|
||||
};
|
||||
};
|
||||
};
|
||||
htop.enable = true;
|
||||
};
|
||||
# The nixpkgs default is "nano", so we go one priority higher
|
||||
environment.variables.EDITOR = mkOverride 999 "vim";
|
||||
})
|
||||
|
||||
(mkIf cfg.extraPrograms {
|
||||
environment.systemPackages = with pkgs; [
|
||||
(pkgs.writeShellScriptBin "ebook-convert" ''
|
||||
exec ${pkgs.calibre}/bin/ebook-convert "$@"
|
||||
'')
|
||||
imagemagick # image convertion cli
|
||||
puddletag # mp3 tag editor
|
||||
tesseract # OCR engine
|
||||
];
|
||||
})
|
||||
|
||||
(mkIf cfg.defaults.ssh {
|
||||
services.openssh.enable = true;
|
||||
services.openssh.settings.PrintMotd = true;
|
||||
environment.etc."motd".text = let
|
||||
ascii = import ./ascii.nix;
|
||||
in ascii.${cfg.hostName} or ascii.beatific;
|
||||
networking.firewall.allowPing = true;
|
||||
networking.firewall.allowedTCPPorts = [ 22 ];
|
||||
})
|
||||
|
||||
(mkIf cfg.defaults.nebula {
|
||||
services.nebula.networks.beatific = let
|
||||
empyreanExternalDns = "vpn.alogoulogoi.com";
|
||||
empyreanInternalIp = "10.22.20.1";
|
||||
nebulaPort = 4242;
|
||||
in {
|
||||
enable = true;
|
||||
|
||||
# The lighthouse only listens on the designated subdomain
|
||||
listen.host = if cfg.isLighthouse then empyreanExternalDns else "0.0.0.0";
|
||||
listen.port = nebulaPort;
|
||||
|
||||
# Standard certificate paths
|
||||
ca = "/etc/nebula/beatific/beatific.crt";
|
||||
cert = "/etc/nebula/beatific/${cfg.hostName}.crt";
|
||||
key = "/etc/nebula/beatific/${cfg.hostName}.key";
|
||||
|
||||
isLighthouse = cfg.isLighthouse;
|
||||
# Non-lighthouses connect to the lighthouse at empyrean
|
||||
# This should be a VPN address in the static host map
|
||||
lighthouses = mkIf (! cfg.isLighthouse) [ empyreanInternalIp ];
|
||||
|
||||
# Currently there is no VPN-level traffic filtering
|
||||
firewall.outbound = [ { port = "any"; proto = "any"; host = "any"; } ];
|
||||
firewall.inbound = [ { port = "any"; proto = "any"; host = "any"; } ];
|
||||
|
||||
# Map the lighthouse address to its public address
|
||||
staticHostMap = { ${empyreanInternalIp} = [ "${empyreanExternalDns}:${toString nebulaPort}" ]; };
|
||||
|
||||
settings = {
|
||||
# Enable UDP holepunching both ways, which allows nodes to establish more direct connections with each other
|
||||
punchy = { punch = true; response = true; };
|
||||
};
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf cfg.defaults.tvb {
|
||||
users.groups.tvb = {};
|
||||
users.users.tvb = {
|
||||
isNormalUser = true;
|
||||
group = "tvb";
|
||||
extraGroups = [ "wheel" ];
|
||||
initialPassword = "password";
|
||||
openssh.authorizedKeys.keyFiles = (import ../keys).tvb;
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf cfg.defaults.tvbSync {
|
||||
# I haven't gotten user services to work correctly yet,
|
||||
# so for now, tvb monopolizes the system syncthing instance.
|
||||
# Adding users in the future should probably involve multiple
|
||||
# system services so as not to require login to sync.
|
||||
services.syncthing = {
|
||||
enable = true;
|
||||
configDir = "/home/tvb/.config/syncthing";
|
||||
# this doesn't prevent syncthing from putting sync points in other locations, it's just a default
|
||||
# normally it would make sense to put it at ~ but see https://github.com/NixOS/nixpkgs/pull/273693
|
||||
dataDir = "/home/tvb/.config/syncthing";
|
||||
openDefaultPorts = true;
|
||||
user = "tvb";
|
||||
group = "tvb";
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf cfg.defaults.hosts {
|
||||
# Create *.home host entries for all the beatific members
|
||||
networking.hosts = {
|
||||
"10.22.20.1" = [
|
||||
"empyrean.home"
|
||||
];
|
||||
"10.22.20.2" = [
|
||||
"catacomb.home"
|
||||
"mopidy.home.ktvb.site"
|
||||
];
|
||||
"10.22.20.3" = [
|
||||
"palamas.home"
|
||||
];
|
||||
"10.22.20.4" = [
|
||||
"stagirite.home"
|
||||
];
|
||||
"10.22.20.5" = [
|
||||
"vagrant.home"
|
||||
];
|
||||
"10.22.20.6" = [
|
||||
"unfolder.home"
|
||||
];
|
||||
"10.22.20.7" = [
|
||||
"centroid.home"
|
||||
];
|
||||
"10.22.20.8" = [
|
||||
"backyard.home"
|
||||
"pool.backyard.home"
|
||||
"mirror.backyard.home"
|
||||
"jellyfin.home.ktvb.site"
|
||||
];
|
||||
"10.22.20.9" = [
|
||||
"imperium.home"
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
|
@ -1,722 +0,0 @@
|
|||
{ config, lib, options, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.syncthing;
|
||||
opt = options.services.syncthing;
|
||||
defaultUser = "syncthing";
|
||||
defaultGroup = defaultUser;
|
||||
settingsFormat = pkgs.formats.json { };
|
||||
cleanedConfig = converge (filterAttrsRecursive (_: v: v != null && v != {})) cfg.settings;
|
||||
|
||||
isUnixGui = (builtins.substring 0 1 cfg.guiAddress) == "/";
|
||||
|
||||
# Syncthing supports serving the GUI over Unix sockets. If that happens, the
|
||||
# API is served over the Unix socket as well. This function returns the correct
|
||||
# curl arguments for the address portion of the curl command for both network
|
||||
# and Unix socket addresses.
|
||||
curlAddressArgs = path: if isUnixGui
|
||||
# if cfg.guiAddress is a unix socket, tell curl explicitly about it
|
||||
# note that the dot in front of `${path}` is the hostname, which is
|
||||
# required.
|
||||
then "--unix-socket ${cfg.guiAddress} http://.${path}"
|
||||
# no adjustements are needed if cfg.guiAddress is a network address
|
||||
else "${cfg.guiAddress}${path}"
|
||||
;
|
||||
|
||||
devices = mapAttrsToList (_: device: device // {
|
||||
deviceID = device.id;
|
||||
}) cfg.settings.devices;
|
||||
|
||||
folders = mapAttrsToList (_: folder: folder //
|
||||
throwIf (folder?rescanInterval || folder?watch || folder?watchDelay) ''
|
||||
The options services.syncthing.settings.folders.<name>.{rescanInterval,watch,watchDelay}
|
||||
were removed. Please use, respectively, {rescanIntervalS,fsWatcherEnabled,fsWatcherDelayS} instead.
|
||||
'' {
|
||||
devices = map (device:
|
||||
if builtins.isString device then
|
||||
{ deviceId = cfg.settings.devices.${device}.id; }
|
||||
else
|
||||
device
|
||||
) folder.devices;
|
||||
}) (filterAttrs (_: folder:
|
||||
folder.enable
|
||||
) cfg.settings.folders);
|
||||
|
||||
jq = "${pkgs.jq}/bin/jq";
|
||||
updateConfig = pkgs.writers.writeBash "merge-syncthing-config" (''
|
||||
set -efu
|
||||
|
||||
# be careful not to leak secrets in the filesystem or in process listings
|
||||
umask 0077
|
||||
|
||||
curl() {
|
||||
# get the api key by parsing the config.xml
|
||||
while
|
||||
! ${pkgs.libxml2}/bin/xmllint \
|
||||
--xpath 'string(configuration/gui/apikey)' \
|
||||
${cfg.configDir}/config.xml \
|
||||
>"$RUNTIME_DIRECTORY/api_key"
|
||||
do sleep 1; done
|
||||
(printf "X-API-Key: "; cat "$RUNTIME_DIRECTORY/api_key") >"$RUNTIME_DIRECTORY/headers"
|
||||
${pkgs.curl}/bin/curl -sSLk -H "@$RUNTIME_DIRECTORY/headers" \
|
||||
--retry 1000 --retry-delay 1 --retry-all-errors \
|
||||
"$@"
|
||||
}
|
||||
'' +
|
||||
|
||||
/* Syncthing's rest API for the folders and devices is almost identical.
|
||||
Hence we iterate them using lib.pipe and generate shell commands for both at
|
||||
the sime time. */
|
||||
(lib.pipe {
|
||||
# The attributes below are the only ones that are different for devices /
|
||||
# folders.
|
||||
devs = {
|
||||
new_conf_IDs = map (v: v.id) devices;
|
||||
GET_IdAttrName = "deviceID";
|
||||
override = cfg.overrideDevices;
|
||||
conf = devices;
|
||||
baseAddress = curlAddressArgs "/rest/config/devices";
|
||||
};
|
||||
dirs = {
|
||||
new_conf_IDs = map (v: v.id) folders;
|
||||
GET_IdAttrName = "id";
|
||||
override = cfg.overrideFolders;
|
||||
conf = folders;
|
||||
baseAddress = curlAddressArgs "/rest/config/folders";
|
||||
};
|
||||
} [
|
||||
# Now for each of these attributes, write the curl commands that are
|
||||
# identical to both folders and devices.
|
||||
(mapAttrs (conf_type: s:
|
||||
# We iterate the `conf` list now, and run a curl -X POST command for each, that
|
||||
# should update that device/folder only.
|
||||
lib.pipe s.conf [
|
||||
# Quoting https://docs.syncthing.net/rest/config.html:
|
||||
#
|
||||
# > PUT takes an array and POST a single object. In both cases if a
|
||||
# given folder/device already exists, it’s replaced, otherwise a new
|
||||
# one is added.
|
||||
#
|
||||
# What's not documented, is that using PUT will remove objects that
|
||||
# don't exist in the array given. That's why we use here `POST`, and
|
||||
# only if s.override == true then we DELETE the relevant folders
|
||||
# afterwards.
|
||||
(map (new_cfg: ''
|
||||
curl -d ${lib.escapeShellArg (builtins.toJSON new_cfg)} -X POST ${s.baseAddress}
|
||||
''))
|
||||
(lib.concatStringsSep "\n")
|
||||
]
|
||||
/* If we need to override devices/folders, we iterate all currently configured
|
||||
IDs, via another `curl -X GET`, and we delete all IDs that are not part of
|
||||
the Nix configured list of IDs
|
||||
*/
|
||||
+ lib.optionalString s.override ''
|
||||
stale_${conf_type}_ids="$(curl -X GET ${s.baseAddress} | ${jq} \
|
||||
--argjson new_ids ${lib.escapeShellArg (builtins.toJSON s.new_conf_IDs)} \
|
||||
--raw-output \
|
||||
'[.[].${s.GET_IdAttrName}] - $new_ids | .[]'
|
||||
)"
|
||||
for id in ''${stale_${conf_type}_ids}; do
|
||||
curl -X DELETE ${s.baseAddress}/$id
|
||||
done
|
||||
''
|
||||
))
|
||||
builtins.attrValues
|
||||
(lib.concatStringsSep "\n")
|
||||
]) +
|
||||
/* Now we update the other settings defined in cleanedConfig which are not
|
||||
"folders" or "devices". */
|
||||
(lib.pipe cleanedConfig [
|
||||
builtins.attrNames
|
||||
(lib.subtractLists ["folders" "devices"])
|
||||
(map (subOption: ''
|
||||
curl -X PUT -d ${lib.escapeShellArg (builtins.toJSON cleanedConfig.${subOption})} ${curlAddressArgs "/rest/config/${subOption}"}
|
||||
''))
|
||||
(lib.concatStringsSep "\n")
|
||||
]) + ''
|
||||
# restart Syncthing if required
|
||||
if curl ${curlAddressArgs "/rest/config/restart-required"} |
|
||||
${jq} -e .requiresRestart > /dev/null; then
|
||||
curl -X POST ${curlAddressArgs "/rest/system/restart"}
|
||||
fi
|
||||
'');
|
||||
in {
|
||||
###### interface
|
||||
options = {
|
||||
services.syncthing = {
|
||||
|
||||
enable = mkEnableOption
|
||||
(lib.mdDoc "Syncthing, a self-hosted open-source alternative to Dropbox and Bittorrent Sync");
|
||||
|
||||
cert = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = mdDoc ''
|
||||
Path to the `cert.pem` file, which will be copied into Syncthing's
|
||||
[configDir](#opt-services.syncthing.configDir).
|
||||
'';
|
||||
};
|
||||
|
||||
key = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = mdDoc ''
|
||||
Path to the `key.pem` file, which will be copied into Syncthing's
|
||||
[configDir](#opt-services.syncthing.configDir).
|
||||
'';
|
||||
};
|
||||
|
||||
overrideDevices = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = mdDoc ''
|
||||
Whether to delete the devices which are not configured via the
|
||||
[devices](#opt-services.syncthing.settings.devices) option.
|
||||
If set to `false`, devices added via the web
|
||||
interface will persist and will have to be deleted manually.
|
||||
'';
|
||||
};
|
||||
|
||||
overrideFolders = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = mdDoc ''
|
||||
Whether to delete the folders which are not configured via the
|
||||
[folders](#opt-services.syncthing.settings.folders) option.
|
||||
If set to `false`, folders added via the web
|
||||
interface will persist and will have to be deleted manually.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
type = types.submodule {
|
||||
freeformType = settingsFormat.type;
|
||||
options = {
|
||||
# global options
|
||||
options = mkOption {
|
||||
default = {};
|
||||
description = mdDoc ''
|
||||
The options element contains all other global configuration options
|
||||
'';
|
||||
type = types.submodule ({ name, ... }: {
|
||||
freeformType = settingsFormat.type;
|
||||
options = {
|
||||
localAnnounceEnabled = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
Whether to send announcements to the local LAN, also use such announcements to find other devices.
|
||||
'';
|
||||
};
|
||||
|
||||
localAnnouncePort = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
The port on which to listen and send IPv4 broadcast announcements to.
|
||||
'';
|
||||
};
|
||||
|
||||
relaysEnabled = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
When true, relays will be connected to and potentially used for device to device connections.
|
||||
'';
|
||||
};
|
||||
|
||||
urAccepted = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
Whether the user has accepted to submit anonymous usage data.
|
||||
The default, 0, mean the user has not made a choice, and Syncthing will ask at some point in the future.
|
||||
"-1" means no, a number above zero means that that version of usage reporting has been accepted.
|
||||
'';
|
||||
};
|
||||
|
||||
limitBandwidthInLan = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
Whether to apply bandwidth limits to devices in the same broadcast domain as the local device.
|
||||
'';
|
||||
};
|
||||
|
||||
maxFolderConcurrency = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
This option controls how many folders may concurrently be in I/O-intensive operations such as syncing or scanning.
|
||||
The mechanism is described in detail in a [separate chapter](https://docs.syncthing.net/advanced/option-max-concurrency.html).
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
# device settings
|
||||
devices = mkOption {
|
||||
default = {};
|
||||
description = mdDoc ''
|
||||
Peers/devices which Syncthing should communicate with.
|
||||
|
||||
Note that you can still add devices manually, but those changes
|
||||
will be reverted on restart if [overrideDevices](#opt-services.syncthing.overrideDevices)
|
||||
is enabled.
|
||||
'';
|
||||
example = {
|
||||
bigbox = {
|
||||
id = "7CFNTQM-IMTJBHJ-3UWRDIU-ZGQJFR6-VCXZ3NB-XUH3KZO-N52ITXR-LAIYUAU";
|
||||
addresses = [ "tcp://192.168.0.10:51820" ];
|
||||
};
|
||||
};
|
||||
type = types.attrsOf (types.submodule ({ name, ... }: {
|
||||
freeformType = settingsFormat.type;
|
||||
options = {
|
||||
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
default = name;
|
||||
description = lib.mdDoc ''
|
||||
The name of the device.
|
||||
'';
|
||||
};
|
||||
|
||||
id = mkOption {
|
||||
type = types.str;
|
||||
description = mdDoc ''
|
||||
The device ID. See <https://docs.syncthing.net/dev/device-ids.html>.
|
||||
'';
|
||||
};
|
||||
|
||||
autoAcceptFolders = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = mdDoc ''
|
||||
Automatically create or share folders that this device advertises at the default path.
|
||||
See <https://docs.syncthing.net/users/config.html?highlight=autoaccept#config-file-format>.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
}));
|
||||
};
|
||||
|
||||
# folder settings
|
||||
folders = mkOption {
|
||||
default = {};
|
||||
description = mdDoc ''
|
||||
Folders which should be shared by Syncthing.
|
||||
|
||||
Note that you can still add folders manually, but those changes
|
||||
will be reverted on restart if [overrideFolders](#opt-services.syncthing.overrideFolders)
|
||||
is enabled.
|
||||
'';
|
||||
example = literalExpression ''
|
||||
{
|
||||
"/home/user/sync" = {
|
||||
id = "syncme";
|
||||
devices = [ "bigbox" ];
|
||||
};
|
||||
}
|
||||
'';
|
||||
type = types.attrsOf (types.submodule ({ name, ... }: {
|
||||
freeformType = settingsFormat.type;
|
||||
options = {
|
||||
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = lib.mdDoc ''
|
||||
Whether to share this folder.
|
||||
This option is useful when you want to define all folders
|
||||
in one place, but not every machine should share all folders.
|
||||
'';
|
||||
};
|
||||
|
||||
path = mkOption {
|
||||
# TODO for release 23.05: allow relative paths again and set
|
||||
# working directory to cfg.dataDir
|
||||
type = types.str // {
|
||||
check = x: types.str.check x && (substring 0 1 x == "/" || substring 0 2 x == "~/");
|
||||
description = types.str.description + " starting with / or ~/";
|
||||
};
|
||||
default = name;
|
||||
description = lib.mdDoc ''
|
||||
The path to the folder which should be shared.
|
||||
Only absolute paths (starting with `/`) and paths relative to
|
||||
the [user](#opt-services.syncthing.user)'s home directory
|
||||
(starting with `~/`) are allowed.
|
||||
'';
|
||||
};
|
||||
|
||||
id = mkOption {
|
||||
type = types.str;
|
||||
default = name;
|
||||
description = lib.mdDoc ''
|
||||
The ID of the folder. Must be the same on all devices.
|
||||
'';
|
||||
};
|
||||
|
||||
label = mkOption {
|
||||
type = types.str;
|
||||
default = name;
|
||||
description = lib.mdDoc ''
|
||||
The label of the folder.
|
||||
'';
|
||||
};
|
||||
|
||||
devices = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = mdDoc ''
|
||||
The devices this folder should be shared with. Each device must
|
||||
be defined in the [devices](#opt-services.syncthing.settings.devices) option.
|
||||
'';
|
||||
};
|
||||
|
||||
versioning = mkOption {
|
||||
default = null;
|
||||
description = mdDoc ''
|
||||
How to keep changed/deleted files with Syncthing.
|
||||
There are 4 different types of versioning with different parameters.
|
||||
See <https://docs.syncthing.net/users/versioning.html>.
|
||||
'';
|
||||
example = literalExpression ''
|
||||
[
|
||||
{
|
||||
versioning = {
|
||||
type = "simple";
|
||||
params.keep = "10";
|
||||
};
|
||||
}
|
||||
{
|
||||
versioning = {
|
||||
type = "trashcan";
|
||||
params.cleanoutDays = "1000";
|
||||
};
|
||||
}
|
||||
{
|
||||
versioning = {
|
||||
type = "staggered";
|
||||
fsPath = "/syncthing/backup";
|
||||
params = {
|
||||
cleanInterval = "3600";
|
||||
maxAge = "31536000";
|
||||
};
|
||||
};
|
||||
}
|
||||
{
|
||||
versioning = {
|
||||
type = "external";
|
||||
params.versionsPath = pkgs.writers.writeBash "backup" '''
|
||||
folderpath="$1"
|
||||
filepath="$2"
|
||||
rm -rf "$folderpath/$filepath"
|
||||
''';
|
||||
};
|
||||
}
|
||||
]
|
||||
'';
|
||||
type = with types; nullOr (submodule {
|
||||
freeformType = settingsFormat.type;
|
||||
options = {
|
||||
type = mkOption {
|
||||
type = enum [ "external" "simple" "staggered" "trashcan" ];
|
||||
description = mdDoc ''
|
||||
The type of versioning.
|
||||
See <https://docs.syncthing.net/users/versioning.html>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
copyOwnershipFromParent = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = mdDoc ''
|
||||
On Unix systems, tries to copy file/folder ownership from the parent directory (the directory it’s located in).
|
||||
Requires running Syncthing as a privileged user, or granting it additional capabilities (e.g. CAP_CHOWN on Linux).
|
||||
'';
|
||||
};
|
||||
};
|
||||
}));
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = mdDoc ''
|
||||
Extra configuration options for Syncthing.
|
||||
See <https://docs.syncthing.net/users/config.html>.
|
||||
Note that this attribute set does not exactly match the documented
|
||||
xml format. Instead, this is the format of the json rest api. There
|
||||
are slight differences. For example, this xml:
|
||||
```xml
|
||||
<options>
|
||||
<listenAddress>default</listenAddress>
|
||||
<minHomeDiskFree unit="%">1</minHomeDiskFree>
|
||||
</options>
|
||||
```
|
||||
corresponds to the json:
|
||||
```json
|
||||
{
|
||||
options: {
|
||||
listenAddresses = [
|
||||
"default"
|
||||
];
|
||||
minHomeDiskFree = {
|
||||
unit = "%";
|
||||
value = 1;
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
'';
|
||||
example = {
|
||||
options.localAnnounceEnabled = false;
|
||||
gui.theme = "black";
|
||||
};
|
||||
};
|
||||
|
||||
guiAddress = mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1:8384";
|
||||
description = lib.mdDoc ''
|
||||
The address to serve the web interface at.
|
||||
'';
|
||||
};
|
||||
|
||||
systemService = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = lib.mdDoc ''
|
||||
Whether to auto-launch Syncthing as a system service.
|
||||
'';
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = defaultUser;
|
||||
example = "yourUser";
|
||||
description = mdDoc ''
|
||||
The user to run Syncthing as.
|
||||
By default, a user named `${defaultUser}` will be created whose home
|
||||
directory is [dataDir](#opt-services.syncthing.dataDir).
|
||||
'';
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = defaultGroup;
|
||||
example = "yourGroup";
|
||||
description = mdDoc ''
|
||||
The group to run Syncthing under.
|
||||
By default, a group named `${defaultGroup}` will be created.
|
||||
'';
|
||||
};
|
||||
|
||||
all_proxy = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
example = "socks5://address.com:1234";
|
||||
description = mdDoc ''
|
||||
Overwrites the all_proxy environment variable for the Syncthing process to
|
||||
the given value. This is normally used to let Syncthing connect
|
||||
through a SOCKS5 proxy server.
|
||||
See <https://docs.syncthing.net/users/proxying.html>.
|
||||
'';
|
||||
};
|
||||
|
||||
dataDir = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/lib/syncthing";
|
||||
example = "/home/yourUser";
|
||||
description = lib.mdDoc ''
|
||||
The path where synchronised directories will exist.
|
||||
'';
|
||||
};
|
||||
|
||||
configDir = let
|
||||
cond = versionAtLeast config.system.stateVersion "19.03";
|
||||
in mkOption {
|
||||
type = types.path;
|
||||
description = lib.mdDoc ''
|
||||
The path where the settings and keys will exist.
|
||||
'';
|
||||
default = cfg.dataDir + optionalString cond "/.config/syncthing";
|
||||
defaultText = literalMD ''
|
||||
* if `stateVersion >= 19.03`:
|
||||
|
||||
config.${opt.dataDir} + "/.config/syncthing"
|
||||
* otherwise:
|
||||
|
||||
config.${opt.dataDir}
|
||||
'';
|
||||
};
|
||||
|
||||
databaseDir = mkOption {
|
||||
type = types.path;
|
||||
description = lib.mdDoc ''
|
||||
The directory containing the database and logs.
|
||||
'';
|
||||
default = cfg.configDir;
|
||||
defaultText = literalExpression "config.${opt.configDir}";
|
||||
};
|
||||
|
||||
extraFlags = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "--reset-deltas" ];
|
||||
description = lib.mdDoc ''
|
||||
Extra flags passed to the syncthing command in the service definition.
|
||||
'';
|
||||
};
|
||||
|
||||
openDefaultPorts = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = lib.mdDoc ''
|
||||
Whether to open the default ports in the firewall: TCP/UDP 22000 for transfers
|
||||
and UDP 21027 for discovery.
|
||||
|
||||
If multiple users are running Syncthing on this machine, you will need
|
||||
to manually open a set of ports for each instance and leave this disabled.
|
||||
Alternatively, if you are running only a single instance on this machine
|
||||
using the default ports, enable this.
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.syncthing;
|
||||
defaultText = literalExpression "pkgs.syncthing";
|
||||
description = lib.mdDoc ''
|
||||
The Syncthing package to use.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
imports = [
|
||||
(mkRemovedOptionModule [ "services" "syncthing" "useInotify" ] ''
|
||||
This option was removed because Syncthing now has the inotify functionality included under the name "fswatcher".
|
||||
It can be enabled on a per-folder basis through the web interface.
|
||||
'')
|
||||
(mkRenamedOptionModule [ "services" "syncthing" "extraOptions" ] [ "services" "syncthing" "settings" ])
|
||||
(mkRenamedOptionModule [ "services" "syncthing" "folders" ] [ "services" "syncthing" "settings" "folders" ])
|
||||
(mkRenamedOptionModule [ "services" "syncthing" "devices" ] [ "services" "syncthing" "settings" "devices" ])
|
||||
(mkRenamedOptionModule [ "services" "syncthing" "options" ] [ "services" "syncthing" "settings" "options" ])
|
||||
] ++ map (o:
|
||||
mkRenamedOptionModule [ "services" "syncthing" "declarative" o ] [ "services" "syncthing" o ]
|
||||
) [ "cert" "key" "devices" "folders" "overrideDevices" "overrideFolders" "extraOptions"];
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
networking.firewall = mkIf cfg.openDefaultPorts {
|
||||
allowedTCPPorts = [ 22000 ];
|
||||
allowedUDPPorts = [ 21027 22000 ];
|
||||
};
|
||||
|
||||
systemd.packages = [ pkgs.syncthing ];
|
||||
|
||||
users.users = mkIf (cfg.systemService && cfg.user == defaultUser) {
|
||||
${defaultUser} =
|
||||
{ group = cfg.group;
|
||||
home = cfg.dataDir;
|
||||
createHome = true;
|
||||
uid = config.ids.uids.syncthing;
|
||||
description = "Syncthing daemon user";
|
||||
};
|
||||
};
|
||||
|
||||
users.groups = mkIf (cfg.systemService && cfg.group == defaultGroup) {
|
||||
${defaultGroup}.gid =
|
||||
config.ids.gids.syncthing;
|
||||
};
|
||||
|
||||
systemd.services = {
|
||||
# upstream reference:
|
||||
# https://github.com/syncthing/syncthing/blob/main/etc/linux-systemd/system/syncthing%40.service
|
||||
syncthing = mkIf cfg.systemService {
|
||||
description = "Syncthing service";
|
||||
after = [ "network.target" ];
|
||||
environment = {
|
||||
STNORESTART = "yes";
|
||||
STNOUPGRADE = "yes";
|
||||
inherit (cfg) all_proxy;
|
||||
} // config.networking.proxy.envVars;
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Restart = "on-failure";
|
||||
SuccessExitStatus = "3 4";
|
||||
RestartForceExitStatus="3 4";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
ExecStartPre = mkIf (cfg.cert != null || cfg.key != null)
|
||||
"+${pkgs.writers.writeBash "syncthing-copy-keys" ''
|
||||
install -dm700 -o ${cfg.user} -g ${cfg.group} ${cfg.configDir}
|
||||
${optionalString (cfg.cert != null) ''
|
||||
install -Dm400 -o ${cfg.user} -g ${cfg.group} ${toString cfg.cert} ${cfg.configDir}/cert.pem
|
||||
''}
|
||||
${optionalString (cfg.key != null) ''
|
||||
install -Dm400 -o ${cfg.user} -g ${cfg.group} ${toString cfg.key} ${cfg.configDir}/key.pem
|
||||
''}
|
||||
''}"
|
||||
;
|
||||
ExecStart = ''
|
||||
${cfg.package}/bin/syncthing \
|
||||
-no-browser \
|
||||
-gui-address=${if isUnixGui then "unix://" else ""}${cfg.guiAddress} \
|
||||
-config=${cfg.configDir} \
|
||||
-data=${cfg.databaseDir} \
|
||||
${escapeShellArgs cfg.extraFlags}
|
||||
'';
|
||||
MemoryDenyWriteExecute = true;
|
||||
NoNewPrivileges = true;
|
||||
PrivateDevices = true;
|
||||
PrivateMounts = true;
|
||||
PrivateTmp = true;
|
||||
PrivateUsers = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
CapabilityBoundingSet = [
|
||||
"~CAP_SYS_PTRACE" "~CAP_SYS_ADMIN"
|
||||
"~CAP_SETGID" "~CAP_SETUID" "~CAP_SETPCAP"
|
||||
"~CAP_SYS_TIME" "~CAP_KILL"
|
||||
];
|
||||
};
|
||||
};
|
||||
syncthing-init = mkIf (cleanedConfig != {}) {
|
||||
description = "Syncthing configuration updater";
|
||||
requisite = [ "syncthing.service" ];
|
||||
after = [ "syncthing.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
User = cfg.user;
|
||||
RemainAfterExit = true;
|
||||
RuntimeDirectory = "syncthing-init";
|
||||
Type = "oneshot";
|
||||
ExecStart = updateConfig;
|
||||
};
|
||||
};
|
||||
|
||||
syncthing-resume = {
|
||||
wantedBy = [ "suspend.target" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
# Flake inputs
|
||||
{ inputs, ... }:
|
||||
# Module inputs
|
||||
{ ... }:
|
||||
{
|
||||
environment.systemPackages = [ inputs.nixpkgs-2405.legacyPackages."i686-linux".gperftools ];
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
# Flake inputs
|
||||
{ inputs, ... }:
|
||||
# Module inputs
|
||||
{ ... }:
|
||||
let
|
||||
pkgs = import inputs.nixpkgs-unstable { system = "x86_64-linux"; config.allowUnfree = true; };
|
||||
in {
|
||||
virtualisation.docker.enable = true;
|
||||
environment.systemPackages = [
|
||||
pkgs.distrobox
|
||||
pkgs.vscode
|
||||
pkgs.icu
|
||||
];
|
||||
}
|
Loading…
Reference in New Issue