Compare commits
1 Commits
wip/feeds3
...
wip-kaitek
Author | SHA1 | Date | |
---|---|---|---|
5152159691 |
47
.sops.yaml
47
.sops.yaml
@@ -1,47 +0,0 @@
|
|||||||
keys:
|
|
||||||
- &user_desko_colin age1tnl4jfgacwkargzeqnhzernw29xx8mkv73xh6ufdyde6q7859slsnzf24x
|
|
||||||
- &user_lappy_colin age1j2pqnl8j0krdzk6npe93s4nnqrzwx978qrc0u570gzlamqpnje9sc8le2g
|
|
||||||
- &user_servo_colin age1z8fauff34cdecr6sjkre260luzxcca05kpcwvhx988d306tpcejsp63znu
|
|
||||||
- &user_moby_colin age1zsrsvd7j6l62fjxpfd2qnhqlk8wk4p8r0dtxpe4sdgnh2474095qdu7xj9
|
|
||||||
- &host_desko age1vnw7lnfpdpjn62l3u5nyv5xt2c965k96p98kc43mcnyzpetrts9q54mc9v
|
|
||||||
- &host_lappy age1w7mectcjku6x3sd8plm8wkn2qfrhv9n6zhzlf329e2r2uycgke8qkf9dyn
|
|
||||||
- &host_servo age1tzlyex2z6t88tg9h82943e39shxhmqeyr7ywhlwpdjmyqsndv3qq27x0rf
|
|
||||||
- &host_moby age18vq5ktwgeaysucvw9t67drqmg5zd5c5k3le34yqxckkfj7wqdqgsd4ejmt
|
|
||||||
creation_rules:
|
|
||||||
- path_regex: secrets/universal*
|
|
||||||
key_groups:
|
|
||||||
- age:
|
|
||||||
- *user_desko_colin
|
|
||||||
- *user_lappy_colin
|
|
||||||
- *user_servo_colin
|
|
||||||
- *user_moby_colin
|
|
||||||
- *host_desko
|
|
||||||
- *host_lappy
|
|
||||||
- *host_servo
|
|
||||||
- *host_moby
|
|
||||||
- path_regex: secrets/servo*
|
|
||||||
key_groups:
|
|
||||||
- age:
|
|
||||||
- *user_desko_colin
|
|
||||||
- *user_lappy_colin
|
|
||||||
- *user_servo_colin
|
|
||||||
- *host_servo
|
|
||||||
- path_regex: secrets/desko.yaml$
|
|
||||||
key_groups:
|
|
||||||
- age:
|
|
||||||
- *user_desko_colin
|
|
||||||
- *user_lappy_colin
|
|
||||||
- *host_desko
|
|
||||||
- path_regex: secrets/lappy.yaml$
|
|
||||||
key_groups:
|
|
||||||
- age:
|
|
||||||
- *user_lappy_colin
|
|
||||||
- *user_desko_colin
|
|
||||||
- *host_lappy
|
|
||||||
- path_regex: secrets/moby.yaml$
|
|
||||||
key_groups:
|
|
||||||
- age:
|
|
||||||
- *user_desko_colin
|
|
||||||
- *user_lappy_colin
|
|
||||||
- *user_moby_colin
|
|
||||||
- *host_moby
|
|
21
TODO.md
Normal file
21
TODO.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# features/tweaks
|
||||||
|
- enable sshfs (deskto/lappy)
|
||||||
|
- set firefox default search engine
|
||||||
|
- iron out video drivers
|
||||||
|
|
||||||
|
# cleanup
|
||||||
|
- remove helpers from outputs section (use `let .. in`)
|
||||||
|
|
||||||
|
|
||||||
|
# speed up cross compiling
|
||||||
|
https://nixos.wiki/wiki/Cross_Compiling
|
||||||
|
https://nixos.wiki/wiki/NixOS_on_ARM
|
||||||
|
overlays = [{ ... }: {
|
||||||
|
nixpkgs.crossSystem.system = "aarch64-linux";
|
||||||
|
}];
|
||||||
|
|
||||||
|
# better secrets management? read:
|
||||||
|
- decrypted at activation time: https://github.com/Mic92/sops-nix
|
||||||
|
less promising:
|
||||||
|
- https://christine.website/blog/nixos-encrypted-secrets-2021-01-20
|
||||||
|
- git-crypt (https://github.com/bobbbay/dotfiles.git)
|
25
configuration.nix
Normal file
25
configuration.nix
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Edit this configuration file to define what should be installed on
|
||||||
|
# your system. Help is available in the configuration.nix(5) man page
|
||||||
|
# and in the NixOS manual (accessible by running ‘nixos-help’).
|
||||||
|
|
||||||
|
# USEFUL COMMANDS:
|
||||||
|
# nix show-config
|
||||||
|
# nix eval --raw <expr> => print an expression. e.g. nixpkgs.raspberrypifw prints store path to the package
|
||||||
|
# nix-option ## query options -- including their SET VALUE; similar to search: https://search.nixos.org/options
|
||||||
|
# nixos-rebuild switch --upgrade ## pull changes from the nixos channel (e.g. security updates) and rebuild
|
||||||
|
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
# enable flake support.
|
||||||
|
# the real config root lives in flake.nix
|
||||||
|
nix = {
|
||||||
|
#package = pkgs.nixFlakes;
|
||||||
|
package = pkgs.nixUnstable;
|
||||||
|
extraOptions = ''
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
131
flake.lock
generated
131
flake.lock
generated
@@ -1,20 +1,5 @@
|
|||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"flake-utils": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1659877975,
|
|
||||||
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"home-manager": {
|
"home-manager": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -22,11 +7,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1667907331,
|
"lastModified": 1654113405,
|
||||||
"narHash": "sha256-bHkAwkYlBjkupPUFcQjimNS8gxWSWjOTevEuwdnp5m0=",
|
"narHash": "sha256-VpK+0QaWG2JRgB00lw77N9TjkE3ec0iMYIX1TzGpxa4=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "6639e3a837fc5deb6f99554072789724997bc8e5",
|
"rev": "ac2287df5a2d6f0a44bbcbd11701dbbf6ec43675",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -39,11 +24,11 @@
|
|||||||
"mobile-nixos": {
|
"mobile-nixos": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1670131242,
|
"lastModified": 1654281294,
|
||||||
"narHash": "sha256-T/o1/3gffr010fsqgNshs1NJJjsnUYvQnUZgm6hilsY=",
|
"narHash": "sha256-hT2/u0jUOD4TFU6YyYt+5Gt+hjIeerLTyZG7ru79aDU=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "mobile-nixos",
|
"repo": "mobile-nixos",
|
||||||
"rev": "5ee45cc1f8e43f4af14ee17ccef9156b0db8cd77",
|
"rev": "d798b0b34240b18a08c22f5c0ee1f59a3ce43c01",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -53,119 +38,41 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs-unpatched"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1,
|
"lastModified": 1654275867,
|
||||||
"narHash": "sha256-RM4ZprjMlUTMD0huOPQceF0ujXG2xk7LE1fGXfcg71g=",
|
"narHash": "sha256-pt14ZE4jVPGvfB2NynGsl34pgXfOqum5YJNpDK4+b9E=",
|
||||||
"path": "nixpatches",
|
|
||||||
"type": "path"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"path": "nixpatches",
|
|
||||||
"type": "path"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs-stable": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1673527292,
|
|
||||||
"narHash": "sha256-903EpRSDCfUvic7Hsiqwy+h7zlMTLAUbCXkEGGriCfM=",
|
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "6a3f9996408c970b99b8b992b11bb249d1455b62",
|
"rev": "7a20c208aacf4964c19186dcad51f89165dc7ed0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"id": "nixpkgs",
|
"id": "nixpkgs",
|
||||||
"ref": "nixos-22.11",
|
"ref": "nixos-22.05",
|
||||||
"type": "indirect"
|
"type": "indirect"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs-stable_2": {
|
"nurpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1673100377,
|
"lastModified": 1654367137,
|
||||||
"narHash": "sha256-mT76pTd0YFxT6CwtPhDgHJhuIgLY+ZLSMiQpBufwMG4=",
|
"narHash": "sha256-xufB/+qvk/7rh7qrwZbzru1kTu8nsmNWBNQkYbdS84Q=",
|
||||||
"owner": "NixOS",
|
"owner": "nix-community",
|
||||||
"repo": "nixpkgs",
|
"repo": "NUR",
|
||||||
"rev": "9f11a2df77cb945c115ae2a65f53f38121597d73",
|
"rev": "86ff2d098bce1d623232f4886027a1d61317b195",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "nix-community",
|
||||||
"ref": "release-22.11",
|
"repo": "NUR",
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs-unpatched": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1673450908,
|
|
||||||
"narHash": "sha256-b8em+kwrNtnB7gR8SyVf6WuTyQ+6tHS6dzt9D9wgKF0=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "6c8644fc37b6e141cbfa6c7dc8d98846c4ff0c2e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"id": "nixpkgs",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"type": "indirect"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
"mobile-nixos": "mobile-nixos",
|
"mobile-nixos": "mobile-nixos",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"nixpkgs-stable": "nixpkgs-stable",
|
"nurpkgs": "nurpkgs"
|
||||||
"nixpkgs-unpatched": "nixpkgs-unpatched",
|
|
||||||
"sops-nix": "sops-nix",
|
|
||||||
"uninsane-dot-org": "uninsane-dot-org"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"sops-nix": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"nixpkgs-stable": "nixpkgs-stable_2"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1673481602,
|
|
||||||
"narHash": "sha256-P80X38fOM2MtoYdgkyuksGOQPDhIhNJW2W2jMeMIZzE=",
|
|
||||||
"owner": "Mic92",
|
|
||||||
"repo": "sops-nix",
|
|
||||||
"rev": "32187b33ac6ec9b628dcd08dd941a715e6241dda",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "Mic92",
|
|
||||||
"repo": "sops-nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"uninsane-dot-org": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils",
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1666870107,
|
|
||||||
"narHash": "sha256-b9eXZxSwhzdJI5uQgfrMhu4SY2POrPkinUg7F5gQVYo=",
|
|
||||||
"ref": "refs/heads/master",
|
|
||||||
"rev": "80c6ec95bd430e29d231cf745f19279bb76fb382",
|
|
||||||
"revCount": 164,
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://git.uninsane.org/colin/uninsane"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://git.uninsane.org/colin/uninsane"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
234
flake.nix
234
flake.nix
@@ -1,15 +1,11 @@
|
|||||||
# docs:
|
# docs:
|
||||||
# - <https://nixos.wiki/wiki/Flakes>
|
# https://nixos.wiki/wiki/Flakes
|
||||||
# - <https://serokell.io/blog/practical-nix-flakes>
|
# https://serokell.io/blog/practical-nix-flakes
|
||||||
|
|
||||||
{
|
{
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs-stable.url = "nixpkgs/nixos-22.11";
|
nixpkgs.url = "nixpkgs/nixos-22.05";
|
||||||
nixpkgs-unpatched.url = "nixpkgs/nixos-unstable";
|
# pkgs-telegram.url = "nixpkgs/33775ec9a2173a08e46edf9f46c9febadbf743e8";# 2022/04/18; telegram 3.7.3. fails: nix log /nix/store/y5kv47hnv55qknb6cnmpcyraicay79fx-telegram-desktop-3.7.3.drv: g++: fatal error: cannot execute '/nix/store/njk5sbd21305bhr7gwibxbbvgbx5lxvn-gcc-9.3.0/libexec/gcc/aarch64-unknown-linux-gnu/9.3.0/cc1plus': execv: No such file or directory
|
||||||
nixpkgs = {
|
|
||||||
url = "path:nixpatches";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs-unpatched";
|
|
||||||
};
|
|
||||||
mobile-nixos = {
|
mobile-nixos = {
|
||||||
url = "github:nixos/mobile-nixos";
|
url = "github:nixos/mobile-nixos";
|
||||||
flake = false;
|
flake = false;
|
||||||
@@ -18,149 +14,103 @@
|
|||||||
url = "github:nix-community/home-manager/release-22.05";
|
url = "github:nix-community/home-manager/release-22.05";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
sops-nix = {
|
nurpkgs.url = "github:nix-community/NUR";
|
||||||
url = "github:Mic92/sops-nix";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
};
|
|
||||||
uninsane-dot-org = {
|
|
||||||
url = "git+https://git.uninsane.org/colin/uninsane";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = {
|
outputs = { self, nixpkgs, mobile-nixos, home-manager, nurpkgs }: {
|
||||||
self,
|
machines.uninsane = self.decl-bootable-machine { name = "uninsane"; system = "aarch64-linux"; };
|
||||||
nixpkgs,
|
machines.desko = self.decl-bootable-machine { name = "desko"; system = "x86_64-linux"; };
|
||||||
nixpkgs-stable,
|
machines.lappy = self.decl-bootable-machine { name = "lappy"; system = "x86_64-linux"; };
|
||||||
nixpkgs-unpatched,
|
|
||||||
mobile-nixos,
|
|
||||||
home-manager,
|
|
||||||
sops-nix,
|
|
||||||
uninsane-dot-org
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
nixpkgsCompiledBy = local: nixpkgs.legacyPackages."${local}";
|
|
||||||
|
|
||||||
evalHost = { name, local, target }:
|
machines.moby =
|
||||||
let
|
let machine = self.decl-machine {
|
||||||
# XXX: we'd prefer to use `nixosSystem = (nixpkgsCompiledBy local).nixos`
|
name = "moby";
|
||||||
# but it doesn't propagate config to the underlying pkgs, meaning it doesn't let you use
|
system = "aarch64-linux";
|
||||||
# non-free packages even after setting nixpkgs.allowUnfree.
|
extraModules = [
|
||||||
nixosSystem = import ((nixpkgsCompiledBy local).path + "/nixos/lib/eval-config.nix");
|
(import "${mobile-nixos}/lib/configuration.nix" {
|
||||||
in
|
device = "pine64-pinephone";
|
||||||
(nixosSystem {
|
})
|
||||||
# we use pkgs built for and *by* the target, i.e. emulation, by default.
|
];
|
||||||
# cross compilation only happens on explicit access to `pkgs.cross`
|
};
|
||||||
system = target;
|
in {
|
||||||
modules = [
|
nixosConfiguration = machine;
|
||||||
(import ./hosts/instantiate.nix { localSystem = local; hostName = name; })
|
img = machine.config.mobile.outputs.u-boot.disk-image;
|
||||||
self.nixosModules.default
|
|
||||||
self.nixosModules.passthru
|
|
||||||
{
|
|
||||||
nixpkgs.overlays = [
|
|
||||||
self.overlays.default
|
|
||||||
self.overlays.passthru
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
});
|
|
||||||
in {
|
|
||||||
nixosConfigurations = {
|
|
||||||
servo = evalHost { name = "servo"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
|
||||||
desko = evalHost { name = "desko"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
|
||||||
lappy = evalHost { name = "lappy"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
|
||||||
moby = evalHost { name = "moby"; local = "aarch64-linux"; target = "aarch64-linux"; };
|
|
||||||
# special cross-compiled variant, to speed up deploys from an x86 box to the arm target
|
|
||||||
# note that these *do* produce different store paths, because the closure for the tools used to cross compile
|
|
||||||
# v.s. emulate differ.
|
|
||||||
# so deploying foo-cross and then foo incurs some rebuilding.
|
|
||||||
moby-cross = evalHost { name = "moby"; local = "x86_64-linux"; target = "aarch64-linux"; };
|
|
||||||
rescue = evalHost { name = "rescue"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# unofficial output
|
nixosConfigurations = builtins.mapAttrs (name: value: value.nixosConfiguration) self.machines;
|
||||||
# this produces a EFI-bootable .img file (GPT with a /boot partition and a system (/ or /nix) partition).
|
imgs = builtins.mapAttrs (name: value: value.img) self.machines;
|
||||||
# after building this:
|
|
||||||
# - flash it to a bootable medium (SD card, flash drive, HDD)
|
|
||||||
# - resize the root partition (use cfdisk)
|
|
||||||
# - mount the part
|
|
||||||
# - chown root:nixbld <part>/nix/store
|
|
||||||
# - chown root:root -R <part>/nix/store/*
|
|
||||||
# - chown root:root -R <part>/persist # if using impermanence
|
|
||||||
# - populate any important things (persist/, home/colin/.ssh, etc)
|
|
||||||
# - boot
|
|
||||||
# - if fs wasn't resized automatically, then `sudo btrfs filesystem resize max /`
|
|
||||||
# - checkout this flake into /etc/nixos AND UPDATE THE FS UUIDS.
|
|
||||||
# - `nixos-rebuild --flake './#<host>' switch`
|
|
||||||
imgs = builtins.mapAttrs (_: host-dfn: host-dfn.config.system.build.img) self.nixosConfigurations;
|
|
||||||
|
|
||||||
overlays = rec {
|
decl-machine = { name, system, extraModules ? [], basePkgs ? nixpkgs }: let
|
||||||
default = pkgs;
|
patchedPkgs = basePkgs.legacyPackages.${system}.applyPatches {
|
||||||
pkgs = import ./pkgs/overlay.nix;
|
name = "nixpkgs-patched-uninsane";
|
||||||
passthru =
|
src = basePkgs;
|
||||||
let
|
patches = [
|
||||||
stable = next: prev: {
|
# for mobile: allow phoc to scale to non-integer values
|
||||||
stable = nixpkgs-stable.legacyPackages."${prev.stdenv.hostPlatform}";
|
./nixpatches/01-phosh-float-scale.patch
|
||||||
};
|
# for raspberry pi: allow building u-boot for rpi 4{,00}
|
||||||
mobile = (import "${mobile-nixos}/overlay/overlay.nix");
|
./nixpatches/02-rpi4-uboot.patch
|
||||||
uninsane = uninsane-dot-org.overlay;
|
./nixpatches/03-whalebird-4.6.0.patch
|
||||||
in
|
./nixpatches/04-dart-2.7.0.patch
|
||||||
next: prev:
|
];
|
||||||
(stable next prev) // (mobile next prev) // (uninsane next prev);
|
|
||||||
};
|
};
|
||||||
|
nixosSystem = import (patchedPkgs + "/nixos/lib/eval-config.nix");
|
||||||
|
in (nixosSystem {
|
||||||
|
inherit system;
|
||||||
|
specialArgs = { inherit home-manager; inherit nurpkgs; secrets = import ./secrets/default.nix; };
|
||||||
|
modules = [
|
||||||
|
./configuration.nix
|
||||||
|
./machines/${name}
|
||||||
|
(import ./helpers/set-hostname.nix name)
|
||||||
|
(self.overlaysModule system)
|
||||||
|
] ++ extraModules;
|
||||||
|
});
|
||||||
|
|
||||||
nixosModules = rec {
|
# this produces a EFI-bootable .img file (GPT with / and /boot).
|
||||||
default = sane;
|
# after building this, steps are:
|
||||||
sane = import ./modules;
|
# run `btrfs-convert --uuid copy <device>`
|
||||||
passthru = { ... }: {
|
# boot, checkout this flake into /etc/nixos AND UPDATE THE UUIDS IT REFERENCES.
|
||||||
imports = [
|
# then `nixos-rebuild ...`
|
||||||
home-manager.nixosModule
|
decl-img = { name, system, extraModules ? [] }: (
|
||||||
sops-nix.nixosModules.sops
|
(self.decl-machine { inherit name; inherit system; extraModules = extraModules ++ [./image.nix]; })
|
||||||
];
|
.config.system.build.raw
|
||||||
};
|
);
|
||||||
};
|
|
||||||
|
|
||||||
# this includes both our native packages and all the nixpkgs packages.
|
decl-bootable-machine = { name, system }: {
|
||||||
legacyPackages =
|
nixosConfiguration = self.decl-machine { inherit name; inherit system; };
|
||||||
let
|
img = self.decl-img { inherit name; inherit system; };
|
||||||
allPkgsFor = sys: (nixpkgsCompiledBy sys).appendOverlays [
|
|
||||||
self.overlays.passthru self.overlays.pkgs
|
|
||||||
];
|
|
||||||
in {
|
|
||||||
x86_64-linux = allPkgsFor "x86_64-linux";
|
|
||||||
aarch64-linux = allPkgsFor "aarch64-linux";
|
|
||||||
};
|
|
||||||
|
|
||||||
# extract only our own packages from the full set
|
|
||||||
packages = builtins.mapAttrs
|
|
||||||
(_: full: full.sane // { inherit (full) sane uninsane-dot-org; })
|
|
||||||
self.legacyPackages;
|
|
||||||
|
|
||||||
apps."x86_64-linux" =
|
|
||||||
let
|
|
||||||
pkgs = self.legacyPackages."x86_64-linux";
|
|
||||||
in {
|
|
||||||
update-feeds = {
|
|
||||||
type = "app";
|
|
||||||
program = "${pkgs.feeds.passthru.updateScript}";
|
|
||||||
};
|
|
||||||
|
|
||||||
init-feed = {
|
|
||||||
type = "app";
|
|
||||||
program = "${pkgs.feeds.passthru.initFeedScript}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
templates = {
|
|
||||||
python-data = {
|
|
||||||
# initialize with:
|
|
||||||
# - `nix flake init -t '/home/colin/dev/nixos/#python-data'`
|
|
||||||
# then enter with:
|
|
||||||
# - `nix develop`
|
|
||||||
path = ./templates/python-data;
|
|
||||||
description = "python environment for data processing";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
overlaysModule = system: { config, pkgs, ...}: {
|
||||||
|
nixpkgs.config.allowUnfree = true;
|
||||||
|
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
#mobile-nixos.overlay
|
||||||
|
nurpkgs.overlay
|
||||||
|
(next: prev: {
|
||||||
|
#### customized packages
|
||||||
|
# nixos-unstable pleroma is too far out-of-date for our db
|
||||||
|
pleroma = prev.callPackage ./pkgs/pleroma { };
|
||||||
|
# jackett doesn't allow customization of the bind address: this will probably always be here.
|
||||||
|
jackett = next.callPackage ./pkgs/jackett { pkgs = prev; };
|
||||||
|
# fix abrupt HDD poweroffs as during reboot. patching systemd requires rebuilding nearly every package.
|
||||||
|
# systemd = import ./pkgs/systemd { pkgs = prev; };
|
||||||
|
|
||||||
|
# patch rpi uboot with something that fixes USB HDD boot
|
||||||
|
ubootRaspberryPi4_64bit = next.callPackage ./pkgs/ubootRaspberryPi4_64bit { pkgs = prev; };
|
||||||
|
|
||||||
|
#### TEMPORARY NIXOS-UNSTABLE PACKAGES
|
||||||
|
|
||||||
|
# stable telegram doesn't build, so explicitly use the stable one.
|
||||||
|
# TODO: apply this specifically to the moby build?
|
||||||
|
# tdesktop = pkgs-telegram.legacyPackages.${system}.tdesktop;
|
||||||
|
tdesktop = nixpkgs.legacyPackages.${system}.tdesktop;
|
||||||
|
|
||||||
|
#### TEMPORARY: PACKAGES WAITING TO BE UPSTREAMED
|
||||||
|
whalebird = prev.callPackage ./pkgs/whalebird { };
|
||||||
|
kaiteki = prev.callPackage ./pkgs/kaiteki { };
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
helpers/gui/gnome.nix
Normal file
13
helpers/gui/gnome.nix
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# start gnome/gdm on boot
|
||||||
|
services.xserver.enable = true;
|
||||||
|
services.xserver.desktopManager.gnome.enable = true;
|
||||||
|
services.xserver.displayManager.gdm.enable = true;
|
||||||
|
|
||||||
|
# gnome does networking stuff with networkmanager
|
||||||
|
networking.useDHCP = false;
|
||||||
|
networking.networkmanager.enable = true;
|
||||||
|
networking.wireless.enable = lib.mkForce false;
|
||||||
|
}
|
16
helpers/gui/i3.nix
Normal file
16
helpers/gui/i3.nix
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
environment.pathsToLink = [ "/libexec" ]; # patch for i3blocks to work
|
||||||
|
services.xserver.enable = true;
|
||||||
|
services.xserver.displayManager.defaultSession = "none+i3";
|
||||||
|
services.xserver.windowManager.i3 = {
|
||||||
|
enable = true;
|
||||||
|
extraPackages = with pkgs; [
|
||||||
|
dmenu
|
||||||
|
i3status
|
||||||
|
i3lock
|
||||||
|
i3blocks
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
21
helpers/gui/phosh.nix
Normal file
21
helpers/gui/phosh.nix
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
# docs: https://github.com/NixOS/nixpkgs/blob/nixos-22.05/nixos/modules/services/x11/desktop-managers/phosh.nix
|
||||||
|
services.xserver.desktopManager.phosh = {
|
||||||
|
enable = true;
|
||||||
|
user = "colin";
|
||||||
|
group = "users";
|
||||||
|
phocConfig = {
|
||||||
|
xwayland = "true";
|
||||||
|
# find default outputs by catting /etc/phosh/phoc.ini
|
||||||
|
outputs.DSI-1 = {
|
||||||
|
scale = 1.5;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.variables = {
|
||||||
|
# Qt apps won't always start unless this env var is set
|
||||||
|
QT_QPA_PLATFORM = "wayland";
|
||||||
|
};
|
||||||
|
}
|
14
helpers/gui/plasma-mobile.nix
Normal file
14
helpers/gui/plasma-mobile.nix
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# start plasma-mobile on boot
|
||||||
|
services.xserver.enable = true;
|
||||||
|
services.xserver.desktopManager.plasma5.mobile.enable = true;
|
||||||
|
services.xserver.desktopManager.plasma5.mobile.installRecommendedSoftware = false; # not all plasma5-mobile packages build for aarch64
|
||||||
|
services.xserver.displayManager.sddm.enable = true;
|
||||||
|
|
||||||
|
# Plasma does networking stuff with networkmanager, but nix configures the defaults itself
|
||||||
|
# networking.useDHCP = false;
|
||||||
|
# networking.networkmanager.enable = true;
|
||||||
|
# networking.wireless.enable = lib.mkForce false;
|
||||||
|
}
|
31
helpers/gui/sway.nix
Normal file
31
helpers/gui/sway.nix
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
# docs: https://nixos.wiki/wiki/Sway
|
||||||
|
{
|
||||||
|
programs.sway = {
|
||||||
|
# we configure sway with home-manager, but this enable gets us e.g. opengl and fonts
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# TODO: should be able to use SDDM to get interactive login
|
||||||
|
services.greetd = {
|
||||||
|
enable = true;
|
||||||
|
settings = rec {
|
||||||
|
initial_session = {
|
||||||
|
command = "${pkgs.sway}/bin/sway";
|
||||||
|
user = "colin";
|
||||||
|
};
|
||||||
|
default_session = initial_session;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# unlike other DEs, sway configures no audio stack
|
||||||
|
# administer with pw-cli, pw-mon, pw-top commands
|
||||||
|
services.pipewire = {
|
||||||
|
enable = true;
|
||||||
|
alsa.enable = true;
|
||||||
|
alsa.support32Bit = true; # ??
|
||||||
|
pulse.enable = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
65
helpers/hardware-x86_64.nix
Normal file
65
helpers/hardware-x86_64.nix
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
boot.initrd.availableKernelModules = [
|
||||||
|
"xhci_pci" "ahci" "sd_mod" "sdhci_pci" # nixos-generate-config defaults
|
||||||
|
"usb_storage" # rpi needed this to boot from usb storage, i think.
|
||||||
|
# "usbhid" "hid-generic" # hopefully these will fix USB HID auto-sleep ?
|
||||||
|
];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.initrd.supportedFilesystems = [ "ext4" "btrfs" "ext2" "ext3" "vfat" ];
|
||||||
|
# find more of these with sensors-detect
|
||||||
|
boot.kernelModules = [
|
||||||
|
"coretemp"
|
||||||
|
"kvm-intel"
|
||||||
|
"kvm-amd" # desktop
|
||||||
|
"amdgpu" # desktop
|
||||||
|
];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
boot.kernelParams = [ "boot.shell_on_fail" ];
|
||||||
|
boot.consoleLogLevel = 7;
|
||||||
|
|
||||||
|
# Use the systemd-boot EFI boot loader.
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
boot.loader.systemd-boot.configurationLimit = 40; # keep this many generations
|
||||||
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
|
||||||
|
# enable cross compilation
|
||||||
|
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
|
||||||
|
# nixpkgs.crossSystem.system = "aarch64-linux";
|
||||||
|
|
||||||
|
powerManagement.cpuFreqGovernor = "powersave";
|
||||||
|
hardware.enableRedistributableFirmware = true;
|
||||||
|
hardware.cpu.amd.updateMicrocode = true; # desktop
|
||||||
|
hardware.cpu.intel.updateMicrocode = true; # laptop
|
||||||
|
services.fwupd.enable = true;
|
||||||
|
# powertop will default to putting USB devices -- including HID -- to sleep after TWO SECONDS
|
||||||
|
powerManagement.powertop.enable = false;
|
||||||
|
|
||||||
|
hardware.opengl.extraPackages = [
|
||||||
|
# laptop
|
||||||
|
pkgs.intel-compute-runtime
|
||||||
|
pkgs.intel-media-driver # new
|
||||||
|
pkgs.libvdpau-va-gl # new
|
||||||
|
pkgs.vaapiIntel
|
||||||
|
# desktop
|
||||||
|
pkgs.rocm-opencl-icd
|
||||||
|
pkgs.rocm-opencl-runtime
|
||||||
|
];
|
||||||
|
hardware.opengl.driSupport = true;
|
||||||
|
# For 32 bit applications
|
||||||
|
hardware.opengl.driSupport32Bit = true;
|
||||||
|
|
||||||
|
# TODO colin: does this *do* anything?
|
||||||
|
swapDevices = [ ];
|
||||||
|
|
||||||
|
# services.snapper.configs = {
|
||||||
|
# root = {
|
||||||
|
# subvolume = "/";
|
||||||
|
# extraConfig = {
|
||||||
|
# ALLOW_USERS = "colin";
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# services.snapper.snapshotInterval = "daily";
|
||||||
|
}
|
532
helpers/home-manager-gen-colin.nix
Normal file
532
helpers/home-manager-gen-colin.nix
Normal file
@@ -0,0 +1,532 @@
|
|||||||
|
# docs:
|
||||||
|
# https://rycee.gitlab.io/home-manager/
|
||||||
|
# https://rycee.gitlab.io/home-manager/options.html
|
||||||
|
# man home-configuration.nix
|
||||||
|
#
|
||||||
|
|
||||||
|
# system is e.g. x86_64-linux
|
||||||
|
# gui is "gnome", or null
|
||||||
|
{ lib, pkgs, system, gui, extraPackages ? [] }: {
|
||||||
|
home.stateVersion = "21.11";
|
||||||
|
home.username = "colin";
|
||||||
|
home.homeDirectory = "/home/colin";
|
||||||
|
programs.home-manager.enable = true; # this lets home-manager manage dot-files in user dirs, i think
|
||||||
|
|
||||||
|
# XDG defines things like ~/Desktop, ~/Downloads, etc.
|
||||||
|
# these clutter the home, so i mostly don't use them.
|
||||||
|
xdg.userDirs = {
|
||||||
|
enable = true;
|
||||||
|
createDirectories = false; # on headless systems, most xdg dirs are noise
|
||||||
|
desktop = "$HOME/.xdg/Desktop";
|
||||||
|
documents = "$HOME/src";
|
||||||
|
download = "$HOME/tmp";
|
||||||
|
music = "$HOME/Music";
|
||||||
|
pictures = "$HOME/Pictures";
|
||||||
|
publicShare = "$HOME/.xdg/Public";
|
||||||
|
templates = "$HOME/.xdg/Templates";
|
||||||
|
videos = "$HOME/Videos";
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.zsh = {
|
||||||
|
enable = true;
|
||||||
|
enableSyntaxHighlighting = true;
|
||||||
|
enableVteIntegration = true;
|
||||||
|
dotDir = ".config/zsh";
|
||||||
|
|
||||||
|
initExtraBeforeCompInit = ''
|
||||||
|
# p10k instant prompt
|
||||||
|
# run p10k configure to configure, but it can't write out its file :-(
|
||||||
|
POWERLEVEL9K_DISABLE_CONFIGURATION_WIZARD=true
|
||||||
|
'';
|
||||||
|
|
||||||
|
# prezto = oh-my-zsh fork; controls prompt, auto-completion, etc.
|
||||||
|
# see: https://github.com/sorin-ionescu/prezto
|
||||||
|
prezto = {
|
||||||
|
enable = true;
|
||||||
|
pmodules = [
|
||||||
|
"environment"
|
||||||
|
"terminal"
|
||||||
|
"editor"
|
||||||
|
"history"
|
||||||
|
"directory"
|
||||||
|
"spectrum"
|
||||||
|
"utility"
|
||||||
|
"completion"
|
||||||
|
"prompt"
|
||||||
|
"git"
|
||||||
|
];
|
||||||
|
prompt = {
|
||||||
|
theme = "powerlevel10k";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
programs.kitty.enable = true;
|
||||||
|
programs.git = {
|
||||||
|
enable = true;
|
||||||
|
userName = "colin";
|
||||||
|
userEmail = "colin@uninsane.org";
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.vim = {
|
||||||
|
enable = true;
|
||||||
|
extraConfig = ''
|
||||||
|
" wtf vim project: NOBODY LIKES MOUSE FOR VISUAL MODE
|
||||||
|
set mouse-=a
|
||||||
|
" copy/paste to system clipboard
|
||||||
|
set clipboard=unnamedplus
|
||||||
|
" <tab> completion menu settings
|
||||||
|
set wildmenu
|
||||||
|
set wildmode=longest,list,full
|
||||||
|
" highlight all matching searches (using / and ?)
|
||||||
|
set hlsearch
|
||||||
|
" allow backspace to delete empty lines in insert mode
|
||||||
|
set backspace=indent,eol,start
|
||||||
|
" built-in syntax highlighting
|
||||||
|
syntax enable
|
||||||
|
" show line/col number in bottom right
|
||||||
|
set ruler
|
||||||
|
" highlight trailing space & related syntax errors (does this work?)
|
||||||
|
let c_space_errors=1
|
||||||
|
let python_space_errors=1
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# obtain these by running `dconf dump /` after manually customizing gnome
|
||||||
|
# TODO: fix "is not of type `GVariant value'"
|
||||||
|
# dconf.settings = lib.mkIf (gui == "gnome") {
|
||||||
|
# gnome = {
|
||||||
|
# # control alt-tab behavior
|
||||||
|
# "org/gnome/desktop/wm/keybindings" = {
|
||||||
|
# switch-applications = [ "<Super>Tab" ];
|
||||||
|
# switch-applications-backward=[];
|
||||||
|
# switch-windows=["<Alt>Tab"];
|
||||||
|
# switch-windows-backward=["<Super><Alt>Tab"];
|
||||||
|
# };
|
||||||
|
# # idle power savings
|
||||||
|
# "org/gnome/settings-deamon/plugins/power" = {
|
||||||
|
# idle-brigthness = 50;
|
||||||
|
# sleep-inactive-ac-type = "nothing";
|
||||||
|
# sleep-inactive-battery-timeout = 5400; # seconds
|
||||||
|
# };
|
||||||
|
# "org/gnome/shell" = {
|
||||||
|
# favorite-apps = [
|
||||||
|
# "org.gnome.Nautilus.desktop"
|
||||||
|
# "firefox.desktop"
|
||||||
|
# "kitty.desktop"
|
||||||
|
# # "org.gnome.Terminal.desktop"
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
# "org/gnome/desktop/session" = {
|
||||||
|
# # how long until considering a session idle (triggers e.g. screen blanking)
|
||||||
|
# idle-delay = 900;
|
||||||
|
# };
|
||||||
|
# "org/gnome/desktop/interface" = {
|
||||||
|
# text-scaling-factor = 1.25;
|
||||||
|
# };
|
||||||
|
# "org/gnome/desktop/media-handling" = {
|
||||||
|
# # don't auto-mount inserted media
|
||||||
|
# automount = false;
|
||||||
|
# automount-open = false;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# home.pointerCursor = {
|
||||||
|
# package = pkgs.vanilla-dmz;
|
||||||
|
# name = "Vanilla-DMZ";
|
||||||
|
# };
|
||||||
|
|
||||||
|
# taken from https://github.com/srid/nix-config/blob/705a70c094da53aa50cf560179b973529617eb31/nix/home/i3.nix
|
||||||
|
xsession.windowManager.i3 = lib.mkIf (gui == "i3") (
|
||||||
|
let
|
||||||
|
mod = "Mod4";
|
||||||
|
in {
|
||||||
|
enable = true;
|
||||||
|
config = {
|
||||||
|
modifier = mod;
|
||||||
|
|
||||||
|
fonts = {
|
||||||
|
names = [ "DejaVu Sans Mono" ];
|
||||||
|
style = "Bold Semi-Condensed";
|
||||||
|
size = 11.0;
|
||||||
|
};
|
||||||
|
|
||||||
|
# terminal = "kitty";
|
||||||
|
# terminal = "${pkgs.kitty}/bin/kitty";
|
||||||
|
|
||||||
|
keybindings = {
|
||||||
|
"${mod}+Return" = "exec ${pkgs.kitty}/bin/kitty";
|
||||||
|
"${mod}+p" = "exec ${pkgs.dmenu}/bin/dmenu_run";
|
||||||
|
"${mod}+x" = "exec sh -c '${pkgs.maim}/bin/maim -s | xclip -selection clipboard -t image/png'";
|
||||||
|
"${mod}+Shift+x" = "exec sh -c '${pkgs.i3lock}/bin/i3lock -c 222222 & sleep 5 && xset dpms force of'";
|
||||||
|
|
||||||
|
# Focus
|
||||||
|
"${mod}+j" = "focus left";
|
||||||
|
"${mod}+k" = "focus down";
|
||||||
|
"${mod}+l" = "focus up";
|
||||||
|
"${mod}+semicolon" = "focus right";
|
||||||
|
|
||||||
|
# Move
|
||||||
|
"${mod}+Shift+j" = "move left";
|
||||||
|
"${mod}+Shift+k" = "move down";
|
||||||
|
"${mod}+Shift+l" = "move up";
|
||||||
|
"${mod}+Shift+semicolon" = "move right";
|
||||||
|
|
||||||
|
# multi monitor setup
|
||||||
|
# "${mod}+m" = "move workspace to output DP-2";
|
||||||
|
# "${mod}+Shift+m" = "move workspace to output DP-5";
|
||||||
|
};
|
||||||
|
|
||||||
|
# bars = [
|
||||||
|
# {
|
||||||
|
# position = "bottom";
|
||||||
|
# statusCommand = "${pkgs.i3status-rust}/bin/i3status-rs ${./i3status-rust.toml}";
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
wayland.windowManager.sway = lib.mkIf (gui == "sway") {
|
||||||
|
enable = true;
|
||||||
|
wrapperFeatures.gtk = true;
|
||||||
|
config = rec {
|
||||||
|
terminal = "${pkgs.kitty}/bin/kitty";
|
||||||
|
window.border = 3; # pixel boundary between windows
|
||||||
|
|
||||||
|
# defaults; required for keybindings decl.
|
||||||
|
modifier = "Mod1";
|
||||||
|
# list of launchers: https://www.reddit.com/r/swaywm/comments/v39hxa/your_favorite_launcher/
|
||||||
|
# menu = "${pkgs.dmenu}/bin/dmenu_path";
|
||||||
|
menu = "${pkgs.fuzzel}/bin/fuzzel";
|
||||||
|
# menu = "${pkgs.albert}/bin/albert";
|
||||||
|
left = "h";
|
||||||
|
down = "j";
|
||||||
|
up = "k";
|
||||||
|
right = "l";
|
||||||
|
keybindings = {
|
||||||
|
"${modifier}+Return" = "exec ${terminal}";
|
||||||
|
"${modifier}+Shift+q" = "kill";
|
||||||
|
"${modifier}+d" = "exec ${menu}";
|
||||||
|
|
||||||
|
"${modifier}+${left}" = "focus left";
|
||||||
|
"${modifier}+${down}" = "focus down";
|
||||||
|
"${modifier}+${up}" = "focus up";
|
||||||
|
"${modifier}+${right}" = "focus right";
|
||||||
|
|
||||||
|
"${modifier}+Left" = "focus left";
|
||||||
|
"${modifier}+Down" = "focus down";
|
||||||
|
"${modifier}+Up" = "focus up";
|
||||||
|
"${modifier}+Right" = "focus right";
|
||||||
|
|
||||||
|
"${modifier}+Shift+${left}" = "move left";
|
||||||
|
"${modifier}+Shift+${down}" = "move down";
|
||||||
|
"${modifier}+Shift+${up}" = "move up";
|
||||||
|
"${modifier}+Shift+${right}" = "move right";
|
||||||
|
|
||||||
|
"${modifier}+Shift+Left" = "move left";
|
||||||
|
"${modifier}+Shift+Down" = "move down";
|
||||||
|
"${modifier}+Shift+Up" = "move up";
|
||||||
|
"${modifier}+Shift+Right" = "move right";
|
||||||
|
|
||||||
|
"${modifier}+b" = "splith";
|
||||||
|
"${modifier}+v" = "splitv";
|
||||||
|
"${modifier}+f" = "fullscreen toggle";
|
||||||
|
"${modifier}+a" = "focus parent";
|
||||||
|
|
||||||
|
"${modifier}+s" = "layout stacking";
|
||||||
|
"${modifier}+w" = "layout tabbed";
|
||||||
|
"${modifier}+e" = "layout toggle split";
|
||||||
|
|
||||||
|
"${modifier}+Shift+space" = "floating toggle";
|
||||||
|
"${modifier}+space" = "focus mode_toggle";
|
||||||
|
|
||||||
|
"${modifier}+1" = "workspace number 1";
|
||||||
|
"${modifier}+2" = "workspace number 2";
|
||||||
|
"${modifier}+3" = "workspace number 3";
|
||||||
|
"${modifier}+4" = "workspace number 4";
|
||||||
|
"${modifier}+5" = "workspace number 5";
|
||||||
|
"${modifier}+6" = "workspace number 6";
|
||||||
|
"${modifier}+7" = "workspace number 7";
|
||||||
|
"${modifier}+8" = "workspace number 8";
|
||||||
|
"${modifier}+9" = "workspace number 9";
|
||||||
|
|
||||||
|
"${modifier}+Shift+1" =
|
||||||
|
"move container to workspace number 1";
|
||||||
|
"${modifier}+Shift+2" =
|
||||||
|
"move container to workspace number 2";
|
||||||
|
"${modifier}+Shift+3" =
|
||||||
|
"move container to workspace number 3";
|
||||||
|
"${modifier}+Shift+4" =
|
||||||
|
"move container to workspace number 4";
|
||||||
|
"${modifier}+Shift+5" =
|
||||||
|
"move container to workspace number 5";
|
||||||
|
"${modifier}+Shift+6" =
|
||||||
|
"move container to workspace number 6";
|
||||||
|
"${modifier}+Shift+7" =
|
||||||
|
"move container to workspace number 7";
|
||||||
|
"${modifier}+Shift+8" =
|
||||||
|
"move container to workspace number 8";
|
||||||
|
"${modifier}+Shift+9" =
|
||||||
|
"move container to workspace number 9";
|
||||||
|
|
||||||
|
"${modifier}+Shift+minus" = "move scratchpad";
|
||||||
|
"${modifier}+minus" = "scratchpad show";
|
||||||
|
|
||||||
|
"${modifier}+Shift+c" = "reload";
|
||||||
|
"${modifier}+Shift+e" =
|
||||||
|
"exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'";
|
||||||
|
|
||||||
|
"${modifier}+r" = "mode resize";
|
||||||
|
} // {
|
||||||
|
# media keys
|
||||||
|
XF86MonBrightnessDown = ''exec "${pkgs.brightnessctl}/bin/brightnessctl set 2%-"'';
|
||||||
|
XF86MonBrightnessUp = ''exec "${pkgs.brightnessctl}/bin/brightnessctl set +2%"'';
|
||||||
|
|
||||||
|
XF86AudioRaiseVolume = "exec '${pkgs.pulsemixer}/bin/pulsemixer --change-volume +5'";
|
||||||
|
XF86AudioLowerVolume = "exec '${pkgs.pulsemixer}/bin/pulsemixer --change-volume -5'";
|
||||||
|
XF86AudioMute = "exec '${pkgs.pulsemixer}/bin/pulsemixer --toggle-mute'";
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
# mostly defaults:
|
||||||
|
bars = [{
|
||||||
|
mode = "dock";
|
||||||
|
hiddenState = "hide";
|
||||||
|
position = "top";
|
||||||
|
command = "${pkgs.waybar}/bin/waybar";
|
||||||
|
workspaceButtons = true;
|
||||||
|
workspaceNumbers = true;
|
||||||
|
statusCommand = "${pkgs.i3status}/bin/i3status";
|
||||||
|
fonts = {
|
||||||
|
names = [ "monospace" ];
|
||||||
|
size = 8.0;
|
||||||
|
};
|
||||||
|
trayOutput = "primary";
|
||||||
|
colors = {
|
||||||
|
background = "#000000";
|
||||||
|
statusline = "#ffffff";
|
||||||
|
separator = "#666666";
|
||||||
|
focusedWorkspace = {
|
||||||
|
border = "#4c7899";
|
||||||
|
background = "#285577";
|
||||||
|
text = "#ffffff";
|
||||||
|
};
|
||||||
|
activeWorkspace = {
|
||||||
|
border = "#333333";
|
||||||
|
background = "#5f676a";
|
||||||
|
text = "#ffffff";
|
||||||
|
};
|
||||||
|
inactiveWorkspace = {
|
||||||
|
border = "#333333";
|
||||||
|
background = "#222222";
|
||||||
|
text = "#888888";
|
||||||
|
};
|
||||||
|
urgentWorkspace = {
|
||||||
|
border = "#2f343a";
|
||||||
|
background = "#900000";
|
||||||
|
text = "#ffffff";
|
||||||
|
};
|
||||||
|
bindingMode = {
|
||||||
|
border = "#2f343a";
|
||||||
|
background = "#900000";
|
||||||
|
text = "#ffffff";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.waybar = lib.mkIf (gui == "sway") {
|
||||||
|
enable = true;
|
||||||
|
# docs: https://github.com/Alexays/Waybar/wiki/Configuration
|
||||||
|
settings = {
|
||||||
|
mainBar = {
|
||||||
|
layer = "top";
|
||||||
|
height = 40;
|
||||||
|
modules-left = ["sway/workspaces" "sway/mode"];
|
||||||
|
modules-center = ["sway/window"];
|
||||||
|
modules-right = ["custom/mediaplayer" "clock" "cpu" "network"];
|
||||||
|
"sway/window" = {
|
||||||
|
max-length = 50;
|
||||||
|
};
|
||||||
|
# include song artist/title. source: https://www.reddit.com/r/swaywm/comments/ni0vso/waybar_spotify_tracktitle/
|
||||||
|
"custom/mediaplayer" = {
|
||||||
|
exec = pkgs.writeShellScript "waybar-mediaplayer" ''
|
||||||
|
player_status=$(${pkgs.playerctl}/bin/playerctl status 2> /dev/null)
|
||||||
|
if [ "$player_status" = "Playing" ]; then
|
||||||
|
echo "$(${pkgs.playerctl}/bin/playerctl metadata artist) - $(${pkgs.playerctl}/bin/playerctl metadata title)"
|
||||||
|
elif [ "$player_status" = "Paused" ]; then
|
||||||
|
echo " $(${pkgs.playerctl}/bin/playerctl metadata artist) - $(${pkgs.playerctl}/bin/playerctl metadata title)"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
interval = 2;
|
||||||
|
format = "{} ";
|
||||||
|
# return-type = "json";
|
||||||
|
on-click = "${pkgs.playerctl}/bin/playerctl play-pause";
|
||||||
|
on-scroll-up = "${pkgs.playerctl}/bin/playerctl next";
|
||||||
|
on-scroll-down = "${pkgs.playerctl}/bin/playerctl previous";
|
||||||
|
};
|
||||||
|
network = {
|
||||||
|
interval = 1;
|
||||||
|
format-ethernet = "{ifname}: {ipaddr}/{cidr} up: {bandwidthUpBits} down: {bandwidthDownBits}";
|
||||||
|
};
|
||||||
|
cpu = {
|
||||||
|
format = "{usage}% ";
|
||||||
|
tooltip = false;
|
||||||
|
};
|
||||||
|
clock = {
|
||||||
|
format-alt = "{:%a, %d. %b %H:%M}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
# style = ''
|
||||||
|
# * {
|
||||||
|
# border: none;
|
||||||
|
# border-radius: 0;
|
||||||
|
# font-family: Source Code Pro;
|
||||||
|
# }
|
||||||
|
# window#waybar {
|
||||||
|
# background: #16191C;
|
||||||
|
# color: #AAB2BF;
|
||||||
|
# }
|
||||||
|
# #workspaces button {
|
||||||
|
# padding: 0 5px;
|
||||||
|
# }
|
||||||
|
# .custom-spotify {
|
||||||
|
# padding: 0 10px;
|
||||||
|
# margin: 0 4px;
|
||||||
|
# background-color: #1DB954;
|
||||||
|
# color: black;
|
||||||
|
# }
|
||||||
|
# '';
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
programs.firefox = lib.mkIf (gui != null) {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
profiles.default = {
|
||||||
|
bookmarks = {
|
||||||
|
fed_uninsane.url = "https://fed.uninsane.org/";
|
||||||
|
delightful.url = "https://delightful.club/";
|
||||||
|
crowdsupply.url = "https://www.crowdsupply.com/";
|
||||||
|
linux_phone_apps.url = "https://linuxphoneapps.org/mobile-compatibility/5/";
|
||||||
|
mempool.url = "https://jochen-hoenicke.de/queue";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# firefox profile support seems to be broken :shrug:
|
||||||
|
# profiles.other = {
|
||||||
|
# id = 2;
|
||||||
|
# };
|
||||||
|
|
||||||
|
# NB: these must be manually enabled in the Firefox settings on first start
|
||||||
|
# extensions can be found here: https://gitlab.com/rycee/nur-expressions/-/blob/master/pkgs/firefox-addons/addons.json
|
||||||
|
extensions = [
|
||||||
|
pkgs.nur.repos.rycee.firefox-addons.bypass-paywalls-clean
|
||||||
|
pkgs.nur.repos.rycee.firefox-addons.metamask
|
||||||
|
pkgs.nur.repos.rycee.firefox-addons.i-dont-care-about-cookies
|
||||||
|
pkgs.nur.repos.rycee.firefox-addons.sidebery
|
||||||
|
pkgs.nur.repos.rycee.firefox-addons.sponsorblock
|
||||||
|
pkgs.nur.repos.rycee.firefox-addons.ublock-origin
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
home.shellAliases = {
|
||||||
|
":q" = "exit";
|
||||||
|
# common typos
|
||||||
|
"cd.." = "cd ..";
|
||||||
|
"cd../" = "cd ../";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
home.packages = [
|
||||||
|
pkgs.btrfs-progs
|
||||||
|
pkgs.dig
|
||||||
|
pkgs.cryptsetup
|
||||||
|
pkgs.duplicity
|
||||||
|
pkgs.fatresize
|
||||||
|
pkgs.fd
|
||||||
|
pkgs.file
|
||||||
|
pkgs.gnumake
|
||||||
|
pkgs.gptfdisk
|
||||||
|
pkgs.hdparm
|
||||||
|
pkgs.htop
|
||||||
|
pkgs.iftop
|
||||||
|
pkgs.inetutils # for telnet
|
||||||
|
pkgs.iotop
|
||||||
|
pkgs.iptables
|
||||||
|
pkgs.jq
|
||||||
|
pkgs.killall
|
||||||
|
pkgs.lm_sensors # for sensors-detect
|
||||||
|
pkgs.lsof
|
||||||
|
pkgs.mix2nix
|
||||||
|
pkgs.netcat
|
||||||
|
pkgs.nixpkgs-review
|
||||||
|
pkgs.nixUnstable # TODO: still needed on 22.05?
|
||||||
|
# pkgs.nixos-generators
|
||||||
|
# pkgs.nettools
|
||||||
|
pkgs.nmap
|
||||||
|
pkgs.obsidian
|
||||||
|
pkgs.parted
|
||||||
|
pkgs.pciutils
|
||||||
|
# pkgs.ponymix
|
||||||
|
pkgs.powertop
|
||||||
|
pkgs.pulsemixer
|
||||||
|
pkgs.python3
|
||||||
|
pkgs.ripgrep
|
||||||
|
pkgs.smartmontools
|
||||||
|
pkgs.snapper
|
||||||
|
pkgs.socat
|
||||||
|
pkgs.sudo
|
||||||
|
pkgs.usbutils
|
||||||
|
pkgs.wget
|
||||||
|
pkgs.wireguard-tools
|
||||||
|
pkgs.youtube-dl
|
||||||
|
pkgs.zola
|
||||||
|
]
|
||||||
|
++ (if gui != null then
|
||||||
|
[
|
||||||
|
# GUI only
|
||||||
|
pkgs.chromium
|
||||||
|
pkgs.clinfo
|
||||||
|
pkgs.element-desktop # broken on phosh
|
||||||
|
pkgs.evince # works on phosh
|
||||||
|
pkgs.font-manager
|
||||||
|
pkgs.gimp # broken on phosh
|
||||||
|
pkgs.gnome.dconf-editor
|
||||||
|
pkgs.gnome.file-roller
|
||||||
|
pkgs.gnome.gnome-maps # works on phosh
|
||||||
|
pkgs.gnome.nautilus
|
||||||
|
pkgs.gnome-podcasts
|
||||||
|
pkgs.gnome.gnome-terminal # works on phosh
|
||||||
|
pkgs.inkscape
|
||||||
|
pkgs.kaiteki # Pleroma client
|
||||||
|
pkgs.libreoffice-fresh # XXX colin: maybe don't want this on mobile
|
||||||
|
pkgs.mesa-demos
|
||||||
|
pkgs.playerctl
|
||||||
|
pkgs.tdesktop # broken on phosh
|
||||||
|
pkgs.vlc # works on phosh
|
||||||
|
pkgs.whalebird # pleroma client. input is broken on phosh
|
||||||
|
pkgs.xterm # broken on phosh
|
||||||
|
] else [])
|
||||||
|
++ (if gui == "sway" then
|
||||||
|
[
|
||||||
|
# TODO: move this to helpers/gui/sway.nix?
|
||||||
|
pkgs.swaylock
|
||||||
|
pkgs.swayidle
|
||||||
|
pkgs.wl-clipboard
|
||||||
|
pkgs.mako # notification daemon
|
||||||
|
# pkgs.dmenu # todo: use wofi?
|
||||||
|
# user stuff
|
||||||
|
# pkgs.pavucontrol
|
||||||
|
] else [])
|
||||||
|
++ (if gui != null && system == "x86_64-linux" then
|
||||||
|
[
|
||||||
|
# x86_64 only
|
||||||
|
pkgs.signal-desktop
|
||||||
|
pkgs.spotify
|
||||||
|
pkgs.discord
|
||||||
|
] else [])
|
||||||
|
++ extraPackages;
|
||||||
|
}
|
4
helpers/set-hostname.nix
Normal file
4
helpers/set-hostname.nix
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
hostName: { ... }:
|
||||||
|
{
|
||||||
|
networking.hostName = hostName;
|
||||||
|
}
|
17
helpers/universal/default.nix
Normal file
17
helpers/universal/default.nix
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./fs.nix
|
||||||
|
./home-manager.nix
|
||||||
|
./nix-cache.nix
|
||||||
|
./users.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
time.timeZone = "America/Los_Angeles";
|
||||||
|
|
||||||
|
environment.variables = {
|
||||||
|
EDITOR = "vim";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
25
helpers/universal/fs.nix
Normal file
25
helpers/universal/fs.nix
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
fileSystems."/mnt/media-uninsane" = {
|
||||||
|
# device = "sshfs#colin@uninsane.org:/opt/uninsane/media";
|
||||||
|
device = "colin@uninsane.org:/opt/uninsane/media";
|
||||||
|
fsType = "fuse.sshfs";
|
||||||
|
options = [
|
||||||
|
"x-systemd.automount"
|
||||||
|
"_netdev"
|
||||||
|
"user"
|
||||||
|
"idmap=user"
|
||||||
|
"transform_symlinks"
|
||||||
|
"identityfile=/home/colin/.ssh/id_ed25519"
|
||||||
|
"allow_other"
|
||||||
|
"default_permissions"
|
||||||
|
"uid=1000"
|
||||||
|
"gid=1000"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
environment.systemPackages = [
|
||||||
|
pkgs.sshfs-fuse
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
9
helpers/universal/home-manager.nix
Normal file
9
helpers/universal/home-manager.nix
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{ home-manager, config, pkgs, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
home-manager.nixosModule
|
||||||
|
];
|
||||||
|
|
||||||
|
home-manager.useGlobalPkgs = true;
|
||||||
|
home-manager.useUserPackages = true;
|
||||||
|
}
|
16
helpers/universal/nix-cache.nix
Normal file
16
helpers/universal/nix-cache.nix
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# use our own binary cache
|
||||||
|
nix.settings = {
|
||||||
|
substituters = [
|
||||||
|
"https://nixcache.uninsane.org"
|
||||||
|
"https://nix-community.cachix.org"
|
||||||
|
"https://cache.nixos.org/"
|
||||||
|
];
|
||||||
|
trusted-public-keys = [
|
||||||
|
"nixcache.uninsane.org:r3WILM6+QrkmsLgqVQcEdibFD7Q/4gyzD9dGT33GP70="
|
||||||
|
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
53
helpers/universal/users.nix
Normal file
53
helpers/universal/users.nix
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
# installer docs: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/installation-device.nix
|
||||||
|
{
|
||||||
|
# Users are exactly these specified here;
|
||||||
|
# old ones will be deleted (from /etc/passwd, etc) upon upgrade.
|
||||||
|
users.mutableUsers = false;
|
||||||
|
|
||||||
|
# docs: https://nixpkgs-manual-sphinx-markedown-example.netlify.app/generated/options-db.xml.html#users-users
|
||||||
|
users.users.colin = {
|
||||||
|
# sets group to "users" (?)
|
||||||
|
isNormalUser = true;
|
||||||
|
home = "/home/colin";
|
||||||
|
uid = 1000;
|
||||||
|
# XXX colin: this is what the installer has, but is it necessary?
|
||||||
|
# group = "users";
|
||||||
|
extraGroups = [
|
||||||
|
"wheel"
|
||||||
|
"nixbuild"
|
||||||
|
"networkmanager"
|
||||||
|
# phosh/mobile. XXX colin: unsure if necessary
|
||||||
|
"video"
|
||||||
|
"feedbackd"
|
||||||
|
"dialout" # required for modem access
|
||||||
|
];
|
||||||
|
initialPassword = lib.mkDefault "";
|
||||||
|
shell = pkgs.zsh;
|
||||||
|
# shell = pkgs.bashInteractive;
|
||||||
|
# XXX colin: create ssh key for THIS user by logging in and running:
|
||||||
|
# ssh-keygen -t ed25519
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGSDe/y0e9PSeUwYlMPjzhW0UhNsGAGsW3lCG3apxrD5 colin@colin.desktop"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG+MZ/l5d8g5hbxMB9ed1uyvhV85jwNrSVNVxb5ujQjw colin@lappy"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPU5GlsSfbaarMvDA20bxpSZGWviEzXGD8gtrIowc1pX colin@desko"
|
||||||
|
# TODO: should probably only let this authenticate to my server
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGCLCA9KbjXaXNNMJJvqbPO5KQQ64JCdG8sg88AfdKzi colin@moby"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
security.sudo = {
|
||||||
|
enable = true;
|
||||||
|
wheelNeedsPassword = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.openssh = {
|
||||||
|
enable = true;
|
||||||
|
permitRootLogin = "no";
|
||||||
|
passwordAuthentication = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
# TODO colin: move this somewhere else!
|
||||||
|
programs.vim.defaultEditor = true;
|
||||||
|
}
|
@@ -1,16 +0,0 @@
|
|||||||
{ lib, pkgs, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
# persist external pairings by default
|
|
||||||
sane.persist.sys.plaintext = [ "/var/lib/bluetooth" ];
|
|
||||||
|
|
||||||
sane.fs."/var/lib/bluetooth".generated.acl.mode = "0700";
|
|
||||||
sane.fs."/var/lib/bluetooth/.secrets.stamp" = {
|
|
||||||
wantedBeforeBy = [ "bluetooth.service" ];
|
|
||||||
# XXX: install-bluetooth uses sed, but that's part of the default systemd unit path, it seems
|
|
||||||
generated.script.script = builtins.readFile ../../scripts/install-bluetooth + ''
|
|
||||||
touch "/var/lib/bluetooth/.secrets.stamp"
|
|
||||||
'';
|
|
||||||
generated.script.scriptArgs = [ "/run/secrets/bt" ];
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,15 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
# the configuration of which specific package set `pkgs.cross` refers to happens elsewhere;
|
|
||||||
# here we just define them all.
|
|
||||||
nixpkgs.overlays = [
|
|
||||||
(next: prev: {
|
|
||||||
# non-emulated packages build *from* local *for* target.
|
|
||||||
# for large packages like the linux kernel which are expensive to build under emulation,
|
|
||||||
# the config can explicitly pull such packages from `pkgs.cross` to do more efficient cross-compilation.
|
|
||||||
crossFrom."x86_64-linux" = (prev.forceSystem "x86_64-linux" null).appendOverlays next.overlays;
|
|
||||||
crossFrom."aarch64-linux" = (prev.forceSystem "aarch64-linux" null).appendOverlays next.overlays;
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
|
@@ -1,77 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./bluetooth.nix
|
|
||||||
./cross.nix
|
|
||||||
./feeds.nix
|
|
||||||
./fs.nix
|
|
||||||
./hardware
|
|
||||||
./i2p.nix
|
|
||||||
./ids.nix
|
|
||||||
./machine-id.nix
|
|
||||||
./net.nix
|
|
||||||
./secrets.nix
|
|
||||||
./ssh.nix
|
|
||||||
./users.nix
|
|
||||||
./vpn.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
sane.home-manager.enable = true;
|
|
||||||
sane.nixcache.enable-trusted-keys = true;
|
|
||||||
sane.packages.enableConsolePkgs = true;
|
|
||||||
sane.packages.enableSystemPkgs = true;
|
|
||||||
|
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
"/var/log"
|
|
||||||
"/var/backup" # for e.g. postgres dumps
|
|
||||||
# TODO: move elsewhere
|
|
||||||
"/var/lib/alsa" # preserve output levels, default devices
|
|
||||||
"/var/lib/colord" # preserve color calibrations (?)
|
|
||||||
"/var/lib/machines" # maybe not needed, but would be painful to add a VM and forget.
|
|
||||||
];
|
|
||||||
|
|
||||||
nixpkgs.config.allowUnfree = true;
|
|
||||||
|
|
||||||
# time.timeZone = "America/Los_Angeles";
|
|
||||||
time.timeZone = "Etc/UTC"; # DST is too confusing for me => use a stable timezone
|
|
||||||
|
|
||||||
# allow `nix flake ...` command
|
|
||||||
nix.extraOptions = ''
|
|
||||||
experimental-features = nix-command flakes
|
|
||||||
'';
|
|
||||||
|
|
||||||
# TODO: move this into home-manager?
|
|
||||||
fonts = {
|
|
||||||
enableDefaultFonts = true;
|
|
||||||
fonts = with pkgs; [ font-awesome twitter-color-emoji hack-font ];
|
|
||||||
fontconfig.enable = true;
|
|
||||||
fontconfig.defaultFonts = {
|
|
||||||
emoji = [ "Font Awesome 6 Free" "Twitter Color Emoji" ];
|
|
||||||
monospace = [ "Hack" ];
|
|
||||||
serif = [ "DejaVu Serif" ];
|
|
||||||
sansSerif = [ "DejaVu Sans" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# disable non-required packages like nano, perl, rsync, strace
|
|
||||||
environment.defaultPackages = [];
|
|
||||||
|
|
||||||
# programs.vim.defaultEditor = true;
|
|
||||||
environment.variables = {
|
|
||||||
EDITOR = "vim";
|
|
||||||
# git claims it should use EDITOR, but it doesn't!
|
|
||||||
GIT_EDITOR = "vim";
|
|
||||||
# TODO: these should be moved to `home.sessionVariables` (home-manager)
|
|
||||||
# Electron apps should use native wayland backend:
|
|
||||||
# https://nixos.wiki/wiki/Slack#Wayland
|
|
||||||
# Discord under sway crashes with this.
|
|
||||||
# NIXOS_OZONE_WL = "1";
|
|
||||||
# LIBGL_ALWAYS_SOFTWARE = "1";
|
|
||||||
};
|
|
||||||
# enable zsh completions
|
|
||||||
environment.pathsToLink = [ "/share/zsh" ];
|
|
||||||
|
|
||||||
# link debug symbols into /run/current-system/sw/lib/debug
|
|
||||||
# hopefully picked up by gdb automatically?
|
|
||||||
environment.enableDebugInfo = true;
|
|
||||||
}
|
|
@@ -1,184 +0,0 @@
|
|||||||
{ lib, sane-data, ... }:
|
|
||||||
let
|
|
||||||
hourly = { freq = "hourly"; };
|
|
||||||
daily = { freq = "daily"; };
|
|
||||||
weekly = { freq = "weekly"; };
|
|
||||||
infrequent = { freq = "infrequent"; };
|
|
||||||
|
|
||||||
art = { cat = "art"; };
|
|
||||||
humor = { cat = "humor"; };
|
|
||||||
pol = { cat = "pol"; }; # or maybe just "social"
|
|
||||||
rat = { cat = "rat"; };
|
|
||||||
tech = { cat = "tech"; };
|
|
||||||
uncat = { cat = "uncat"; };
|
|
||||||
|
|
||||||
text = { format = "text"; };
|
|
||||||
|
|
||||||
mkRss = format: url: { inherit url format; } // uncat // infrequent;
|
|
||||||
# format-specific helpers
|
|
||||||
mkText = mkRss "text";
|
|
||||||
mkImg = mkRss "image";
|
|
||||||
mkPod = mkRss "podcast";
|
|
||||||
|
|
||||||
# host-specific helpers
|
|
||||||
mkSubstack = subdomain: { substack = subdomain; };
|
|
||||||
|
|
||||||
fromDb = name:
|
|
||||||
let
|
|
||||||
raw = sane-data.feeds."${name}";
|
|
||||||
in {
|
|
||||||
url = raw.url;
|
|
||||||
# not sure the exact mapping with velocity here: entries per day?
|
|
||||||
freq = lib.mkDefault (
|
|
||||||
if raw.velocity or 0 > 2 then
|
|
||||||
"hourly"
|
|
||||||
else if raw.velocity or 0 > 0.5 then
|
|
||||||
"daily"
|
|
||||||
else if raw.velocity or 0 > 0.1 then
|
|
||||||
"weekly"
|
|
||||||
else
|
|
||||||
"infrequent"
|
|
||||||
);
|
|
||||||
} // lib.optionalAttrs (raw.is_podcast or false) {
|
|
||||||
format = "podcast";
|
|
||||||
};
|
|
||||||
|
|
||||||
podcasts = [
|
|
||||||
(fromDb "lexfridman.com/podcast" // rat)
|
|
||||||
# (mkPod "https://lexfridman.com/feed/podcast/" // rat // weekly)
|
|
||||||
## Astral Codex Ten
|
|
||||||
(fromDb "sscpodcast.libsyn.com" // rat)
|
|
||||||
## Econ Talk
|
|
||||||
(fromDb "feeds.simplecast.com/wgl4xEgL" // rat)
|
|
||||||
## Cory Doctorow -- both podcast & text entries
|
|
||||||
(fromDb "craphound.com" // pol)
|
|
||||||
(mkPod "https://congressionaldish.libsyn.com/rss" // pol // infrequent)
|
|
||||||
## Civboot -- https://anchor.fm/civboot
|
|
||||||
(fromDb "anchor.fm/s/34c7232c/podcast/rss" // tech)
|
|
||||||
(fromDb "feeds.feedburner.com/80000HoursPodcast" // rat)
|
|
||||||
(fromDb "allinchamathjason.libsyn.com" // pol)
|
|
||||||
(fromDb "acquired.libsyn.com" // tech)
|
|
||||||
# The Intercept - Deconstructed; also available: <rss.acast.com/deconstructed>
|
|
||||||
(fromDb "rss.prod.firstlook.media/deconstructed/podcast.rss" // pol)
|
|
||||||
## The Daily
|
|
||||||
(mkPod "https://feeds.simplecast.com/54nAGcIl" // pol // daily)
|
|
||||||
# The Intercept - Intercepted; also available: <https://rss.acast.com/intercepted-with-jeremy-scahill>
|
|
||||||
(fromDb "rss.prod.firstlook.media/intercepted/podcast.rss" // pol)
|
|
||||||
(fromDb "podcast.posttv.com/itunes/post-reports.xml" // pol)
|
|
||||||
## Eric Weinstein
|
|
||||||
(fromDb "rss.art19.com/the-portal" // rat)
|
|
||||||
(fromDb "darknetdiaries.com" // tech)
|
|
||||||
## Radiolab -- also available here, but ONLY OVER HTTP: <http://feeds.wnyc.org/radiolab>
|
|
||||||
(fromDb "feeds.feedburner.com/radiolab" // pol)
|
|
||||||
## Sam Harris
|
|
||||||
(fromDb "wakingup.libsyn.com" // pol)
|
|
||||||
## 99% Invisible -- also available here: <https://feeds.simplecast.com/BqbsxVfO>
|
|
||||||
(fromDb "feeds.99percentinvisible.org/99percentinvisible" // pol)
|
|
||||||
(fromDb "rss.acast.com/ft-tech-tonic" // tech)
|
|
||||||
(fromDb "feeds.feedburner.com/dancarlin/history" // rat)
|
|
||||||
(fromDb "rss.art19.com/60-minutes" // pol)
|
|
||||||
## The Verge - Decoder
|
|
||||||
(fromDb "feeds.megaphone.fm/recodedecode" // tech)
|
|
||||||
## Matrix (chat) Live
|
|
||||||
(fromDb "feed.podbean.com/matrixlive/feed.xml" // tech)
|
|
||||||
## Michael Malice - Your Welcome -- also available here: <https://origin.podcastone.com/podcast?categoryID2=2232>
|
|
||||||
(fromDb "rss.art19.com/your-welcome" // pol)
|
|
||||||
];
|
|
||||||
|
|
||||||
texts = [
|
|
||||||
# AGGREGATORS (> 1 post/day)
|
|
||||||
(fromDb "lesswrong.com" // rat)
|
|
||||||
(fromDb "econlib.org" // pol)
|
|
||||||
|
|
||||||
# AGGREGATORS (< 1 post/day)
|
|
||||||
(mkText "https://palladiummag.com/feed" // uncat // weekly)
|
|
||||||
(mkText "https://profectusmag.com/feed" // uncat // weekly)
|
|
||||||
(mkText "https://semiaccurate.com/feed" // tech // weekly)
|
|
||||||
(mkText "https://linuxphoneapps.org/blog/atom.xml" // tech // infrequent)
|
|
||||||
(mkText "https://spectrum.ieee.org/rss" // tech // weekly)
|
|
||||||
|
|
||||||
## No Moods, Ads or Cutesy Fucking Icons
|
|
||||||
(mkText "https://www.rifters.com/crawl/?feed=rss2" // uncat // weekly)
|
|
||||||
|
|
||||||
# DEVELOPERS
|
|
||||||
(fromDb "uninsane.org" // tech)
|
|
||||||
(fromDb "mg.lol" // tech)
|
|
||||||
## Ken Shirriff
|
|
||||||
(fromDb "righto.com" // tech)
|
|
||||||
## Vitalik Buterin
|
|
||||||
(mkText "https://vitalik.ca/feed.xml" // tech // infrequent)
|
|
||||||
## ian (Sanctuary)
|
|
||||||
(mkText "https://sagacioussuricata.com/feed.xml" // tech // infrequent)
|
|
||||||
## Bunnie Juang
|
|
||||||
(mkText "https://www.bunniestudios.com/blog/?feed=rss2" // tech // infrequent)
|
|
||||||
(mkText "https://blog.danieljanus.pl/atom.xml" // tech // infrequent)
|
|
||||||
(mkText "https://ianthehenry.com/feed.xml" // tech // infrequent)
|
|
||||||
(mkText "https://bitbashing.io/feed.xml" // tech // infrequent)
|
|
||||||
(mkText "https://idiomdrottning.org/feed.xml" // uncat // daily)
|
|
||||||
(mkText "https://anish.lakhwara.com/home.html" // tech // weekly)
|
|
||||||
(mkText "https://www.jefftk.com/news.rss" // tech // daily)
|
|
||||||
(mkText "https://pomeroyb.com/feed.xml" // tech // infrequent)
|
|
||||||
|
|
||||||
# (TECH; POL) COMMENTATORS
|
|
||||||
(fromDb "edwardsnowden.substack.com" // pol // text)
|
|
||||||
(mkText "http://benjaminrosshoffman.com/feed" // pol // weekly)
|
|
||||||
## Ben Thompson
|
|
||||||
(mkText "https://www.stratechery.com/rss" // pol // weekly)
|
|
||||||
## Balaji
|
|
||||||
(mkText "https://balajis.com/rss" // pol // weekly)
|
|
||||||
(mkText "https://www.ben-evans.com/benedictevans/rss.xml" // pol // weekly)
|
|
||||||
(mkText "https://www.lynalden.com/feed" // pol // infrequent)
|
|
||||||
(mkText "https://austinvernon.site/rss.xml" // tech // infrequent)
|
|
||||||
(mkSubstack "oversharing" // pol // daily)
|
|
||||||
(mkSubstack "doomberg" // tech // weekly)
|
|
||||||
## David Rosenthal
|
|
||||||
(mkText "https://blog.dshr.org/rss.xml" // pol // weekly)
|
|
||||||
## Matt Levine
|
|
||||||
(mkText "https://www.bloomberg.com/opinion/authors/ARbTQlRLRjE/matthew-s-levine.rss" // pol // weekly)
|
|
||||||
(mkText "https://stpeter.im/atom.xml" // pol // weekly)
|
|
||||||
|
|
||||||
# RATIONALITY/PHILOSOPHY/ETC
|
|
||||||
(mkSubstack "samkriss" // humor // infrequent)
|
|
||||||
(mkText "https://unintendedconsequenc.es/feed" // rat // infrequent)
|
|
||||||
(mkText "https://applieddivinitystudies.com/atom.xml" // rat // weekly)
|
|
||||||
(mkText "https://slimemoldtimemold.com/feed.xml" // rat // weekly)
|
|
||||||
(mkText "https://www.richardcarrier.info/feed" // rat // weekly)
|
|
||||||
(mkText "https://www.gwern.net/feed.xml" // uncat // infrequent)
|
|
||||||
## Jason Crawford
|
|
||||||
(mkText "https://rootsofprogress.org/feed.xml" // rat // weekly)
|
|
||||||
## Robin Hanson
|
|
||||||
(mkText "https://www.overcomingbias.com/feed" // rat // daily)
|
|
||||||
## Scott Alexander
|
|
||||||
(mkSubstack "astralcodexten" // rat // daily)
|
|
||||||
## Paul Christiano
|
|
||||||
(mkText "https://sideways-view.com/feed" // rat // infrequent)
|
|
||||||
## Sean Carroll
|
|
||||||
(mkText "https://www.preposterousuniverse.com/rss" // rat // infrequent)
|
|
||||||
|
|
||||||
## mostly dating topics. not advice, or humor, but looking through a social lens
|
|
||||||
(mkText "https://putanumonit.com/feed" // rat // infrequent)
|
|
||||||
|
|
||||||
# CODE
|
|
||||||
# (mkText "https://github.com/Kaiteki-Fedi/Kaiteki/commits/master.atom" // tech // infrequent)
|
|
||||||
];
|
|
||||||
|
|
||||||
images = [
|
|
||||||
(mkImg "https://www.smbc-comics.com/comic/rss" // humor // daily)
|
|
||||||
(mkImg "https://xkcd.com/atom.xml" // humor // daily)
|
|
||||||
(mkImg "https://pbfcomics.com/feed" // humor // infrequent)
|
|
||||||
# (mkImg "http://dilbert.com/feed" // humor // daily)
|
|
||||||
|
|
||||||
# ART
|
|
||||||
(mkImg "https://miniature-calendar.com/feed" // art // daily)
|
|
||||||
];
|
|
||||||
in
|
|
||||||
{
|
|
||||||
sane.feeds = texts ++ images ++ podcasts;
|
|
||||||
|
|
||||||
assertions = builtins.map
|
|
||||||
(p: {
|
|
||||||
assertion = p.format or "unknown" == "podcast";
|
|
||||||
message = ''${p.url} is not a podcast: ${p.format or "unknown"}'';
|
|
||||||
})
|
|
||||||
podcasts;
|
|
||||||
}
|
|
@@ -1,74 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
|
|
||||||
let sshOpts = rec {
|
|
||||||
fsType = "fuse.sshfs";
|
|
||||||
optionsBase = [
|
|
||||||
"x-systemd.automount"
|
|
||||||
"_netdev"
|
|
||||||
"user"
|
|
||||||
"identityfile=/home/colin/.ssh/id_ed25519"
|
|
||||||
"allow_other"
|
|
||||||
"default_permissions"
|
|
||||||
];
|
|
||||||
optionsColin = optionsBase ++ [
|
|
||||||
"transform_symlinks"
|
|
||||||
"idmap=user"
|
|
||||||
"uid=1000"
|
|
||||||
"gid=100"
|
|
||||||
];
|
|
||||||
|
|
||||||
optionsRoot = optionsBase ++ [
|
|
||||||
# we don't transform_symlinks because that breaks the validity of remote /nix stores
|
|
||||||
"sftp_server=/run/wrappers/bin/sudo\\040/run/current-system/sw/libexec/sftp-server"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
environment.pathsToLink = [
|
|
||||||
# needed to achieve superuser access for user-mounted filesystems (see optionsRoot above)
|
|
||||||
# we can only link whole directories here, even though we're only interested in pkgs.openssh
|
|
||||||
"/libexec"
|
|
||||||
];
|
|
||||||
|
|
||||||
fileSystems."/mnt/servo-media-wan" = {
|
|
||||||
device = "colin@uninsane.org:/var/lib/uninsane/media";
|
|
||||||
inherit (sshOpts) fsType;
|
|
||||||
options = sshOpts.optionsColin;
|
|
||||||
noCheck = true;
|
|
||||||
};
|
|
||||||
fileSystems."/mnt/servo-media-lan" = {
|
|
||||||
device = "colin@servo:/var/lib/uninsane/media";
|
|
||||||
inherit (sshOpts) fsType;
|
|
||||||
options = sshOpts.optionsColin;
|
|
||||||
noCheck = true;
|
|
||||||
};
|
|
||||||
fileSystems."/mnt/servo-root-wan" = {
|
|
||||||
device = "colin@uninsane.org:/";
|
|
||||||
inherit (sshOpts) fsType;
|
|
||||||
options = sshOpts.optionsRoot;
|
|
||||||
noCheck = true;
|
|
||||||
};
|
|
||||||
fileSystems."/mnt/servo-root-lan" = {
|
|
||||||
device = "colin@servo:/";
|
|
||||||
inherit (sshOpts) fsType;
|
|
||||||
options = sshOpts.optionsRoot;
|
|
||||||
noCheck = true;
|
|
||||||
};
|
|
||||||
fileSystems."/mnt/desko-home" = {
|
|
||||||
device = "colin@desko:/home/colin";
|
|
||||||
inherit (sshOpts) fsType;
|
|
||||||
options = sshOpts.optionsColin;
|
|
||||||
noCheck = true;
|
|
||||||
};
|
|
||||||
fileSystems."/mnt/desko-root" = {
|
|
||||||
device = "colin@desko:/";
|
|
||||||
inherit (sshOpts) fsType;
|
|
||||||
options = sshOpts.optionsRoot;
|
|
||||||
noCheck = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.systemPackages = [
|
|
||||||
pkgs.sshfs-fuse
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@@ -1,40 +0,0 @@
|
|||||||
{ lib, pkgs, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
boot.initrd.supportedFilesystems = [ "ext4" "btrfs" "ext2" "ext3" "vfat" ];
|
|
||||||
# useful emergency utils
|
|
||||||
boot.initrd.extraUtilsCommands = ''
|
|
||||||
copy_bin_and_libs ${pkgs.btrfs-progs}/bin/btrfstune
|
|
||||||
'';
|
|
||||||
boot.kernelParams = [ "boot.shell_on_fail" ];
|
|
||||||
# other kernelParams:
|
|
||||||
# "boot.trace"
|
|
||||||
# "systemd.log_level=debug"
|
|
||||||
# "systemd.log_target=console"
|
|
||||||
|
|
||||||
# hack in the `boot.shell_on_fail` arg since that doesn't always seem to work.
|
|
||||||
boot.initrd.preFailCommands = "allowShell=1";
|
|
||||||
|
|
||||||
# default: 4 (warn). 7 is debug
|
|
||||||
boot.consoleLogLevel = 7;
|
|
||||||
|
|
||||||
boot.loader.grub.enable = lib.mkDefault false;
|
|
||||||
boot.loader.generic-extlinux-compatible.enable = lib.mkDefault true;
|
|
||||||
|
|
||||||
# non-free firmware
|
|
||||||
hardware.enableRedistributableFirmware = true;
|
|
||||||
services.fwupd.enable = true;
|
|
||||||
|
|
||||||
# powertop will default to putting USB devices -- including HID -- to sleep after TWO SECONDS
|
|
||||||
powerManagement.powertop.enable = false;
|
|
||||||
|
|
||||||
# services.snapper.configs = {
|
|
||||||
# root = {
|
|
||||||
# subvolume = "/";
|
|
||||||
# extraConfig = {
|
|
||||||
# ALLOW_USERS = "colin";
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
# services.snapper.snapshotInterval = "daily";
|
|
||||||
}
|
|
@@ -1,8 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./all.nix
|
|
||||||
./x86_64.nix
|
|
||||||
];
|
|
||||||
}
|
|
@@ -1,26 +0,0 @@
|
|||||||
{ lib, pkgs, ... }:
|
|
||||||
|
|
||||||
with lib;
|
|
||||||
{
|
|
||||||
config = mkIf (pkgs.system == "x86_64-linux") {
|
|
||||||
boot.initrd.availableKernelModules = [
|
|
||||||
"xhci_pci" "ahci" "sd_mod" "sdhci_pci" # nixos-generate-config defaults
|
|
||||||
"usb_storage" # rpi needed this to boot from usb storage, i think.
|
|
||||||
"nvme" # to boot from nvme devices
|
|
||||||
# efi_pstore evivars
|
|
||||||
];
|
|
||||||
|
|
||||||
# enable cross compilation
|
|
||||||
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
|
|
||||||
# nixpkgs.config.allowUnsupportedSystem = true;
|
|
||||||
# nixpkgs.crossSystem.system = "aarch64-linux";
|
|
||||||
|
|
||||||
powerManagement.cpuFreqGovernor = "powersave";
|
|
||||||
hardware.cpu.amd.updateMicrocode = true; # desktop
|
|
||||||
hardware.cpu.intel.updateMicrocode = true; # laptop
|
|
||||||
|
|
||||||
hardware.opengl.driSupport = true;
|
|
||||||
# For 32 bit applications
|
|
||||||
hardware.opengl.driSupport32Bit = true;
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,4 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
{
|
|
||||||
services.i2p.enable = true;
|
|
||||||
}
|
|
@@ -1,60 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
# legacy servo users, some are inconvenient to migrate
|
|
||||||
sane.ids.dhcpcd.gid = 991;
|
|
||||||
sane.ids.dhcpcd.uid = 992;
|
|
||||||
sane.ids.gitea.gid = 993;
|
|
||||||
sane.ids.git.uid = 994;
|
|
||||||
sane.ids.jellyfin.gid = 994;
|
|
||||||
sane.ids.pleroma.gid = 995;
|
|
||||||
sane.ids.jellyfin.uid = 996;
|
|
||||||
sane.ids.acme.gid = 996;
|
|
||||||
sane.ids.pleroma.uid = 997;
|
|
||||||
sane.ids.acme.uid = 998;
|
|
||||||
|
|
||||||
# greetd (used by sway)
|
|
||||||
sane.ids.greeter.uid = 999;
|
|
||||||
sane.ids.greeter.gid = 999;
|
|
||||||
|
|
||||||
# new servo users
|
|
||||||
sane.ids.freshrss.uid = 2401;
|
|
||||||
sane.ids.freshrss.gid = 2401;
|
|
||||||
sane.ids.mediawiki.uid = 2402;
|
|
||||||
|
|
||||||
sane.ids.colin.uid = 1000;
|
|
||||||
sane.ids.guest.uid = 1100;
|
|
||||||
|
|
||||||
# found on all hosts
|
|
||||||
sane.ids.sshd.uid = 2001; # 997
|
|
||||||
sane.ids.sshd.gid = 2001; # 997
|
|
||||||
sane.ids.polkituser.gid = 2002; # 998
|
|
||||||
sane.ids.systemd-coredump.gid = 2003; # 996
|
|
||||||
sane.ids.nscd.uid = 2004;
|
|
||||||
sane.ids.nscd.gid = 2004;
|
|
||||||
sane.ids.systemd-oom.uid = 2005;
|
|
||||||
sane.ids.systemd-oom.gid = 2005;
|
|
||||||
|
|
||||||
# found on graphical hosts
|
|
||||||
sane.ids.nm-iodine.uid = 2101; # desko/moby/lappy
|
|
||||||
|
|
||||||
# found on desko host
|
|
||||||
# from services.usbmuxd
|
|
||||||
sane.ids.usbmux.uid = 2204;
|
|
||||||
sane.ids.usbmux.gid = 2204;
|
|
||||||
|
|
||||||
|
|
||||||
# originally found on moby host
|
|
||||||
# gnome core-shell
|
|
||||||
sane.ids.avahi.uid = 2304;
|
|
||||||
sane.ids.avahi.gid = 2304;
|
|
||||||
sane.ids.colord.uid = 2305;
|
|
||||||
sane.ids.colord.gid = 2305;
|
|
||||||
sane.ids.geoclue.uid = 2306;
|
|
||||||
sane.ids.geoclue.gid = 2306;
|
|
||||||
# gnome core-os-services
|
|
||||||
sane.ids.rtkit.uid = 2307;
|
|
||||||
sane.ids.rtkit.gid = 2307;
|
|
||||||
# phosh
|
|
||||||
sane.ids.feedbackd.gid = 2308;
|
|
||||||
}
|
|
@@ -1,16 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
{
|
|
||||||
# /etc/machine-id is a globally unique identifier used for:
|
|
||||||
# - systemd-networkd: DHCP lease renewal (instead of keying by the MAC address)
|
|
||||||
# - systemd-journald: to filter logs by host
|
|
||||||
# - chromium (potentially to track re-installations)
|
|
||||||
# - gdbus; system services that might upgrade to AF_LOCAL if both services can confirm they're on the same machine
|
|
||||||
# because of e.g. the chromium use, we *don't want* to persist this.
|
|
||||||
# however, `journalctl` won't show logs from previous boots unless the machine-ids match.
|
|
||||||
# so for now, generate something unique from the host ssh key.
|
|
||||||
# TODO: move this into modules?
|
|
||||||
system.activationScripts.machine-id = {
|
|
||||||
deps = [ "etc" ];
|
|
||||||
text = "sha256sum /etc/ssh/host_keys/ssh_host_ed25519_key | cut -c 1-32 > /etc/machine-id";
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,43 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
# if using router's DNS, these mappings will already exist.
|
|
||||||
# if using a different DNS provider (which servo does), then we need to explicity provide them.
|
|
||||||
# ugly hack. would be better to get servo to somehow use the router's DNS
|
|
||||||
networking.hosts = {
|
|
||||||
"192.168.0.5" = [ "servo" ];
|
|
||||||
"192.168.0.20" = [ "lappy" ];
|
|
||||||
"192.168.0.22" = [ "desko" ];
|
|
||||||
"192.168.0.48" = [ "moby" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
# the default backend is "wpa_supplicant".
|
|
||||||
# wpa_supplicant reliably picks weak APs to connect to.
|
|
||||||
# see: <https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/474>
|
|
||||||
# iwd is an alternative that shouldn't have this problem
|
|
||||||
# docs:
|
|
||||||
# - <https://nixos.wiki/wiki/Iwd>
|
|
||||||
# - <https://iwd.wiki.kernel.org/networkmanager>
|
|
||||||
# - `man iwd.config` for global config
|
|
||||||
# - `man iwd.network` for per-SSID config
|
|
||||||
# use `iwctl` to control
|
|
||||||
networking.networkmanager.wifi.backend = "iwd";
|
|
||||||
networking.wireless.iwd.enable = true;
|
|
||||||
networking.wireless.iwd.settings = {
|
|
||||||
# auto-connect to a stronger network if signal drops below this value
|
|
||||||
# bedroom -> bedroom connection is -35 to -40 dBm
|
|
||||||
# bedroom -> living room connection is -60 dBm
|
|
||||||
General.RoamThreshold = "-52"; # default -70
|
|
||||||
General.RoamThreshold5G = "-52"; # default -76
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.fs."/var/lib/iwd/.secrets.psk.stamp" = {
|
|
||||||
wantedBeforeBy = [ "iwd.service" ];
|
|
||||||
generated.acl.mode = "0600";
|
|
||||||
# XXX: install-iwd uses sed, but that's part of the default systemd unit path, it seems
|
|
||||||
generated.script.script = builtins.readFile ../../scripts/install-iwd + ''
|
|
||||||
touch "/var/lib/iwd/.secrets.psk.stamp"
|
|
||||||
'';
|
|
||||||
generated.script.scriptArgs = [ "/run/secrets/iwd" "/var/lib/iwd" ];
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,124 +0,0 @@
|
|||||||
{ config, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
# SOPS configuration:
|
|
||||||
# docs: https://github.com/Mic92/sops-nix
|
|
||||||
#
|
|
||||||
# for each new user you want to edit sops files:
|
|
||||||
# create a private age key from ssh key:
|
|
||||||
# $ mkdir -p ~/.config/sops/age; ssh-to-age -private-key -i ~/.ssh/id_ed25519 > ~/.config/sops/age/keys.txt; chmod 600 ~/.config/sops/age/keys.txt
|
|
||||||
# if the private key was password protected, then first decrypt it:
|
|
||||||
# $ cp ~/.ssh/id_ed25519 /tmp/id_ed25519
|
|
||||||
# $ ssh-keygen -p -N "" -f /tmp/id_ed25519
|
|
||||||
#
|
|
||||||
# for each user you want to decrypt secrets:
|
|
||||||
# $ cat ~/.ssh/id_ed25519.pub | ssh-to-age
|
|
||||||
# add the result to .sops.yaml
|
|
||||||
# since we specify ssh pubkeys in the nix config, you can just grep for `ssh-ed25519` here and use those instead
|
|
||||||
#
|
|
||||||
# for each host you want to decrypt secrets:
|
|
||||||
# $ cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age
|
|
||||||
# add the result to .sops.yaml
|
|
||||||
# $ sops updatekeys secrets/example.yaml
|
|
||||||
#
|
|
||||||
# to create a new secret:
|
|
||||||
# $ sops secrets/example.yaml
|
|
||||||
# control access below (sops.secret.<x>.owner = ...)
|
|
||||||
#
|
|
||||||
# to read a secret:
|
|
||||||
# $ cat /run/secrets/example_key
|
|
||||||
|
|
||||||
# sops.age.sshKeyPaths = [ "/home/colin/.ssh/id_ed25519_dec" ];
|
|
||||||
# This will add secrets.yaml to the nix store
|
|
||||||
# You can avoid this by adding a string to the full path instead, i.e.
|
|
||||||
# sops.defaultSopsFile = "/root/.sops/secrets/example.yaml";
|
|
||||||
sops.defaultSopsFile = ../../secrets/universal.yaml;
|
|
||||||
sops.gnupg.sshKeyPaths = []; # disable RSA key import
|
|
||||||
# This is using an age key that is expected to already be in the filesystem
|
|
||||||
# sops.age.keyFile = "/home/colin/.ssh/age.pub";
|
|
||||||
# sops.age.keyFile = "/var/lib/sops-nix/key.txt";
|
|
||||||
# This will generate a new key if the key specified above does not exist
|
|
||||||
# sops.age.generateKey = true;
|
|
||||||
# This is the actual specification of the secrets.
|
|
||||||
# sops.secrets.example_key = {
|
|
||||||
# owner = config.users.users.colin.name;
|
|
||||||
# };
|
|
||||||
# sops.secrets."myservice/my_subdir/my_secret" = {};
|
|
||||||
|
|
||||||
## universal secrets
|
|
||||||
# TODO: glob these?
|
|
||||||
|
|
||||||
sops.secrets."jackett_apikey" = {
|
|
||||||
sopsFile = ../../secrets/universal.yaml;
|
|
||||||
owner = config.users.users.colin.name;
|
|
||||||
};
|
|
||||||
sops.secrets."router_passwd" = {
|
|
||||||
sopsFile = ../../secrets/universal.yaml;
|
|
||||||
};
|
|
||||||
sops.secrets."wg_ovpnd_us_privkey" = {
|
|
||||||
sopsFile = ../../secrets/universal.yaml;
|
|
||||||
};
|
|
||||||
sops.secrets."wg_ovpnd_us-atl_privkey" = {
|
|
||||||
sopsFile = ../../secrets/universal.yaml;
|
|
||||||
};
|
|
||||||
sops.secrets."wg_ovpnd_us-mi_privkey" = {
|
|
||||||
sopsFile = ../../secrets/universal.yaml;
|
|
||||||
};
|
|
||||||
sops.secrets."wg_ovpnd_ukr_privkey" = {
|
|
||||||
sopsFile = ../../secrets/universal.yaml;
|
|
||||||
};
|
|
||||||
|
|
||||||
sops.secrets."snippets" = {
|
|
||||||
sopsFile = ../../secrets/universal/snippets.bin;
|
|
||||||
format = "binary";
|
|
||||||
owner = config.users.users.colin.name;
|
|
||||||
};
|
|
||||||
|
|
||||||
sops.secrets."bt/car" = {
|
|
||||||
sopsFile = ../../secrets/universal/bt/car.bin;
|
|
||||||
format = "binary";
|
|
||||||
};
|
|
||||||
sops.secrets."bt/earbuds" = {
|
|
||||||
sopsFile = ../../secrets/universal/bt/earbuds.bin;
|
|
||||||
format = "binary";
|
|
||||||
};
|
|
||||||
sops.secrets."bt/portable-speaker" = {
|
|
||||||
sopsFile = ../../secrets/universal/bt/portable-speaker.bin;
|
|
||||||
format = "binary";
|
|
||||||
};
|
|
||||||
|
|
||||||
sops.secrets."iwd/community-university.psk" = {
|
|
||||||
sopsFile = ../../secrets/universal/net/community-university.psk.bin;
|
|
||||||
format = "binary";
|
|
||||||
};
|
|
||||||
sops.secrets."iwd/friend-libertarian-dod.psk" = {
|
|
||||||
sopsFile = ../../secrets/universal/net/friend-libertarian-dod.psk.bin;
|
|
||||||
format = "binary";
|
|
||||||
};
|
|
||||||
sops.secrets."iwd/friend-rationalist-empathist.psk" = {
|
|
||||||
sopsFile = ../../secrets/universal/net/friend-rationalist-empathist.psk.bin;
|
|
||||||
format = "binary";
|
|
||||||
};
|
|
||||||
sops.secrets."iwd/home-bedroom.psk" = {
|
|
||||||
sopsFile = ../../secrets/universal/net/home-bedroom.psk.bin;
|
|
||||||
format = "binary";
|
|
||||||
};
|
|
||||||
sops.secrets."iwd/home-shared-24G.psk" = {
|
|
||||||
sopsFile = ../../secrets/universal/net/home-shared-24G.psk.bin;
|
|
||||||
format = "binary";
|
|
||||||
};
|
|
||||||
sops.secrets."iwd/home-shared.psk" = {
|
|
||||||
sopsFile = ../../secrets/universal/net/home-shared.psk.bin;
|
|
||||||
format = "binary";
|
|
||||||
};
|
|
||||||
sops.secrets."iwd/iphone" = {
|
|
||||||
sopsFile = ../../secrets/universal/net/iphone.psk.bin;
|
|
||||||
format = "binary";
|
|
||||||
};
|
|
||||||
sops.secrets."iwd/parents" = {
|
|
||||||
sopsFile = ../../secrets/universal/net/parents.psk.bin;
|
|
||||||
format = "binary";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@@ -1,24 +0,0 @@
|
|||||||
{ config, lib, sane-data, sane-lib, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
sane.ssh.pubkeys =
|
|
||||||
let
|
|
||||||
# path is a DNS-style path like [ "org" "uninsane" "root" ]
|
|
||||||
keyNameForPath = path:
|
|
||||||
let
|
|
||||||
rev = lib.reverseList path;
|
|
||||||
name = builtins.head rev;
|
|
||||||
host = lib.concatStringsSep "." (builtins.tail rev);
|
|
||||||
in
|
|
||||||
"${name}@${host}";
|
|
||||||
|
|
||||||
# [{ path :: [String], value :: String }] for the keys we want to install
|
|
||||||
globalKeys = sane-lib.flattenAttrs sane-data.keys;
|
|
||||||
localKeys = sane-lib.flattenAttrs sane-data.keys.org.uninsane.local;
|
|
||||||
in lib.mkMerge (builtins.map
|
|
||||||
({ path, value }: {
|
|
||||||
"${keyNameForPath path}" = value;
|
|
||||||
})
|
|
||||||
(globalKeys ++ localKeys)
|
|
||||||
);
|
|
||||||
}
|
|
@@ -1,132 +0,0 @@
|
|||||||
{ config, pkgs, lib, sane-lib, ... }:
|
|
||||||
|
|
||||||
# installer docs: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/installation-device.nix
|
|
||||||
with lib;
|
|
||||||
let
|
|
||||||
cfg = config.sane.users;
|
|
||||||
fs = sane-lib.fs;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options = {
|
|
||||||
sane.users.guest.enable = mkOption {
|
|
||||||
default = false;
|
|
||||||
type = types.bool;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
# Users are exactly these specified here;
|
|
||||||
# old ones will be deleted (from /etc/passwd, etc) upon upgrade.
|
|
||||||
users.mutableUsers = false;
|
|
||||||
|
|
||||||
# docs: https://nixpkgs-manual-sphinx-markedown-example.netlify.app/generated/options-db.xml.html#users-users
|
|
||||||
users.users.colin = {
|
|
||||||
# sets group to "users" (?)
|
|
||||||
isNormalUser = true;
|
|
||||||
home = "/home/colin";
|
|
||||||
createHome = true;
|
|
||||||
homeMode = "0700";
|
|
||||||
# i don't get exactly what this is, but nixos defaults to this non-deterministically
|
|
||||||
# in /var/lib/nixos/auto-subuid-map and i don't want that.
|
|
||||||
subUidRanges = [
|
|
||||||
{ startUid=100000; count=1; }
|
|
||||||
];
|
|
||||||
group = "users";
|
|
||||||
extraGroups = [
|
|
||||||
"wheel"
|
|
||||||
"nixbuild"
|
|
||||||
"networkmanager"
|
|
||||||
# phosh/mobile. XXX colin: unsure if necessary
|
|
||||||
"video"
|
|
||||||
"feedbackd"
|
|
||||||
"dialout" # required for modem access
|
|
||||||
];
|
|
||||||
|
|
||||||
# initial password is empty, in case anything goes wrong.
|
|
||||||
# if `colin-passwd` (a password hash) is successfully found/decrypted, that becomes the password at boot.
|
|
||||||
initialPassword = lib.mkDefault "";
|
|
||||||
passwordFile = lib.mkIf (config.sops.secrets ? "colin-passwd") config.sops.secrets.colin-passwd.path;
|
|
||||||
|
|
||||||
shell = pkgs.zsh;
|
|
||||||
|
|
||||||
# mount encrypted stuff at login
|
|
||||||
# some other nix pam users:
|
|
||||||
# - <https://github.com/g00pix/nixconf/blob/32c04f6fa843fed97639dd3f09e157668d3eea1f/profiles/sshfs.nix>
|
|
||||||
# - <https://github.com/lourkeur/distro/blob/11173454c6bb50f7ccab28cc2c757dca21446d1d/nixos/profiles/users/louis-full.nix>
|
|
||||||
# - <https://github.com/dnr/sample-nix-code/blob/03494480c1fae550c033aa54fd96aeb3827761c5/nixos/laptop.nix>
|
|
||||||
pamMount = let
|
|
||||||
priv = config.fileSystems."/home/colin/private";
|
|
||||||
in {
|
|
||||||
fstype = priv.fsType;
|
|
||||||
path = priv.device;
|
|
||||||
mountpoint = priv.mountPoint;
|
|
||||||
options = builtins.concatStringsSep "," priv.options;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
security.pam.mount.enable = true;
|
|
||||||
|
|
||||||
# ensure ~ perms are known to sane.fs module.
|
|
||||||
# TODO: this is generic enough to be lifted up into sane.fs itself.
|
|
||||||
sane.fs."/home/colin".dir.acl = {
|
|
||||||
user = "colin";
|
|
||||||
group = config.users.users.colin.group;
|
|
||||||
mode = config.users.users.colin.homeMode;
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.persist.home.plaintext = [
|
|
||||||
"archive"
|
|
||||||
"dev"
|
|
||||||
# TODO: records should be private
|
|
||||||
"records"
|
|
||||||
"ref"
|
|
||||||
"tmp"
|
|
||||||
"use"
|
|
||||||
"Music"
|
|
||||||
"Pictures"
|
|
||||||
"Videos"
|
|
||||||
|
|
||||||
".cargo"
|
|
||||||
".rustup"
|
|
||||||
];
|
|
||||||
|
|
||||||
# convenience
|
|
||||||
sane.fs."/home/colin/knowledge" = fs.wantedSymlinkTo "/home/colin/private/knowledge";
|
|
||||||
sane.fs."/home/colin/nixos" = fs.wantedSymlinkTo "/home/colin/dev/nixos";
|
|
||||||
sane.fs."/home/colin/Videos/servo" = fs.wantedSymlinkTo "/mnt/servo-media/Videos";
|
|
||||||
sane.fs."/home/colin/Videos/servo-incomplete" = fs.wantedSymlinkTo "/mnt/servo-media/incomplete";
|
|
||||||
sane.fs."/home/colin/Music/servo" = fs.wantedSymlinkTo "/mnt/servo-media/Music";
|
|
||||||
|
|
||||||
# used by password managers, e.g. unix `pass`
|
|
||||||
sane.fs."/home/colin/.password-store" = fs.wantedSymlinkTo "/home/colin/knowledge/secrets/accounts";
|
|
||||||
|
|
||||||
sane.persist.sys.plaintext = mkIf cfg.guest.enable [
|
|
||||||
# intentionally allow other users to write to the guest folder
|
|
||||||
{ directory = "/home/guest"; user = "guest"; group = "users"; mode = "0775"; }
|
|
||||||
];
|
|
||||||
users.users.guest = mkIf cfg.guest.enable {
|
|
||||||
isNormalUser = true;
|
|
||||||
home = "/home/guest";
|
|
||||||
subUidRanges = [
|
|
||||||
{ startUid=200000; count=1; }
|
|
||||||
];
|
|
||||||
group = "users";
|
|
||||||
initialPassword = lib.mkDefault "";
|
|
||||||
shell = pkgs.zsh;
|
|
||||||
openssh.authorizedKeys.keys = [
|
|
||||||
# TODO: insert pubkeys that should be allowed in
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
security.sudo = {
|
|
||||||
enable = true;
|
|
||||||
wheelNeedsPassword = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
services.openssh = {
|
|
||||||
enable = true;
|
|
||||||
permitRootLogin = "no";
|
|
||||||
passwordAuthentication = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,66 +0,0 @@
|
|||||||
{ config, lib, ... }:
|
|
||||||
|
|
||||||
# to add a new OVPN VPN:
|
|
||||||
# - generate a privkey `wg genkey`
|
|
||||||
# - add this key to `sops secrets/universal.yaml`
|
|
||||||
# - upload pubkey to OVPN.com
|
|
||||||
# - generate config @ OVPN.com
|
|
||||||
# - copy the Address, PublicKey, Endpoint from OVPN's config
|
|
||||||
# N.B.: maximum interface name in Linux is 15 characters.
|
|
||||||
let
|
|
||||||
def-ovpn = name: { endpoint, publicKey, address }: {
|
|
||||||
networking.wg-quick.interfaces."ovpnd-${name}" = {
|
|
||||||
inherit address;
|
|
||||||
privateKeyFile = config.sops.secrets."wg_ovpnd_${name}_privkey".path;
|
|
||||||
dns = [
|
|
||||||
"46.227.67.134"
|
|
||||||
"192.165.9.158"
|
|
||||||
];
|
|
||||||
peers = [
|
|
||||||
{
|
|
||||||
allowedIPs = [
|
|
||||||
"0.0.0.0/0"
|
|
||||||
"::/0"
|
|
||||||
];
|
|
||||||
inherit endpoint publicKey;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
# to start: `systemctl start wg-quick-ovpnd-${name}`
|
|
||||||
autostart = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
in lib.mkMerge [
|
|
||||||
(def-ovpn "us" {
|
|
||||||
endpoint = "vpn31.prd.losangeles.ovpn.com:9929";
|
|
||||||
publicKey = "VW6bEWMOlOneta1bf6YFE25N/oMGh1E1UFBCfyggd0k=";
|
|
||||||
address = [
|
|
||||||
"172.27.237.218/32"
|
|
||||||
"fd00:0000:1337:cafe:1111:1111:ab00:4c8f/128"
|
|
||||||
];
|
|
||||||
})
|
|
||||||
# NB: us-* share the same wg key and link-local addrs, but distinct public addresses
|
|
||||||
(def-ovpn "us-atl" {
|
|
||||||
endpoint = "vpn18.prd.atlanta.ovpn.com:9929";
|
|
||||||
publicKey = "Dpg/4v5s9u0YbrXukfrMpkA+XQqKIFpf8ZFgyw0IkE0=";
|
|
||||||
address = [
|
|
||||||
"172.21.182.178/32"
|
|
||||||
"fd00:0000:1337:cafe:1111:1111:cfcb:27e3/128"
|
|
||||||
];
|
|
||||||
})
|
|
||||||
(def-ovpn "us-mi" {
|
|
||||||
endpoint = "vpn34.prd.miami.ovpn.com:9929";
|
|
||||||
publicKey = "VtJz2irbu8mdkIQvzlsYhU+k9d55or9mx4A2a14t0V0=";
|
|
||||||
address = [
|
|
||||||
"172.21.182.178/32"
|
|
||||||
"fd00:0000:1337:cafe:1111:1111:cfcb:27e3/128"
|
|
||||||
];
|
|
||||||
})
|
|
||||||
(def-ovpn "ukr" {
|
|
||||||
endpoint = "vpn96.prd.kyiv.ovpn.com:9929";
|
|
||||||
publicKey = "CjZcXDxaaKpW8b5As1EcNbI6+42A6BjWahwXDCwfVFg=";
|
|
||||||
address = [
|
|
||||||
"172.18.180.159/32"
|
|
||||||
"fd00:0000:1337:cafe:1111:1111:ec5c:add3/128"
|
|
||||||
];
|
|
||||||
})
|
|
||||||
]
|
|
@@ -1,60 +0,0 @@
|
|||||||
{ config, pkgs, ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./fs.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
# sane.packages.enableDevPkgs = true;
|
|
||||||
|
|
||||||
sane.gui.sway.enable = true;
|
|
||||||
sane.services.duplicity.enable = true;
|
|
||||||
sane.services.nixserve.enable = true;
|
|
||||||
sane.services.nixserve.sopsFile = ../../secrets/desko.yaml;
|
|
||||||
sane.persist.enable = true;
|
|
||||||
|
|
||||||
boot.loader.efi.canTouchEfiVariables = false;
|
|
||||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
|
||||||
|
|
||||||
# needed to use libimobiledevice/ifuse, for iphone sync
|
|
||||||
services.usbmuxd.enable = true;
|
|
||||||
|
|
||||||
sops.secrets.colin-passwd = {
|
|
||||||
sopsFile = ../../secrets/desko.yaml;
|
|
||||||
neededForUsers = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# don't enable wifi by default: it messes with connectivity.
|
|
||||||
systemd.services.iwd.enable = false;
|
|
||||||
|
|
||||||
# default config: https://man.archlinux.org/man/snapper-configs.5
|
|
||||||
# defaults to something like:
|
|
||||||
# - hourly snapshots
|
|
||||||
# - auto cleanup; keep the last 10 hourlies, last 10 daylies, last 10 monthlys.
|
|
||||||
services.snapper.configs.nix = {
|
|
||||||
# TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
|
||||||
# but that also requires setting up the persist dir as a subvol
|
|
||||||
subvolume = "/nix";
|
|
||||||
# TODO: ALLOW_USERS doesn't seem to work. still need `sudo snapper -c nix list`
|
|
||||||
extraConfig = ''
|
|
||||||
ALLOW_USERS = "colin";
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
sops.secrets.duplicity_passphrase = {
|
|
||||||
sopsFile = ../../secrets/desko.yaml;
|
|
||||||
};
|
|
||||||
|
|
||||||
programs.steam = {
|
|
||||||
enable = true;
|
|
||||||
# not sure if needed: stole this whole snippet from the wiki
|
|
||||||
remotePlay.openFirewall = true; # Open ports in the firewall for Steam Remote Play
|
|
||||||
dedicatedServer.openFirewall = true; # Open ports in the firewall for Source Dedicated Server
|
|
||||||
};
|
|
||||||
sane.persist.home.plaintext = [
|
|
||||||
".steam"
|
|
||||||
".local/share/Steam"
|
|
||||||
];
|
|
||||||
|
|
||||||
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
|
|
||||||
system.stateVersion = "21.05";
|
|
||||||
}
|
|
@@ -1,31 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
sane.persist.root-on-tmpfs = true;
|
|
||||||
# we need a /tmp for building large nix things.
|
|
||||||
# a cross-compiled kernel, particularly, will easily use 30+GB of tmp
|
|
||||||
fileSystems."/tmp" = {
|
|
||||||
device = "none";
|
|
||||||
fsType = "tmpfs";
|
|
||||||
options = [
|
|
||||||
"mode=777"
|
|
||||||
"size=64G"
|
|
||||||
"defaults"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
fileSystems."/nix" = {
|
|
||||||
# device = "/dev/disk/by-uuid/985a0a32-da52-4043-9df7-615adec2e4ff";
|
|
||||||
device = "/dev/disk/by-uuid/0ab0770b-7734-4167-88d9-6e4e20bb2a56";
|
|
||||||
fsType = "btrfs";
|
|
||||||
options = [
|
|
||||||
"compress=zstd"
|
|
||||||
"defaults"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems."/boot" = {
|
|
||||||
# device = "/dev/disk/by-uuid/CAA7-E7D2";
|
|
||||||
device = "/dev/disk/by-uuid/41B6-BAEF";
|
|
||||||
fsType = "vfat";
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,23 +0,0 @@
|
|||||||
# trampoline from flake.nix into the specific host definition, while doing a tiny bit of common setup
|
|
||||||
|
|
||||||
{ hostName, localSystem }:
|
|
||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./${hostName}
|
|
||||||
./common
|
|
||||||
];
|
|
||||||
|
|
||||||
networking.hostName = hostName;
|
|
||||||
|
|
||||||
nixpkgs.overlays = [
|
|
||||||
(next: prev: {
|
|
||||||
# for local != target we by default just emulate the target while building.
|
|
||||||
# provide a `pkgs.cross.<pkg>` alias that consumers can use instead of `pkgs.<foo>`
|
|
||||||
# to explicitly opt into non-emulated cross compilation for any specific package.
|
|
||||||
# this is most beneficial for large packages with few pre-requisites -- like Linux.
|
|
||||||
cross = next.crossFrom."${localSystem}";
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
|
@@ -1,36 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./fs.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
# sane.packages.enableDevPkgs = true;
|
|
||||||
|
|
||||||
# sane.users.guest.enable = true;
|
|
||||||
sane.gui.sway.enable = true;
|
|
||||||
sane.persist.enable = true;
|
|
||||||
sane.nixcache.enable = true;
|
|
||||||
boot.loader.efi.canTouchEfiVariables = false;
|
|
||||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
|
||||||
|
|
||||||
sops.secrets.colin-passwd = {
|
|
||||||
sopsFile = ../../secrets/lappy.yaml;
|
|
||||||
neededForUsers = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# default config: https://man.archlinux.org/man/snapper-configs.5
|
|
||||||
# defaults to something like:
|
|
||||||
# - hourly snapshots
|
|
||||||
# - auto cleanup; keep the last 10 hourlies, last 10 daylies, last 10 monthlys.
|
|
||||||
services.snapper.configs.nix = {
|
|
||||||
# TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
|
||||||
# but that also requires setting up the persist dir as a subvol
|
|
||||||
subvolume = "/nix";
|
|
||||||
};
|
|
||||||
|
|
||||||
# TODO: only here for debugging
|
|
||||||
# services.ipfs.enable = true;
|
|
||||||
|
|
||||||
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
|
|
||||||
system.stateVersion = "21.05";
|
|
||||||
}
|
|
@@ -1,48 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
sane.persist.root-on-tmpfs = true;
|
|
||||||
# we need a /tmp of default size (half RAM) for building large nix things
|
|
||||||
fileSystems."/tmp" = {
|
|
||||||
device = "none";
|
|
||||||
fsType = "tmpfs";
|
|
||||||
options = [
|
|
||||||
"mode=777"
|
|
||||||
"defaults"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems."/nix" = {
|
|
||||||
device = "/dev/disk/by-uuid/75230e56-2c69-4e41-b03e-68475f119980";
|
|
||||||
fsType = "btrfs";
|
|
||||||
options = [
|
|
||||||
"compress=zstd"
|
|
||||||
"defaults"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems."/boot" = {
|
|
||||||
device = "/dev/disk/by-uuid/BD79-D6BB";
|
|
||||||
fsType = "vfat";
|
|
||||||
};
|
|
||||||
|
|
||||||
# fileSystems."/nix" = {
|
|
||||||
# device = "/dev/disk/by-uuid/5a7fa69c-9394-8144-a74c-6726048b129f";
|
|
||||||
# fsType = "btrfs";
|
|
||||||
# };
|
|
||||||
|
|
||||||
# fileSystems."/boot" = {
|
|
||||||
# device = "/dev/disk/by-uuid/4302-1685";
|
|
||||||
# fsType = "vfat";
|
|
||||||
# };
|
|
||||||
|
|
||||||
# fileSystems."/" = {
|
|
||||||
# device = "none";
|
|
||||||
# fsType = "tmpfs";
|
|
||||||
# options = [
|
|
||||||
# "mode=755"
|
|
||||||
# "size=1G"
|
|
||||||
# "defaults"
|
|
||||||
# ];
|
|
||||||
# };
|
|
||||||
}
|
|
@@ -1,89 +0,0 @@
|
|||||||
{ config, pkgs, lib, ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./firmware.nix
|
|
||||||
./fs.nix
|
|
||||||
./kernel.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
# cross-compiled documentation is *slow*.
|
|
||||||
# no obvious way to natively compile docs (2022/09/29).
|
|
||||||
# entrypoint is nixos/modules/misc/documentation.nix
|
|
||||||
# doc building happens in nixos/doc/manual/default.nix
|
|
||||||
# TODO: we could *maybe* inject pkgs.buildPackages.xyz = cross.buildPackages.xyz?
|
|
||||||
documentation.nixos.enable = false;
|
|
||||||
|
|
||||||
# XXX colin: phosh doesn't work well with passwordless login,
|
|
||||||
# so set this more reliable default password should anything go wrong
|
|
||||||
users.users.colin.initialPassword = "147147";
|
|
||||||
services.getty.autologinUser = "root"; # allows for emergency maintenance?
|
|
||||||
|
|
||||||
sops.secrets.colin-passwd = {
|
|
||||||
sopsFile = ../../secrets/moby.yaml;
|
|
||||||
neededForUsers = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# usability compromises
|
|
||||||
sane.web-browser.persistCache = "private";
|
|
||||||
sane.web-browser.persistData = "private";
|
|
||||||
sane.persist.home.plaintext = [
|
|
||||||
".config/pulse" # persist pulseaudio volume
|
|
||||||
];
|
|
||||||
|
|
||||||
# sane.packages.enableGuiPkgs = false; # XXX faster builds/imaging for debugging
|
|
||||||
sane.packages.extraUserPkgs = [
|
|
||||||
pkgs.plasma5Packages.konsole # terminal
|
|
||||||
];
|
|
||||||
|
|
||||||
sane.nixcache.enable = true;
|
|
||||||
sane.persist.enable = true;
|
|
||||||
sane.gui.phosh.enable = true;
|
|
||||||
|
|
||||||
boot.loader.efi.canTouchEfiVariables = false;
|
|
||||||
# /boot space is at a premium. default was 20.
|
|
||||||
# even 10 can be too much
|
|
||||||
# TODO: compress moby kernels!
|
|
||||||
boot.loader.generic-extlinux-compatible.configurationLimit = 8;
|
|
||||||
# mobile.bootloader.enable = false;
|
|
||||||
# mobile.boot.stage-1.enable = false;
|
|
||||||
# boot.initrd.systemd.enable = false;
|
|
||||||
# boot.initrd.services.swraid.enable = false; # attempt to fix dm_mod stuff
|
|
||||||
# disable proximity sensor.
|
|
||||||
# the filtering/calibration is bad that it causes the screen to go fully dark at times.
|
|
||||||
boot.blacklistedKernelModules = [ "stk3310" ];
|
|
||||||
|
|
||||||
# without this some GUI apps fail: `DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory`
|
|
||||||
# this is because they can't allocate enough video ram.
|
|
||||||
# the default CMA seems to be 32M. we could probably get by with as little as 64M, and safely with 128M.
|
|
||||||
# `cat /proc/meminfo` to see CmaTotal/CmaFree if interested in tuning this.
|
|
||||||
boot.kernelParams = [ "cma=256M" ];
|
|
||||||
|
|
||||||
# mobile-nixos' /lib/firmware includes:
|
|
||||||
# rtl_bt (bluetooth)
|
|
||||||
# anx7688-fw.bin (USB-C -> HDMI bridge)
|
|
||||||
# ov5640_af.bin (camera module)
|
|
||||||
# hardware.firmware = [ config.mobile.device.firmware ];
|
|
||||||
hardware.firmware = [ pkgs.rtl8723cs-firmware ];
|
|
||||||
|
|
||||||
system.stateVersion = "21.11";
|
|
||||||
|
|
||||||
# defined: https://www.freedesktop.org/software/systemd/man/machine-info.html
|
|
||||||
# XXX colin: not sure which, if any, software makes use of this
|
|
||||||
environment.etc."machine-info".text = ''
|
|
||||||
CHASSIS="handset"
|
|
||||||
'';
|
|
||||||
|
|
||||||
# enable rotation sensor
|
|
||||||
hardware.sensor.iio.enable = true;
|
|
||||||
|
|
||||||
# from https://gitlab.manjaro.org/manjaro-arm/packages/community/phosh/alsa-ucm-pinephone
|
|
||||||
# mobile-nixos does this same thing, with *slightly different settings*.
|
|
||||||
# i trust manjaro more because the guy maintaining that is actively trying to upstream into alsa-ucm-conf.
|
|
||||||
# an alternative may be to build a custom alsa with the PinePhone config patch applied:
|
|
||||||
# - <https://github.com/alsa-project/alsa-ucm-conf/pull/134>
|
|
||||||
# that would make this be not device-specific
|
|
||||||
environment.variables.ALSA_CONFIG_UCM2 = "${./ucm2}";
|
|
||||||
systemd.services.pulseaudio.environment.ALSA_CONFIG_UCM2 = "${./ucm2}";
|
|
||||||
|
|
||||||
hardware.opengl.driSupport = true;
|
|
||||||
}
|
|
@@ -1,12 +0,0 @@
|
|||||||
{ config, pkgs, ... }:
|
|
||||||
{
|
|
||||||
# we need space in the GPT header to place tow-boot.
|
|
||||||
# only actually need 1 MB, but better to over-allocate than under-allocate
|
|
||||||
sane.image.extraGPTPadding = 16 * 1024 * 1024;
|
|
||||||
sane.image.firstPartGap = 0;
|
|
||||||
system.build.img = pkgs.runCommand "nixos_full-disk-image.img" {} ''
|
|
||||||
cp -v ${config.system.build.img-without-firmware}/nixos.img $out
|
|
||||||
chmod +w $out
|
|
||||||
dd if=${pkgs.tow-boot-pinephone}/Tow-Boot.noenv.bin of=$out bs=1024 seek=8 conv=notrunc
|
|
||||||
'';
|
|
||||||
}
|
|
@@ -1,18 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
sane.persist.root-on-tmpfs = true;
|
|
||||||
fileSystems."/nix" = {
|
|
||||||
device = "/dev/disk/by-uuid/1f1271f8-53ce-4081-8a29-60a4a6b5d6f9";
|
|
||||||
fsType = "btrfs";
|
|
||||||
options = [
|
|
||||||
"compress=zstd"
|
|
||||||
"defaults"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems."/boot" = {
|
|
||||||
device = "/dev/disk/by-uuid/0299-F1E5";
|
|
||||||
fsType = "vfat";
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,143 +0,0 @@
|
|||||||
{ lib, pkgs, ... }:
|
|
||||||
let
|
|
||||||
# use the last commit on the 5.18 branch (5.18.14)
|
|
||||||
# manjaro's changes between kernel patch versions tend to be minimal if any.
|
|
||||||
manjaroBase = "https://gitlab.manjaro.org/manjaro-arm/packages/core/linux/-/raw/25bd828cd47b1c6e09fcbcf394a649b89d2876dd";
|
|
||||||
manjaroPatch = name: sha256: {
|
|
||||||
inherit name;
|
|
||||||
patch = pkgs.fetchpatch {
|
|
||||||
inherit name;
|
|
||||||
url = "${manjaroBase}/${name}?inline=false";
|
|
||||||
inherit sha256;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# the idea for patching off Manjaro's kernel comes from jakewaksbaum:
|
|
||||||
# - https://git.sr.ht/~jakewaksbaum/pi/tree/af20aae5653545d6e67a459b59ee3e1ca8a680b0/item/kernel/default.nix
|
|
||||||
# - he later abandoned this, i think because he's using the Pinephone Pro which received mainline support.
|
|
||||||
manjaroPatches = [
|
|
||||||
(manjaroPatch
|
|
||||||
"1001-arm64-dts-allwinner-add-hdmi-sound-to-pine-devices.patch"
|
|
||||||
"sha256-DApd791A+AxB28Ven/MVAyuyVphdo8KQDx8O7oxVPnc="
|
|
||||||
)
|
|
||||||
# these patches below are critical to enable wifi (RTL8723CS)
|
|
||||||
# - the alternative is a wholly forked kernel by megi/megous:
|
|
||||||
# - https://xnux.eu/howtos/build-pinephone-kernel.html#toc-how-to-build-megi-s-pinehpone-kernel
|
|
||||||
# - i don't know if these patches are based on megi's or original
|
|
||||||
(manjaroPatch
|
|
||||||
"2001-Bluetooth-Add-new-quirk-for-broken-local-ext-features.patch"
|
|
||||||
"sha256-CExhJuUWivegxPdnzKINEsKrMFx/m/1kOZFmlZ2SEOc="
|
|
||||||
)
|
|
||||||
(manjaroPatch
|
|
||||||
"2002-Bluetooth-btrtl-add-support-for-the-RTL8723CS.patch"
|
|
||||||
"sha256-dDdvOphTcP/Aog93HyH+L9m55laTgtjndPSE4/rnzUA="
|
|
||||||
)
|
|
||||||
(manjaroPatch
|
|
||||||
"2004-arm64-dts-allwinner-enable-bluetooth-pinetab-pinepho.patch"
|
|
||||||
"sha256-o43P3WzXyHK1PF+Kdter4asuyGAEKO6wf5ixcco2kCQ="
|
|
||||||
)
|
|
||||||
# XXX: this one has a Makefile, which hardcodes /sbin/depmod:
|
|
||||||
# - drivers/staging/rtl8723cs/Makefile
|
|
||||||
# - not sure if this is problematic?
|
|
||||||
(manjaroPatch
|
|
||||||
"2005-staging-add-rtl8723cs-driver.patch"
|
|
||||||
"sha256-6ywm3dQQ5JYl60CLKarxlSUukwi4QzqctCj3tVgzFbo="
|
|
||||||
)
|
|
||||||
];
|
|
||||||
|
|
||||||
# pinephone uses the linux dtb at arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
|
||||||
# - this includes sun50i-a64.dtsi
|
|
||||||
# - and sun50i-a64-cpu-opp.dtsi
|
|
||||||
# - no need to touch the allwinner-h6 stuff: that's the SBC pine product
|
|
||||||
# - i think it's safe to ignore sun9i stuff, but i don't know what it is
|
|
||||||
kernelConfig = with lib.kernel; {
|
|
||||||
# NB: nix adds the CONFIG_ prefix to each of these.
|
|
||||||
# if you add the prefix yourself nix will IGNORE YOUR CONFIG.
|
|
||||||
RTL8723CS = module;
|
|
||||||
BT_HCIUART_3WIRE = yes;
|
|
||||||
BT_HCIUART_RTL = yes;
|
|
||||||
RTL8XXXU_UNTESTED = yes;
|
|
||||||
BT_BNEP_MC_FILTER = yes;
|
|
||||||
BT_BNEP_PROTO_FILTER = yes;
|
|
||||||
BT_HS = yes;
|
|
||||||
BT_LE = yes;
|
|
||||||
# relevant configs inherited from nixos defaults (or above additions):
|
|
||||||
# CONFIG_BT=m
|
|
||||||
# CONFIG_BT_BREDR=y
|
|
||||||
# CONFIG_BT_RFCOMM=m
|
|
||||||
# CONFIG_BT_RFCOMM_TTY=y
|
|
||||||
# CONFIG_BT_BNEP=m
|
|
||||||
# CONFIG_BT_HIDP=m
|
|
||||||
# CONFIG_BT_RTL=m
|
|
||||||
# CONFIG_BT_HCIBTUSB=m
|
|
||||||
# CONFIG_BT_HCIBTUSB_BCM=y
|
|
||||||
# CONFIG_BT_HCIBTUSB_RTL=y
|
|
||||||
# CONFIG_BT_HCIUART=m
|
|
||||||
# CONFIG_BT_HCIUART_SERDEV=y
|
|
||||||
# CONFIG_BT_HCIUART_H4=y
|
|
||||||
# CONFIG_BT_HCIUART_LL=y
|
|
||||||
# CONFIG_RTL_CARDS=m
|
|
||||||
# CONFIG_RTLWIFI=m
|
|
||||||
# CONFIG_RTLWIFI_PCI=m
|
|
||||||
# CONFIG_RTLWIFI_USB=m
|
|
||||||
# CONFIG_RTLWIFI_DEBUG=y
|
|
||||||
# CONFIG_RTL8723_COMMON=m
|
|
||||||
# CONFIG_RTLBTCOEXIST=m
|
|
||||||
# CONFIG_RTL8XXXU=m
|
|
||||||
# CONFIG_RTLLIB=m
|
|
||||||
# consider adding (from mobile-nixos):
|
|
||||||
# maybe: CONFIG_BT_HCIUART_3WIRE=y
|
|
||||||
# maybe: CONFIG_BT_HCIUART_RTL=y
|
|
||||||
# maybe: CONFIG_RTL8XXXU_UNTESTED=y
|
|
||||||
# consider adding (from manjaro):
|
|
||||||
# CONFIG_BT_6LOWPAN=m (not listed as option in nixos kernel)
|
|
||||||
# these are referenced in the rtl8723 source, but not known to config (and not in mobile-nixos config
|
|
||||||
# maybe: CONFIG_RTL_ODM_WLAN_DRIVER
|
|
||||||
# maybe: CONFIG_RTL_TRIBAND_SUPPORT
|
|
||||||
# maybe: CONFIG_SDIO_HCI
|
|
||||||
# maybe: CONFIG_USB_HCI
|
|
||||||
};
|
|
||||||
|
|
||||||
# create a kernelPatch which overrides nixos' defconfig with extra options
|
|
||||||
patchDefconfig = config: {
|
|
||||||
# defconfig options. this method comes from here:
|
|
||||||
# - https://discourse.nixos.org/t/the-correct-way-to-override-the-latest-kernel-config/533/9
|
|
||||||
name = "sane-moby-defconfig";
|
|
||||||
patch = null;
|
|
||||||
extraStructuredConfig = config;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
# use Megi's kernel:
|
|
||||||
# even with the Manjaro patches, stock 5.18 has a few issues on Pinephone:
|
|
||||||
# - no battery charging
|
|
||||||
# - phone rotation sensor is off by 90 degrees
|
|
||||||
# - ambient light sensor causes screen brightness to be shakey
|
|
||||||
# - phosh greeter may not appear after wake from sleep
|
|
||||||
boot.kernelPackages = pkgs.cross.linuxPackagesFor pkgs.cross.linux-megous;
|
|
||||||
|
|
||||||
boot.kernelPatches = [
|
|
||||||
(patchDefconfig (kernelConfig //
|
|
||||||
(with lib.kernel; {
|
|
||||||
# disabling the sun5i_eink driver avoids this compilation error:
|
|
||||||
# CC [M] drivers/video/fbdev/sun5i-eink-neon.o
|
|
||||||
# aarch64-unknown-linux-gnu-gcc: error: unrecognized command line option '-mfloat-abi=softfp'
|
|
||||||
# aarch64-unknown-linux-gnu-gcc: error: unrecognized command line option '-mfpu=neon'
|
|
||||||
# make[3]: *** [../scripts/Makefile.build:289: drivers/video/fbdev/sun5i-eink-neon.o] Error 1
|
|
||||||
FB_SUN5I_EINK = no;
|
|
||||||
})
|
|
||||||
))
|
|
||||||
];
|
|
||||||
|
|
||||||
# alternatively, use nixos' kernel and add the stuff we want:
|
|
||||||
# # cross-compilation optimization:
|
|
||||||
# boot.kernelPackages =
|
|
||||||
# let p = (import nixpkgs { localSystem = "x86_64-linux"; });
|
|
||||||
# in p.pkgsCross.aarch64-multiplatform.linuxPackages_5_18;
|
|
||||||
# # non-cross:
|
|
||||||
# # boot.kernelPackages = pkgs.linuxPackages_5_18;
|
|
||||||
|
|
||||||
# boot.kernelPatches = manjaroPatches ++ [
|
|
||||||
# (patchDefconfig kernelConfig)
|
|
||||||
# ];
|
|
||||||
}
|
|
@@ -1,148 +0,0 @@
|
|||||||
SectionVerb {
|
|
||||||
EnableSequence [
|
|
||||||
cset "name='Headphone Playback Switch' off"
|
|
||||||
cset "name='Headphone Source Playback Route' DAC"
|
|
||||||
cset "name='Line In Playback Switch' off"
|
|
||||||
cset "name='Line Out Playback Switch' off"
|
|
||||||
cset "name='Line Out Source Playback Route' Mono Differential"
|
|
||||||
cset "name='Mic1 Playback Switch' off"
|
|
||||||
cset "name='Mic2 Playback Switch' off"
|
|
||||||
cset "name='AIF1 DA0 Playback Volume' 160"
|
|
||||||
cset "name='AIF3 ADC Source Capture Route' None"
|
|
||||||
cset "name='AIF2 DAC Source Playback Route' AIF2"
|
|
||||||
cset "name='DAC Playback Switch' on"
|
|
||||||
cset "name='DAC Playback Volume' 160"
|
|
||||||
cset "name='ADC Digital DAC Playback Switch' off"
|
|
||||||
cset "name='AIF1 Slot 0 Digital DAC Playback Switch' on"
|
|
||||||
cset "name='AIF2 Digital DAC Playback Switch' off"
|
|
||||||
cset "name='DAC Reversed Playback Switch' off"
|
|
||||||
cset "name='Earpiece Playback Switch' off"
|
|
||||||
cset "name='Earpiece Source Playback Route' DACL"
|
|
||||||
|
|
||||||
cset "name='Line In Capture Switch' off"
|
|
||||||
cset "name='Mic1 Capture Switch' off"
|
|
||||||
cset "name='Mic1 Boost Volume' 7"
|
|
||||||
cset "name='Mic2 Capture Switch' off"
|
|
||||||
cset "name='Mic2 Boost Volume' 7"
|
|
||||||
cset "name='Mixer Capture Switch' off"
|
|
||||||
cset "name='Mixer Reversed Capture Switch' off"
|
|
||||||
cset "name='ADC Capture Volume' 160"
|
|
||||||
cset "name='ADC Gain Capture Volume' 7"
|
|
||||||
cset "name='AIF1 AD0 Capture Volume' 160"
|
|
||||||
cset "name='AIF1 Data Digital ADC Capture Switch' on"
|
|
||||||
cset "name='AIF2 ADC Mixer ADC Capture Switch' off"
|
|
||||||
cset "name='AIF2 ADC Mixer AIF1 DA0 Capture Switch' off"
|
|
||||||
cset "name='AIF2 ADC Mixer AIF2 DAC Rev Capture Switch' off"
|
|
||||||
cset "name='AIF2 ADC Mixer AIF1 DA0 Capture Switch' off"
|
|
||||||
cset "name='AIF2 ADC Mixer AIF1 DA0 Capture Switch' off"
|
|
||||||
]
|
|
||||||
|
|
||||||
DisableSequence [
|
|
||||||
]
|
|
||||||
|
|
||||||
Value {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SectionDevice."Speaker" {
|
|
||||||
Comment "Internal speaker"
|
|
||||||
EnableSequence [
|
|
||||||
cset "name='AIF1 DA0 Stereo Playback Route' Mix Mono"
|
|
||||||
cset "name='Line Out Playback Switch' on"
|
|
||||||
cset "name='Line Out Playback Volume' 100%"
|
|
||||||
]
|
|
||||||
|
|
||||||
DisableSequence [
|
|
||||||
cset "name='Line Out Playback Switch' off"
|
|
||||||
]
|
|
||||||
|
|
||||||
Value {
|
|
||||||
PlaybackVolume "Line Out Playback Volume"
|
|
||||||
PlaybackSwitch "Line Out Playback Switch"
|
|
||||||
PlaybackChannels 2
|
|
||||||
PlaybackPriority 300
|
|
||||||
PlaybackPCM "hw:${CardId},0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SectionDevice."Earpiece" {
|
|
||||||
Comment "Internal Earpiece"
|
|
||||||
EnableSequence [
|
|
||||||
cset "name='AIF1 DA0 Stereo Playback Route' Mix Mono"
|
|
||||||
cset "name='Earpiece Playback Switch' on"
|
|
||||||
cset "name='Earpiece Playback Volume' 100%"
|
|
||||||
]
|
|
||||||
|
|
||||||
DisableSequence [
|
|
||||||
cset "name='Earpiece Playback Switch' off"
|
|
||||||
]
|
|
||||||
|
|
||||||
Value {
|
|
||||||
PlaybackVolume "Earpiece Playback Volume"
|
|
||||||
PlaybackSwitch "Earpiece Playback Switch"
|
|
||||||
PlaybackChannels 2
|
|
||||||
PlaybackPriority 200
|
|
||||||
PlaybackPCM "hw:${CardId},0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SectionDevice."Mic" {
|
|
||||||
Comment "Internal Microphone"
|
|
||||||
ConflictingDevice [
|
|
||||||
"Headset"
|
|
||||||
]
|
|
||||||
EnableSequence [
|
|
||||||
cset "name='Mic1 Capture Switch' on"
|
|
||||||
]
|
|
||||||
DisableSequence [
|
|
||||||
cset "name='Mic1 Capture Switch' off"
|
|
||||||
]
|
|
||||||
Value {
|
|
||||||
CapturePriority 100
|
|
||||||
CapturePCM "hw:${CardId},0"
|
|
||||||
CaptureChannels 2
|
|
||||||
CaptureMixerElem "ADC"
|
|
||||||
CaptureVolume "ADC Capture Volume"
|
|
||||||
CaptureSwitch "Mic1 Capture Switch"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SectionDevice."Headset" {
|
|
||||||
Comment "Headset Microphone"
|
|
||||||
ConflictingDevice [
|
|
||||||
"Mic"
|
|
||||||
]
|
|
||||||
EnableSequence [
|
|
||||||
cset "name='Mic2 Capture Switch' on"
|
|
||||||
]
|
|
||||||
DisableSequence [
|
|
||||||
cset "name='Mic2 Capture Switch' off"
|
|
||||||
]
|
|
||||||
Value {
|
|
||||||
CapturePriority 500
|
|
||||||
CapturePCM "hw:${CardId},0"
|
|
||||||
CaptureChannels 2
|
|
||||||
CaptureMixerElem "ADC"
|
|
||||||
CaptureVolume "ADC Capture Volume"
|
|
||||||
CaptureSwitch "Mic2 Capture Switch"
|
|
||||||
JackControl "Headset Microphone Jack"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SectionDevice."Headphones" {
|
|
||||||
Comment "Headphones"
|
|
||||||
EnableSequence [
|
|
||||||
cset "name='AIF1 DA0 Stereo Playback Route' Stereo"
|
|
||||||
cset "name='Headphone Playback Switch' on"
|
|
||||||
cset "name='Headphone Playback Volume' 70%"
|
|
||||||
]
|
|
||||||
|
|
||||||
DisableSequence [
|
|
||||||
cset "name='Headphone Playback Switch' off"
|
|
||||||
]
|
|
||||||
|
|
||||||
Value {
|
|
||||||
PlaybackVolume "Headphone Playback Volume"
|
|
||||||
PlaybackSwitch "Headphone Playback Switch"
|
|
||||||
PlaybackChannels 2
|
|
||||||
PlaybackPriority 500
|
|
||||||
PlaybackPCM "hw:${CardId},0"
|
|
||||||
JackControl "Headphone Jack"
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
Syntax 2
|
|
||||||
|
|
||||||
SectionUseCase."HiFi" {
|
|
||||||
File "HiFi.conf"
|
|
||||||
Comment "Default"
|
|
||||||
}
|
|
||||||
|
|
||||||
SectionUseCase."Voice Call" {
|
|
||||||
File "VoiceCall.conf"
|
|
||||||
Comment "Phone call"
|
|
||||||
}
|
|
@@ -1,153 +0,0 @@
|
|||||||
SectionVerb {
|
|
||||||
EnableSequence [
|
|
||||||
cset "name='Headphone Playback Switch' off"
|
|
||||||
cset "name='Headphone Source Playback Route' DAC"
|
|
||||||
cset "name='Line In Playback Switch' off"
|
|
||||||
cset "name='Line Out Playback Switch' off"
|
|
||||||
cset "name='Line Out Source Playback Route' Mono Differential"
|
|
||||||
cset "name='Mic1 Playback Switch' off"
|
|
||||||
cset "name='Mic2 Playback Switch' off"
|
|
||||||
cset "name='AIF1 DA0 Playback Volume' 160"
|
|
||||||
cset "name='AIF2 DAC Playback Volume' 160"
|
|
||||||
cset "name='AIF3 ADC Source Capture Route' None"
|
|
||||||
cset "name='AIF2 DAC Source Playback Route' AIF2"
|
|
||||||
cset "name='DAC Playback Switch' on"
|
|
||||||
cset "name='DAC Playback Volume' 160"
|
|
||||||
cset "name='ADC Digital DAC Playback Switch' off"
|
|
||||||
cset "name='AIF1 Slot 0 Digital DAC Playback Switch' on"
|
|
||||||
cset "name='AIF2 Digital DAC Playback Switch' on"
|
|
||||||
cset "name='DAC Reversed Playback Switch' off"
|
|
||||||
cset "name='Earpiece Playback Switch' off"
|
|
||||||
cset "name='Earpiece Source Playback Route' DACL"
|
|
||||||
|
|
||||||
cset "name='Line In Capture Switch' off"
|
|
||||||
cset "name='Mic1 Capture Switch' off"
|
|
||||||
cset "name='Mic1 Boost Volume' 0"
|
|
||||||
cset "name='Mic1 Playback Volume' 7"
|
|
||||||
cset "name='Mic2 Capture Switch' off"
|
|
||||||
cset "name='Mic2 Boost Volume' 0"
|
|
||||||
cset "name='Mic2 Playback Volume' 7"
|
|
||||||
cset "name='Mixer Capture Switch' off"
|
|
||||||
cset "name='Mixer Reversed Capture Switch' off"
|
|
||||||
cset "name='ADC Capture Volume' 160"
|
|
||||||
cset "name='ADC Gain Capture Volume' 7"
|
|
||||||
cset "name='AIF1 AD0 Capture Volume' 160"
|
|
||||||
cset "name='AIF1 Data Digital ADC Capture Switch' on"
|
|
||||||
cset "name='AIF2 ADC Capture Volume' 160"
|
|
||||||
cset "name='AIF2 ADC Mixer ADC Capture Switch' on"
|
|
||||||
cset "name='AIF2 ADC Mixer AIF1 DA0 Capture Switch' off"
|
|
||||||
cset "name='AIF2 ADC Mixer AIF2 DAC Rev Capture Switch' off"
|
|
||||||
cset "name='AIF2 ADC Mixer AIF1 DA0 Capture Switch' off"
|
|
||||||
cset "name='AIF2 ADC Mixer AIF1 DA0 Capture Switch' off"
|
|
||||||
]
|
|
||||||
|
|
||||||
DisableSequence [
|
|
||||||
]
|
|
||||||
|
|
||||||
Value {
|
|
||||||
PlaybackRate 8000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SectionDevice."Speaker" {
|
|
||||||
Comment "Internal speaker"
|
|
||||||
EnableSequence [
|
|
||||||
cset "name='AIF1 DA0 Stereo Playback Route' Mix Mono"
|
|
||||||
cset "name='Line Out Playback Switch' on"
|
|
||||||
cset "name='Line Out Playback Volume' 100%"
|
|
||||||
]
|
|
||||||
|
|
||||||
DisableSequence [
|
|
||||||
cset "name='Line Out Playback Switch' off"
|
|
||||||
]
|
|
||||||
|
|
||||||
Value {
|
|
||||||
PlaybackVolume "Line Out Playback Volume"
|
|
||||||
PlaybackSwitch "Line Out Playback Switch"
|
|
||||||
PlaybackChannels 2
|
|
||||||
PlaybackPriority 300
|
|
||||||
PlaybackPCM "hw:${CardId},0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SectionDevice."Earpiece" {
|
|
||||||
Comment "Internal Earpiece"
|
|
||||||
EnableSequence [
|
|
||||||
cset "name='AIF1 DA0 Stereo Playback Route' Mix Mono"
|
|
||||||
cset "name='Earpiece Playback Switch' on"
|
|
||||||
cset "name='Earpiece Playback Volume' 100%"
|
|
||||||
]
|
|
||||||
|
|
||||||
DisableSequence [
|
|
||||||
cset "name='Earpiece Playback Switch' off"
|
|
||||||
]
|
|
||||||
|
|
||||||
Value {
|
|
||||||
PlaybackVolume "Earpiece Playback Volume"
|
|
||||||
PlaybackSwitch "Earpiece Playback Switch"
|
|
||||||
PlaybackChannels 2
|
|
||||||
PlaybackPriority 500
|
|
||||||
PlaybackPCM "hw:${CardId},0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SectionDevice."Mic" {
|
|
||||||
Comment "Internal Microphone"
|
|
||||||
ConflictingDevice [
|
|
||||||
"Headset"
|
|
||||||
]
|
|
||||||
EnableSequence [
|
|
||||||
cset "name='Mic1 Capture Switch' on"
|
|
||||||
]
|
|
||||||
DisableSequence [
|
|
||||||
cset "name='Mic1 Capture Switch' off"
|
|
||||||
]
|
|
||||||
Value {
|
|
||||||
CapturePriority 200
|
|
||||||
CapturePCM "hw:${CardId},0"
|
|
||||||
CaptureMixerElem "ADC"
|
|
||||||
CaptureVolume "ADC Capture Volume"
|
|
||||||
CaptureSwitch "Mic1 Capture Switch"
|
|
||||||
CaptureChannels 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SectionDevice."Headset" {
|
|
||||||
Comment "Headset Microphone"
|
|
||||||
ConflictingDevice [
|
|
||||||
"Mic"
|
|
||||||
]
|
|
||||||
EnableSequence [
|
|
||||||
cset "name='Mic2 Capture Switch' on"
|
|
||||||
]
|
|
||||||
DisableSequence [
|
|
||||||
cset "name='Mic2 Capture Switch' off"
|
|
||||||
]
|
|
||||||
Value {
|
|
||||||
CapturePriority 500
|
|
||||||
CapturePCM "hw:${CardId},0"
|
|
||||||
CaptureChannels 2
|
|
||||||
CaptureMixerElem "ADC"
|
|
||||||
CaptureVolume "ADC Capture Volume"
|
|
||||||
CaptureSwitch "Mic2 Capture Switch"
|
|
||||||
JackControl "Headset Microphone Jack"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SectionDevice."Headphones" {
|
|
||||||
Comment "Headphones"
|
|
||||||
EnableSequence [
|
|
||||||
cset "name='AIF1 DA0 Stereo Playback Route' Stereo"
|
|
||||||
cset "name='Headphone Playback Switch' on"
|
|
||||||
cset "name='Headphone Playback Volume' 100%"
|
|
||||||
]
|
|
||||||
|
|
||||||
DisableSequence [
|
|
||||||
cset "name='Headphone Playback Switch' off"
|
|
||||||
]
|
|
||||||
|
|
||||||
Value {
|
|
||||||
PlaybackVolume "Headphone Playback Volume"
|
|
||||||
PlaybackSwitch "Headphone Playback Switch"
|
|
||||||
PlaybackChannels 2
|
|
||||||
PlaybackPriority 500
|
|
||||||
PlaybackPCM "hw:${CardId},0"
|
|
||||||
JackControl "Headphone Jack"
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,8 +0,0 @@
|
|||||||
Syntax 3
|
|
||||||
|
|
||||||
UseCasePath {
|
|
||||||
legacy {
|
|
||||||
Directory "PinePhone"
|
|
||||||
File "PinePhone.conf"
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,13 +0,0 @@
|
|||||||
{ config, pkgs, ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./fs.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
boot.loader.generic-extlinux-compatible.enable = true;
|
|
||||||
boot.loader.efi.canTouchEfiVariables = false;
|
|
||||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
|
||||||
|
|
||||||
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
|
|
||||||
system.stateVersion = "21.05";
|
|
||||||
}
|
|
@@ -1,12 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
fileSystems."/" = {
|
|
||||||
device = "/dev/disk/by-uuid/44445555-6666-7777-8888-999900001111";
|
|
||||||
fsType = "ext4";
|
|
||||||
};
|
|
||||||
fileSystems."/boot" = {
|
|
||||||
device = "/dev/disk/by-uuid/2222-3333";
|
|
||||||
fsType = "vfat";
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,41 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./fs.nix
|
|
||||||
./net.nix
|
|
||||||
./users.nix
|
|
||||||
./services
|
|
||||||
];
|
|
||||||
|
|
||||||
sane.packages.extraUserPkgs = [
|
|
||||||
# for administering services
|
|
||||||
pkgs.matrix-synapse
|
|
||||||
pkgs.freshrss
|
|
||||||
];
|
|
||||||
sane.persist.enable = true;
|
|
||||||
sane.services.dyn-dns.enable = true;
|
|
||||||
# sane.services.duplicity.enable = true; # TODO: re-enable after HW upgrade
|
|
||||||
|
|
||||||
boot.loader.efi.canTouchEfiVariables = false;
|
|
||||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
|
||||||
|
|
||||||
sops.secrets.duplicity_passphrase = {
|
|
||||||
sopsFile = ../../secrets/servo.yaml;
|
|
||||||
};
|
|
||||||
|
|
||||||
# both transmission and ipfs try to set different net defaults.
|
|
||||||
# we just use the most aggressive of the two here:
|
|
||||||
boot.kernel.sysctl = {
|
|
||||||
"net.core.rmem_max" = 4194304; # 4MB
|
|
||||||
};
|
|
||||||
|
|
||||||
# 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 = "21.11";
|
|
||||||
}
|
|
||||||
|
|
@@ -1,93 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
sane.persist.root-on-tmpfs = true;
|
|
||||||
# we need a /tmp for building large nix things
|
|
||||||
fileSystems."/tmp" = {
|
|
||||||
device = "none";
|
|
||||||
fsType = "tmpfs";
|
|
||||||
options = [
|
|
||||||
"mode=777"
|
|
||||||
"defaults"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems."/nix" = {
|
|
||||||
device = "/dev/disk/by-uuid/cc81cca0-3cc7-4d82-a00c-6243af3e7776";
|
|
||||||
fsType = "btrfs";
|
|
||||||
options = [
|
|
||||||
"compress=zstd"
|
|
||||||
"defaults"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems."/boot" = {
|
|
||||||
device = "/dev/disk/by-uuid/6EE3-4171";
|
|
||||||
fsType = "vfat";
|
|
||||||
};
|
|
||||||
|
|
||||||
# slow, external storage (for archiving, etc)
|
|
||||||
fileSystems."/mnt/persist/ext" = {
|
|
||||||
device = "/dev/disk/by-uuid/aa272cff-0fcc-498e-a4cb-0d95fb60631b";
|
|
||||||
fsType = "btrfs";
|
|
||||||
options = [
|
|
||||||
"compress=zstd"
|
|
||||||
"defaults"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.persist.stores."ext" = {
|
|
||||||
origin = "/mnt/persist/ext/persist";
|
|
||||||
storeDescription = "external HDD storage";
|
|
||||||
};
|
|
||||||
sane.fs."/mnt/persist/ext".mount = {};
|
|
||||||
|
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
# TODO: this is overly broad; only need media and share directories to be persisted
|
|
||||||
{ user = "colin"; group = "users"; directory = "/var/lib/uninsane"; }
|
|
||||||
];
|
|
||||||
# make sure large media is stored to the HDD
|
|
||||||
sane.persist.sys.ext = [
|
|
||||||
{
|
|
||||||
user = "colin";
|
|
||||||
group = "users";
|
|
||||||
mode = "0777";
|
|
||||||
directory = "/var/lib/uninsane/media/Videos";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
user = "colin";
|
|
||||||
group = "users";
|
|
||||||
mode = "0777";
|
|
||||||
directory = "/var/lib/uninsane/media/freeleech";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
# in-memory compressed RAM (seems to be dynamically sized)
|
|
||||||
# zramSwap = {
|
|
||||||
# enable = true;
|
|
||||||
# };
|
|
||||||
|
|
||||||
# btrfs doesn't easily support swapfiles
|
|
||||||
# swapDevices = [
|
|
||||||
# { device = "/nix/persist/swapfile"; size = 4096; }
|
|
||||||
# ];
|
|
||||||
|
|
||||||
# this can be a partition. create with:
|
|
||||||
# fdisk <dev>
|
|
||||||
# n
|
|
||||||
# <default partno>
|
|
||||||
# <start>
|
|
||||||
# <end>
|
|
||||||
# t
|
|
||||||
# <partno>
|
|
||||||
# 19 # set part type to Linux swap
|
|
||||||
# w # write changes
|
|
||||||
# mkswap -L swap <part>
|
|
||||||
# swapDevices = [
|
|
||||||
# {
|
|
||||||
# label = "swap";
|
|
||||||
# # TODO: randomEncryption.enable = true;
|
|
||||||
# }
|
|
||||||
# ];
|
|
||||||
}
|
|
||||||
|
|
@@ -1,212 +0,0 @@
|
|||||||
{ config, pkgs, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
networking.domain = "uninsane.org";
|
|
||||||
|
|
||||||
# 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
|
|
||||||
# replicates the default behaviour.
|
|
||||||
networking.useDHCP = false;
|
|
||||||
networking.interfaces.eth0.useDHCP = true;
|
|
||||||
# XXX colin: probably don't need this. wlan0 won't be populated unless i touch a value in networking.interfaces.wlan0
|
|
||||||
networking.wireless.enable = false;
|
|
||||||
|
|
||||||
# networking.firewall.enable = false;
|
|
||||||
networking.firewall.enable = true;
|
|
||||||
|
|
||||||
# this is needed to forward packets from the VPN to the host
|
|
||||||
boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
|
|
||||||
|
|
||||||
# unless we add interface-specific settings for each VPN, we have to define nameservers globally.
|
|
||||||
# networking.nameservers = [
|
|
||||||
# "1.1.1.1"
|
|
||||||
# "9.9.9.9"
|
|
||||||
# ];
|
|
||||||
|
|
||||||
# use systemd's stub resolver.
|
|
||||||
# /etc/resolv.conf isn't sophisticated enough to use different servers per net namespace (or link).
|
|
||||||
# instead, running the stub resolver on a known address in the root ns lets us rewrite packets
|
|
||||||
# in the ovnps namespace to use the provider's DNS resolvers.
|
|
||||||
# a weakness is we can only query 1 NS at a time (unless we were to clone the packets?)
|
|
||||||
# there also seems to be some cache somewhere that's shared between the two namespaces.
|
|
||||||
# i think this is a libc thing. might need to leverage proper cgroups to _really_ kill it.
|
|
||||||
# - getent ahostsv4 www.google.com
|
|
||||||
# - try fix: <https://serverfault.com/questions/765989/connect-to-3rd-party-vpn-server-but-dont-use-it-as-the-default-route/766290#766290>
|
|
||||||
services.resolved.enable = true;
|
|
||||||
networking.nameservers = [
|
|
||||||
# use systemd-resolved resolver
|
|
||||||
# full resolver (which understands /etc/hosts) lives on 127.0.0.53
|
|
||||||
# stub resolver (just forwards upstream) lives on 127.0.0.54
|
|
||||||
"127.0.0.53"
|
|
||||||
];
|
|
||||||
|
|
||||||
# nscd -- the Name Service Caching Daemon -- caches DNS query responses
|
|
||||||
# in a way that's unaware of my VPN routing, so routes are frequently poor against
|
|
||||||
# services which advertise different IPs based on geolocation.
|
|
||||||
# nscd claims to be usable without a cache, but in practice i can't get it to not cache!
|
|
||||||
# nsncd is the Name Service NON-Caching Daemon. it's a drop-in that doesn't cache;
|
|
||||||
# this is OK on the host -- because systemd-resolved caches. it's probably sub-optimal
|
|
||||||
# in the netns and we query upstream DNS more often than needed. hm.
|
|
||||||
# TODO: run a separate recursive resolver in each namespace.
|
|
||||||
services.nscd.enableNsncd = true;
|
|
||||||
|
|
||||||
# services.resolved.extraConfig = ''
|
|
||||||
# # docs: `man resolved.conf`
|
|
||||||
# # DNS servers to use via the `wg0` interface.
|
|
||||||
# # i hope that from the root ns, these aren't visible.
|
|
||||||
# DNS=46.227.67.134%wg0 192.165.9.158%wg0
|
|
||||||
# FallbackDNS=1.1.1.1 9.9.9.9
|
|
||||||
# '';
|
|
||||||
|
|
||||||
# OVPN CONFIG (https://www.ovpn.com):
|
|
||||||
# DOCS: https://nixos.wiki/wiki/WireGuard
|
|
||||||
# if you `systemctl restart wireguard-wg0`, make sure to also restart any other services in `NetworkNamespacePath = .../ovpns`.
|
|
||||||
# TODO: why not create the namespace as a seperate operation (nix config for that?)
|
|
||||||
networking.wireguard.enable = true;
|
|
||||||
networking.wireguard.interfaces.wg0 = let
|
|
||||||
ip = "${pkgs.iproute2}/bin/ip";
|
|
||||||
in-ns = "${ip} netns exec ovpns";
|
|
||||||
iptables = "${pkgs.iptables}/bin/iptables";
|
|
||||||
veth-host-ip = "10.0.1.5";
|
|
||||||
veth-local-ip = "10.0.1.6";
|
|
||||||
vpn-ip = "185.157.162.178";
|
|
||||||
# DNS = 46.227.67.134, 192.165.9.158, 2a07:a880:4601:10f0:cd45::1, 2001:67c:750:1:cafe:cd45::1
|
|
||||||
vpn-dns = "46.227.67.134";
|
|
||||||
in {
|
|
||||||
privateKeyFile = config.sops.secrets.wg_ovpns_privkey.path;
|
|
||||||
# wg is active only in this namespace.
|
|
||||||
# run e.g. ip netns exec ovpns <some command like ping/curl/etc, it'll go through wg>
|
|
||||||
# sudo ip netns exec ovpns ping www.google.com
|
|
||||||
interfaceNamespace = "ovpns";
|
|
||||||
ips = [
|
|
||||||
"185.157.162.178/32"
|
|
||||||
];
|
|
||||||
peers = [
|
|
||||||
{
|
|
||||||
publicKey = "SkkEZDCBde22KTs/Hc7FWvDBfdOCQA4YtBEuC3n5KGs=";
|
|
||||||
endpoint = "185.157.162.10:9930";
|
|
||||||
# alternatively: use hostname, but that presents bootstrapping issues (e.g. if host net flakes)
|
|
||||||
# endpoint = "vpn36.prd.amsterdam.ovpn.com:9930";
|
|
||||||
allowedIPs = [ "0.0.0.0/0" ];
|
|
||||||
# nixOS says this is important for keeping NATs active
|
|
||||||
persistentKeepalive = 25;
|
|
||||||
# re-executes wg this often. docs hint that this might help wg notice DNS/hostname changes.
|
|
||||||
# so, maybe that helps if we specify endpoint as a domain name
|
|
||||||
# dynamicEndpointRefreshSeconds = 30;
|
|
||||||
# when refresh fails, try it again after this period instead.
|
|
||||||
# TODO: not avail until nixpkgs upgrade
|
|
||||||
# dynamicEndpointRefreshRestartSeconds = 5;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
preSetup = "" + ''
|
|
||||||
${ip} netns add ovpns || echo "ovpns already exists"
|
|
||||||
'';
|
|
||||||
postShutdown = "" + ''
|
|
||||||
${in-ns} ip link del ovpns-veth-b || echo "couldn't delete ovpns-veth-b"
|
|
||||||
${ip} link del ovpns-veth-a || echo "couldn't delete ovpns-veth-a"
|
|
||||||
${ip} netns delete ovpns || echo "couldn't delete ovpns"
|
|
||||||
# restore rules/routes
|
|
||||||
${ip} rule del from ${veth-host-ip} lookup ovpns pref 50 || echo "couldn't delete init -> ovpns rule"
|
|
||||||
${ip} route del default via ${veth-local-ip} dev ovpns-veth-a proto kernel src ${veth-host-ip} metric 1002 table ovpns || echo "couldn't delete init -> ovpns route"
|
|
||||||
${ip} rule add from all lookup local pref 0
|
|
||||||
${ip} rule del from all lookup local pref 100
|
|
||||||
'';
|
|
||||||
postSetup = "" + ''
|
|
||||||
# DOCS:
|
|
||||||
# - some of this approach is described here: <https://josephmuia.ca/2018-05-16-net-namespaces-veth-nat/>
|
|
||||||
# - iptables primer: <https://danielmiessler.com/study/iptables/>
|
|
||||||
# create veth pair
|
|
||||||
${ip} link add ovpns-veth-a type veth peer name ovpns-veth-b
|
|
||||||
${ip} addr add ${veth-host-ip}/24 dev ovpns-veth-a
|
|
||||||
${ip} link set ovpns-veth-a up
|
|
||||||
|
|
||||||
# mv veth-b into the ovpns namespace
|
|
||||||
${ip} link set ovpns-veth-b netns ovpns
|
|
||||||
${in-ns} ip addr add ${veth-local-ip}/24 dev ovpns-veth-b
|
|
||||||
${in-ns} ip link set ovpns-veth-b up
|
|
||||||
|
|
||||||
# make it so traffic originating from the host side of the veth
|
|
||||||
# is sent over the veth no matter its destination.
|
|
||||||
${ip} rule add from ${veth-host-ip} lookup ovpns pref 50
|
|
||||||
# for traffic originating at the host veth to the WAN, use the veth as our gateway
|
|
||||||
# not sure if the metric 1002 matters.
|
|
||||||
${ip} route add default via ${veth-local-ip} dev ovpns-veth-a proto kernel src ${veth-host-ip} metric 1002 table ovpns
|
|
||||||
# give the default route lower priority
|
|
||||||
${ip} rule add from all lookup local pref 100
|
|
||||||
${ip} rule del from all lookup local pref 0
|
|
||||||
|
|
||||||
# bridge HTTP traffic:
|
|
||||||
# any external port-80 request sent to the VPN addr will be forwarded to the rootns.
|
|
||||||
# this exists so LetsEncrypt can procure a cert for the MX over http.
|
|
||||||
# TODO: we could use _acme_challence.mx.uninsane.org CNAME to avoid this forwarding
|
|
||||||
# - <https://community.letsencrypt.org/t/where-does-letsencrypt-resolve-dns-from/37607/8>
|
|
||||||
${in-ns} ${iptables} -A PREROUTING -t nat -p tcp --dport 80 -m iprange --dst-range ${vpn-ip} \
|
|
||||||
-j DNAT --to-destination ${veth-host-ip}:80
|
|
||||||
|
|
||||||
# we also bridge DNS traffic
|
|
||||||
${in-ns} ${iptables} -A PREROUTING -t nat -p udp --dport 53 -m iprange --dst-range ${vpn-ip} \
|
|
||||||
-j DNAT --to-destination ${veth-host-ip}:53
|
|
||||||
${in-ns} ${iptables} -A PREROUTING -t nat -p tcp --dport 53 -m iprange --dst-range ${vpn-ip} \
|
|
||||||
-j DNAT --to-destination ${veth-host-ip}:53
|
|
||||||
|
|
||||||
# in order to access DNS in this netns, we need to route it to the VPN's nameservers
|
|
||||||
# - alternatively, we could fix DNS servers like 1.1.1.1.
|
|
||||||
${in-ns} ${iptables} -A OUTPUT -t nat -p udp --dport 53 -m iprange --dst-range 127.0.0.53 \
|
|
||||||
-j DNAT --to-destination ${vpn-dns}:53
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# create a new routing table that we can use to proxy traffic out of the root namespace
|
|
||||||
# through the ovpns namespace, and to the WAN via VPN.
|
|
||||||
networking.iproute2.rttablesExtraConfig = ''
|
|
||||||
5 ovpns
|
|
||||||
'';
|
|
||||||
networking.iproute2.enable = true;
|
|
||||||
|
|
||||||
sops.secrets."wg_ovpns_privkey" = {
|
|
||||||
sopsFile = ../../secrets/servo.yaml;
|
|
||||||
};
|
|
||||||
|
|
||||||
# HURRICANE ELECTRIC CONFIG:
|
|
||||||
# networking.sits = {
|
|
||||||
# hurricane = {
|
|
||||||
# remote = "216.218.226.238";
|
|
||||||
# local = "192.168.0.5";
|
|
||||||
# # local = "10.0.0.5";
|
|
||||||
# # remote = "10.0.0.1";
|
|
||||||
# # local = "10.0.0.22";
|
|
||||||
# dev = "eth0";
|
|
||||||
# ttl = 255;
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
# networking.interfaces."hurricane".ipv6 = {
|
|
||||||
# addresses = [
|
|
||||||
# # mx.uninsane.org (publically routed /64)
|
|
||||||
# {
|
|
||||||
# address = "2001:470:b:465::1";
|
|
||||||
# prefixLength = 128;
|
|
||||||
# }
|
|
||||||
# # client addr
|
|
||||||
# # {
|
|
||||||
# # address = "2001:470:a:466::2";
|
|
||||||
# # prefixLength = 64;
|
|
||||||
# # }
|
|
||||||
# ];
|
|
||||||
# routes = [
|
|
||||||
# {
|
|
||||||
# address = "::";
|
|
||||||
# prefixLength = 0;
|
|
||||||
# # via = "2001:470:a:466::1";
|
|
||||||
# }
|
|
||||||
# ];
|
|
||||||
# };
|
|
||||||
|
|
||||||
# # after configuration, we want the hurricane device to look like this:
|
|
||||||
# # hurricane: flags=209<UP,POINTOPOINT,RUNNING,NOARP> mtu 1480
|
|
||||||
# # inet6 2001:470:a:450::2 prefixlen 64 scopeid 0x0<global>
|
|
||||||
# # inet6 fe80::c0a8:16 prefixlen 64 scopeid 0x20<link>
|
|
||||||
# # sit txqueuelen 1000 (IPv6-in-IPv4)
|
|
||||||
# # test with:
|
|
||||||
# # curl --interface hurricane http://[2607:f8b0:400a:80b::2004]
|
|
||||||
# # ping 2607:f8b0:400a:80b::2004
|
|
||||||
}
|
|
@@ -1,31 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
# using manual ddns now
|
|
||||||
lib.mkIf false
|
|
||||||
{
|
|
||||||
systemd.services.ddns-afraid = {
|
|
||||||
description = "update dynamic DNS entries for freedns.afraid.org";
|
|
||||||
serviceConfig = {
|
|
||||||
EnvironmentFile = config.sops.secrets.ddns_afraid.path;
|
|
||||||
# TODO: ProtectSystem = "strict";
|
|
||||||
# TODO: ProtectHome = "full";
|
|
||||||
# TODO: PrivateTmp = true;
|
|
||||||
};
|
|
||||||
script = let
|
|
||||||
curl = "${pkgs.curl}/bin/curl -4";
|
|
||||||
in ''
|
|
||||||
${curl} "https://freedns.afraid.org/dynamic/update.php?$AFRAID_KEY"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
systemd.timers.ddns-afraid = {
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
timerConfig = {
|
|
||||||
OnStartupSec = "2min";
|
|
||||||
OnUnitActiveSec = "10min";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sops.secrets."ddns_afraid" = {
|
|
||||||
sopsFile = ../../../secrets/servo.yaml;
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,34 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
# we use manual DDNS now
|
|
||||||
lib.mkIf false
|
|
||||||
{
|
|
||||||
systemd.services.ddns-he = {
|
|
||||||
description = "update dynamic DNS entries for HurricaneElectric";
|
|
||||||
serviceConfig = {
|
|
||||||
EnvironmentFile = config.sops.secrets.ddns_he.path;
|
|
||||||
# TODO: ProtectSystem = "strict";
|
|
||||||
# TODO: ProtectHome = "full";
|
|
||||||
# TODO: PrivateTmp = true;
|
|
||||||
};
|
|
||||||
# HE DDNS API is documented: https://dns.he.net/docs.html
|
|
||||||
script = let
|
|
||||||
crl = "${pkgs.curl}/bin/curl -4";
|
|
||||||
in ''
|
|
||||||
${crl} "https://he.uninsane.org:$HE_PASSPHRASE@dyn.dns.he.net/nic/update?hostname=he.uninsane.org"
|
|
||||||
${crl} "https://native.uninsane.org:$HE_PASSPHRASE@dyn.dns.he.net/nic/update?hostname=native.uninsane.org"
|
|
||||||
${crl} "https://uninsane.org:$HE_PASSPHRASE@dyn.dns.he.net/nic/update?hostname=uninsane.org"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
systemd.timers.ddns-he = {
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
timerConfig = {
|
|
||||||
OnStartupSec = "2min";
|
|
||||||
OnUnitActiveSec = "10min";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sops.secrets."ddns_he" = {
|
|
||||||
sopsFile = ../../../secrets/servo.yaml;
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,26 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./ddns-afraid.nix
|
|
||||||
./ddns-he.nix
|
|
||||||
./ejabberd.nix
|
|
||||||
./freshrss.nix
|
|
||||||
./gitea.nix
|
|
||||||
./goaccess.nix
|
|
||||||
./ipfs.nix
|
|
||||||
./jackett.nix
|
|
||||||
./jellyfin.nix
|
|
||||||
./kiwix-serve.nix
|
|
||||||
./matrix
|
|
||||||
./navidrome.nix
|
|
||||||
./nixserve.nix
|
|
||||||
./nginx.nix
|
|
||||||
./pleroma.nix
|
|
||||||
./postfix.nix
|
|
||||||
./postgres.nix
|
|
||||||
./prosody.nix
|
|
||||||
./transmission.nix
|
|
||||||
./trust-dns.nix
|
|
||||||
./wikipedia.nix
|
|
||||||
];
|
|
||||||
}
|
|
@@ -1,393 +0,0 @@
|
|||||||
# docs:
|
|
||||||
# - <https://docs.ejabberd.im/admin/configuration/basic>
|
|
||||||
# example configs:
|
|
||||||
# - <https://github.com/vkleen/machines/blob/138a2586ce185d7cf201d4e1fe898c83c4af52eb/hosts/europium/ejabberd.nix>
|
|
||||||
# - <https://github.com/Mic92/stockholm/blob/675ef0088624c9de1cb531f318446316884a9d3d/tv/3modules/ejabberd/default.nix>
|
|
||||||
# - <https://github.com/buffet/tararice/blob/master/programs/ejabberd.nix>
|
|
||||||
# - enables STUN and TURN
|
|
||||||
# - only over UDP 3478, not firewall-forwarding any TURN port range
|
|
||||||
# - uses stun_disco module (but with no options)
|
|
||||||
# - <https://github.com/leo60228/dotfiles/blob/39b3abba3009bdc31413d4757ca2f882a33eec8b/files/ejabberd.yml>
|
|
||||||
# - <https://github.com/Mic92/dotfiles/blob/ddf0f4821f554f7667fc803344657367c55fb9e6/nixos/eve/modules/ejabberd.nix>
|
|
||||||
# - <nixpkgs:nixos/tests/xmpp/ejabberd.nix>
|
|
||||||
# - 2013: <https://github.com/processone/ejabberd/blob/master/ejabberd.yml.example>
|
|
||||||
#
|
|
||||||
# compliance tests:
|
|
||||||
# - <https://compliance.conversations.im/server/uninsane.org/#xep0352>
|
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
# XXX: avatar support works in MUCs but not DMs
|
|
||||||
# lib.mkIf false
|
|
||||||
{
|
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
{ user = "ejabberd"; group = "ejabberd"; directory = "/var/lib/ejabberd"; }
|
|
||||||
];
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
|
||||||
3478 # STUN/TURN
|
|
||||||
5222 # XMPP client -> server
|
|
||||||
5223 # XMPPS client -> server (XMPP over TLS)
|
|
||||||
5269 # XMPP server -> server
|
|
||||||
5270 # XMPPS server -> server (XMPP over TLS)
|
|
||||||
5280 # bosh
|
|
||||||
5281 # bosh (https) ??
|
|
||||||
5349 # STUN/TURN (TLS)
|
|
||||||
5443 # web services (file uploads, websockets, admin)
|
|
||||||
];
|
|
||||||
networking.firewall.allowedUDPPorts = [
|
|
||||||
3478 # STUN/TURN
|
|
||||||
];
|
|
||||||
networking.firewall.allowedTCPPortRanges = [{
|
|
||||||
from = 49152; # TURN
|
|
||||||
to = 65535;
|
|
||||||
}];
|
|
||||||
networking.firewall.allowedUDPPortRanges = [{
|
|
||||||
from = 49152; # TURN
|
|
||||||
to = 65535;
|
|
||||||
}];
|
|
||||||
|
|
||||||
# provide access to certs
|
|
||||||
users.users.ejabberd.extraGroups = [ "nginx" ];
|
|
||||||
|
|
||||||
security.acme.certs."uninsane.org".extraDomainNames = [
|
|
||||||
"xmpp.uninsane.org"
|
|
||||||
"muc.xmpp.uninsane.org"
|
|
||||||
"pubsub.xmpp.uninsane.org"
|
|
||||||
"upload.xmpp.uninsane.org"
|
|
||||||
"vjid.xmpp.uninsane.org"
|
|
||||||
];
|
|
||||||
|
|
||||||
# exists so the XMPP server's cert can obtain altNames for all its resources
|
|
||||||
services.nginx.virtualHosts."xmpp.uninsane.org" = {
|
|
||||||
useACMEHost = "uninsane.org";
|
|
||||||
};
|
|
||||||
services.nginx.virtualHosts."muc.xmpp.uninsane.org" = {
|
|
||||||
useACMEHost = "uninsane.org";
|
|
||||||
};
|
|
||||||
services.nginx.virtualHosts."pubsub.xmpp.uninsane.org" = {
|
|
||||||
useACMEHost = "uninsane.org";
|
|
||||||
};
|
|
||||||
services.nginx.virtualHosts."upload.xmpp.uninsane.org" = {
|
|
||||||
useACMEHost = "uninsane.org";
|
|
||||||
};
|
|
||||||
services.nginx.virtualHosts."vjid.xmpp.uninsane.org" = {
|
|
||||||
useACMEHost = "uninsane.org";
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".inet = {
|
|
||||||
# XXX: SRV records have to point to something with a A/AAAA record; no CNAMEs
|
|
||||||
A."xmpp" = "%NATIVE%";
|
|
||||||
CNAME."muc.xmpp" = "xmpp";
|
|
||||||
CNAME."pubsub.xmpp" = "xmpp";
|
|
||||||
CNAME."upload.xmpp" = "xmpp";
|
|
||||||
CNAME."vjid.xmpp" = "xmpp";
|
|
||||||
|
|
||||||
# _Service._Proto.Name TTL Class SRV Priority Weight Port Target
|
|
||||||
# - <https://xmpp.org/extensions/xep-0368.html>
|
|
||||||
# something's requesting the SRV records for muc.xmpp, so let's include it
|
|
||||||
# nothing seems to request XMPP SRVs for the other records (except @)
|
|
||||||
# lower numerical priority field tells clients to prefer this method
|
|
||||||
SRV."_xmpps-client._tcp.muc.xmpp" = "3 50 5223 xmpp";
|
|
||||||
SRV."_xmpps-server._tcp.muc.xmpp" = "3 50 5270 xmpp";
|
|
||||||
SRV."_xmpp-client._tcp.muc.xmpp" = "5 50 5222 xmpp";
|
|
||||||
SRV."_xmpp-server._tcp.muc.xmpp" = "5 50 5269 xmpp";
|
|
||||||
|
|
||||||
SRV."_xmpps-client._tcp" = "3 50 5223 xmpp";
|
|
||||||
SRV."_xmpps-server._tcp" = "3 50 5270 xmpp";
|
|
||||||
SRV."_xmpp-client._tcp" = "5 50 5222 xmpp";
|
|
||||||
SRV."_xmpp-server._tcp" = "5 50 5269 xmpp";
|
|
||||||
|
|
||||||
SRV."_stun._udp" = "5 50 3478 xmpp";
|
|
||||||
SRV."_stun._tcp" = "5 50 3478 xmpp";
|
|
||||||
SRV."_stuns._tcp" = "5 50 5349 xmpp";
|
|
||||||
SRV."_turn._udp" = "5 50 3478 xmpp";
|
|
||||||
SRV."_turn._tcp" = "5 50 3478 xmpp";
|
|
||||||
SRV."_turns._tcp" = "5 50 5349 xmpp";
|
|
||||||
};
|
|
||||||
|
|
||||||
# TODO: allocate UIDs/GIDs ?
|
|
||||||
services.ejabberd.enable = true;
|
|
||||||
services.ejabberd.configFile = "/var/lib/ejabberd/ejabberd.yaml";
|
|
||||||
systemd.services.ejabberd.preStart = let
|
|
||||||
config-in = pkgs.writeTextFile {
|
|
||||||
name = "ejabberd.yaml.in";
|
|
||||||
text = ''
|
|
||||||
hosts:
|
|
||||||
- uninsane.org
|
|
||||||
|
|
||||||
# none | emergency | alert | critical | error | warning | notice | info | debug
|
|
||||||
loglevel: debug
|
|
||||||
# loglevel: info
|
|
||||||
# loglevel: notice
|
|
||||||
|
|
||||||
acme:
|
|
||||||
auto: false
|
|
||||||
certfiles:
|
|
||||||
- /var/lib/acme/uninsane.org/full.pem
|
|
||||||
# ca_file: ${pkgs.cacert.unbundled}/etc/ssl/certs/
|
|
||||||
# ca_file: ${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
|
|
||||||
|
|
||||||
pam_userinfotype: jid
|
|
||||||
|
|
||||||
acl:
|
|
||||||
admin:
|
|
||||||
user:
|
|
||||||
- "colin@uninsane.org"
|
|
||||||
local:
|
|
||||||
user_regexp: ""
|
|
||||||
loopback:
|
|
||||||
ip:
|
|
||||||
- 127.0.0.0/8
|
|
||||||
- ::1/128
|
|
||||||
|
|
||||||
access_rules:
|
|
||||||
local:
|
|
||||||
allow: local
|
|
||||||
c2s_access:
|
|
||||||
allow: all
|
|
||||||
announce:
|
|
||||||
allow: admin
|
|
||||||
configure:
|
|
||||||
allow: admin
|
|
||||||
muc_create:
|
|
||||||
allow: local
|
|
||||||
pubsub_createnode_access:
|
|
||||||
allow: all
|
|
||||||
trusted_network:
|
|
||||||
allow: loopback
|
|
||||||
|
|
||||||
# docs: <https://docs.ejabberd.im/admin/configuration/basic/#shaper-rules>
|
|
||||||
shaper_rules:
|
|
||||||
# setting this to above 1 may break outgoing messages
|
|
||||||
# - maybe some servers rate limit? or just don't understand simultaneous connections?
|
|
||||||
max_s2s_connections: 1
|
|
||||||
max_user_sessions: 10
|
|
||||||
max_user_offline_messages: 5000
|
|
||||||
c2s_shaper:
|
|
||||||
fast: all
|
|
||||||
s2s_shaper:
|
|
||||||
med: all
|
|
||||||
|
|
||||||
# docs: <https://docs.ejabberd.im/admin/configuration/basic/#shapers>
|
|
||||||
# this limits the bytes/sec.
|
|
||||||
# for example, burst: 3_000_000 and rate: 100_000 means:
|
|
||||||
# - each client has a BW budget that accumulates 100kB/sec and is capped at 3 MB
|
|
||||||
shaper:
|
|
||||||
fast: 1000000
|
|
||||||
med: 500000
|
|
||||||
# fast:
|
|
||||||
# - rate: 1000000
|
|
||||||
# - burst_size: 10000000
|
|
||||||
# med:
|
|
||||||
# - rate: 500000
|
|
||||||
# - burst_size: 5000000
|
|
||||||
|
|
||||||
# see: <https://docs.ejabberd.im/admin/configuration/listen/>
|
|
||||||
# s2s_use_starttls: true
|
|
||||||
s2s_use_starttls: optional
|
|
||||||
# lessens 504: remote-server-timeout errors
|
|
||||||
# see: <https://github.com/processone/ejabberd/issues/3105#issuecomment-562182967>
|
|
||||||
negotiation_timeout: 60
|
|
||||||
|
|
||||||
listen:
|
|
||||||
-
|
|
||||||
port: 5222
|
|
||||||
module: ejabberd_c2s
|
|
||||||
shaper: c2s_shaper
|
|
||||||
starttls: true
|
|
||||||
access: c2s_access
|
|
||||||
-
|
|
||||||
port: 5223
|
|
||||||
module: ejabberd_c2s
|
|
||||||
shaper: c2s_shaper
|
|
||||||
tls: true
|
|
||||||
access: c2s_access
|
|
||||||
-
|
|
||||||
port: 5269
|
|
||||||
module: ejabberd_s2s_in
|
|
||||||
shaper: s2s_shaper
|
|
||||||
-
|
|
||||||
port: 5270
|
|
||||||
module: ejabberd_s2s_in
|
|
||||||
shaper: s2s_shaper
|
|
||||||
tls: true
|
|
||||||
-
|
|
||||||
port: 5443
|
|
||||||
module: ejabberd_http
|
|
||||||
tls: true
|
|
||||||
request_handlers:
|
|
||||||
/admin: ejabberd_web_admin # TODO: ensure this actually works
|
|
||||||
/api: mod_http_api # ejabberd API endpoint (to control server)
|
|
||||||
/bosh: mod_bosh
|
|
||||||
/upload: mod_http_upload
|
|
||||||
/ws: ejabberd_http_ws
|
|
||||||
# /.well-known/host-meta: mod_host_meta
|
|
||||||
# /.well-known/host-meta.json: mod_host_meta
|
|
||||||
-
|
|
||||||
# STUN+TURN TCP
|
|
||||||
# note that the full port range should be forwarded ("not NAT'd")
|
|
||||||
# `use_turn=true` enables both TURN *and* STUN
|
|
||||||
port: 3478
|
|
||||||
module: ejabberd_stun
|
|
||||||
transport: tcp
|
|
||||||
use_turn: true
|
|
||||||
turn_min_port: 49152
|
|
||||||
turn_max_port: 65535
|
|
||||||
turn_ipv4_address: %NATIVE%
|
|
||||||
-
|
|
||||||
# STUN+TURN UDP
|
|
||||||
port: 3478
|
|
||||||
module: ejabberd_stun
|
|
||||||
transport: udp
|
|
||||||
use_turn: true
|
|
||||||
turn_min_port: 49152
|
|
||||||
turn_max_port: 65535
|
|
||||||
turn_ipv4_address: %NATIVE%
|
|
||||||
-
|
|
||||||
# STUN+TURN TLS over TCP
|
|
||||||
port: 5349
|
|
||||||
module: ejabberd_stun
|
|
||||||
transport: tcp
|
|
||||||
tls: true
|
|
||||||
certfile: /var/lib/acme/uninsane.org/full.pem
|
|
||||||
use_turn: true
|
|
||||||
turn_min_port: 49152
|
|
||||||
turn_max_port: 65535
|
|
||||||
turn_ipv4_address: %NATIVE%
|
|
||||||
|
|
||||||
# TODO: enable mod_fail2ban
|
|
||||||
# TODO(low): look into mod_http_fileserver for serving macros?
|
|
||||||
modules:
|
|
||||||
# mod_adhoc: {}
|
|
||||||
# mod_announce:
|
|
||||||
# access: admin
|
|
||||||
# allows users to set avatars in vCard
|
|
||||||
# - <https://docs.ejabberd.im/admin/configuration/modules/#mod-avatar>
|
|
||||||
mod_avatar: {}
|
|
||||||
mod_caps: {} # for mod_pubsub
|
|
||||||
mod_carboncopy: {} # allows multiple clients to receive a user's message
|
|
||||||
# queues messages when recipient is offline, including PEP and presence messages.
|
|
||||||
# compliance test suggests this be enabled
|
|
||||||
mod_client_state: {}
|
|
||||||
# mod_conversejs: TODO: enable once on 21.12
|
|
||||||
# allows clients like Dino to discover where to upload files
|
|
||||||
mod_disco:
|
|
||||||
server_info:
|
|
||||||
-
|
|
||||||
modules: all
|
|
||||||
name: abuse-addresses
|
|
||||||
urls:
|
|
||||||
- "mailto:admin.xmpp@uninsane.org"
|
|
||||||
- "xmpp:colin@uninsane.org"
|
|
||||||
-
|
|
||||||
modules: all
|
|
||||||
name: admin-addresses
|
|
||||||
urls:
|
|
||||||
- "mailto:admin.xmpp@uninsane.org"
|
|
||||||
- "xmpp:colin@uninsane.org"
|
|
||||||
mod_http_upload:
|
|
||||||
host: upload.xmpp.uninsane.org
|
|
||||||
hosts:
|
|
||||||
- upload.xmpp.uninsane.org
|
|
||||||
put_url: "https://@HOST@:5443/upload"
|
|
||||||
dir_mode: "0750"
|
|
||||||
file_mode: "0750"
|
|
||||||
rm_on_unregister: false
|
|
||||||
# allow discoverability of BOSH and websocket endpoints
|
|
||||||
# TODO: enable once on ejabberd 22.05 (presently 21.04)
|
|
||||||
# mod_host_meta: {}
|
|
||||||
mod_jidprep: {} # probably not needed: lets clients normalize jids
|
|
||||||
mod_last: {} # allow other users to know when i was last online
|
|
||||||
mod_mam:
|
|
||||||
# Mnesia is limited to 2GB, better to use an SQL backend
|
|
||||||
# For small servers SQLite is a good fit and is very easy
|
|
||||||
# to configure. Uncomment this when you have SQL configured:
|
|
||||||
# db_type: sql
|
|
||||||
assume_mam_usage: true
|
|
||||||
default: always
|
|
||||||
mod_muc:
|
|
||||||
access:
|
|
||||||
- allow
|
|
||||||
access_admin:
|
|
||||||
- allow: admin
|
|
||||||
access_create: muc_create
|
|
||||||
access_persistent: muc_create
|
|
||||||
access_mam:
|
|
||||||
- allow
|
|
||||||
history_size: 100 # messages to show new participants
|
|
||||||
host: muc.xmpp.uninsane.org
|
|
||||||
hosts:
|
|
||||||
- muc.xmpp.uninsane.org
|
|
||||||
default_room_options:
|
|
||||||
anonymous: false
|
|
||||||
lang: en
|
|
||||||
persistent: true
|
|
||||||
mam: true
|
|
||||||
mod_muc_admin: {}
|
|
||||||
mod_offline: # store messages for a user when they're offline (TODO: understand multi-client workflow?)
|
|
||||||
access_max_user_messages: max_user_offline_messages
|
|
||||||
store_groupchat: true
|
|
||||||
mod_ping: {}
|
|
||||||
mod_privacy: {} # deprecated, but required for `ejabberctl export_piefxis`
|
|
||||||
mod_private: {} # allow local clients to persist arbitrary data on my server
|
|
||||||
# push notifications to services integrated with e.g. Apple/Android.
|
|
||||||
# default is for a maximum amount of PII to be withheld, since these push notifs
|
|
||||||
# generally traverse 3rd party services. can opt to include message body, etc, though.
|
|
||||||
mod_push: {}
|
|
||||||
# i don't fully understand what this does, but it seems aimed at making push notifs more reliable.
|
|
||||||
mod_push_keepalive: {}
|
|
||||||
mod_roster:
|
|
||||||
versioning: true
|
|
||||||
# docs: <https://docs.ejabberd.im/admin/configuration/modules/#mod-s2s-dialback>
|
|
||||||
# s2s dialback to verify inbound messages
|
|
||||||
# unclear to what degree the XMPP network requires this
|
|
||||||
mod_s2s_dialback: {}
|
|
||||||
mod_shared_roster: {} # creates groups for @all, @online, and anything manually administered?
|
|
||||||
mod_stream_mgmt:
|
|
||||||
resend_on_timeout: if_offline # resend undelivered messages if the origin client is offline
|
|
||||||
# fallback for when DNS-based STUN discovery is unsupported.
|
|
||||||
# - see: <https://xmpp.org/extensions/xep-0215.html>
|
|
||||||
# docs: <https://docs.ejabberd.im/admin/configuration/modules/#mod-stun-disco>
|
|
||||||
# people say to just keep this defaulted (i guess ejabberd knows to return its `host` option of uninsane.org?)
|
|
||||||
mod_stun_disco: {}
|
|
||||||
# docs: <https://docs.ejabberd.im/admin/configuration/modules/#mod-vcard>
|
|
||||||
mod_vcard:
|
|
||||||
allow_return_all: true # all users are discoverable (?)
|
|
||||||
host: vjid.xmpp.uninsane.org
|
|
||||||
hosts:
|
|
||||||
- vjid.xmpp.uninsane.org
|
|
||||||
search: true
|
|
||||||
mod_vcard_xupdate: {} # needed for avatars
|
|
||||||
# docs: <https://docs.ejabberd.im/admin/configuration/modules/#mod-pubsub>
|
|
||||||
mod_pubsub: # needed for avatars
|
|
||||||
access_createnode: pubsub_createnode_access
|
|
||||||
host: pubsub.xmpp.uninsane.org
|
|
||||||
hosts:
|
|
||||||
- pubsub.xmpp.uninsane.org
|
|
||||||
ignore_pep_from_offline: false
|
|
||||||
last_item_cache: true
|
|
||||||
plugins:
|
|
||||||
- pep
|
|
||||||
- flat
|
|
||||||
force_node_config:
|
|
||||||
# ensure client bookmarks are private
|
|
||||||
storage:bookmarks:
|
|
||||||
access_model: whitelist
|
|
||||||
urn:xmpp:avatar:data:
|
|
||||||
access_model: open
|
|
||||||
urn:xmpp:avatar:metadata:
|
|
||||||
access_model: open
|
|
||||||
mod_version: {}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
sed = "${pkgs.gnused}/bin/sed";
|
|
||||||
in ''
|
|
||||||
ip=$(cat '${config.sane.services.dyn-dns.ipPath}')
|
|
||||||
# config is 444 (not 644), so we want to write out-of-place and then atomically move
|
|
||||||
# TODO: factor this out into `sane-woop` helper?
|
|
||||||
rm -f /var/lib/ejabberd/ejabberd.yaml.new
|
|
||||||
${sed} "s/%NATIVE%/$ip/" ${config-in} > /var/lib/ejabberd/ejabberd.yaml.new
|
|
||||||
mv /var/lib/ejabberd/ejabberd.yaml{.new,}
|
|
||||||
'';
|
|
||||||
|
|
||||||
sane.services.dyn-dns.restartOnChange = [ "ejabberd.service" ];
|
|
||||||
}
|
|
@@ -1,61 +0,0 @@
|
|||||||
# import feeds with e.g.
|
|
||||||
# ```console
|
|
||||||
# $ nix build '.#nixpkgs.freshrss'
|
|
||||||
# $ sudo -u freshrss -g freshrss FRESHRSS_DATA_PATH=/var/lib/freshrss ./result/cli/import-for-user.php --user admin --filename /home/colin/.config/newsflashFeeds.opml
|
|
||||||
# ```
|
|
||||||
#
|
|
||||||
# export feeds with
|
|
||||||
# ```console
|
|
||||||
# $ sudo -u freshrss -g freshrss FRESHRSS_DATA_PATH=/var/lib/freshrss ./result/cli/export-opml-for-user.php --user admin
|
|
||||||
# ```
|
|
||||||
|
|
||||||
{ config, lib, pkgs, sane-lib, ... }:
|
|
||||||
{
|
|
||||||
sops.secrets.freshrss_passwd = {
|
|
||||||
sopsFile = ../../../secrets/servo.yaml;
|
|
||||||
owner = config.users.users.freshrss.name;
|
|
||||||
mode = "0400";
|
|
||||||
};
|
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
{ user = "freshrss"; group = "freshrss"; directory = "/var/lib/freshrss"; }
|
|
||||||
];
|
|
||||||
|
|
||||||
services.freshrss.enable = true;
|
|
||||||
services.freshrss.baseUrl = "https://rss.uninsane.org";
|
|
||||||
services.freshrss.virtualHost = "rss.uninsane.org";
|
|
||||||
services.freshrss.passwordFile = config.sops.secrets.freshrss_passwd.path;
|
|
||||||
|
|
||||||
systemd.services.freshrss-import-feeds =
|
|
||||||
let
|
|
||||||
feeds = sane-lib.feeds;
|
|
||||||
fresh = config.systemd.services.freshrss-config;
|
|
||||||
all-feeds = config.sane.feeds;
|
|
||||||
wanted-feeds = feeds.filterByFormat ["text" "image"] all-feeds;
|
|
||||||
opml = pkgs.writeText "sane-freshrss.opml" (feeds.feedsToOpml wanted-feeds);
|
|
||||||
in {
|
|
||||||
inherit (fresh) wantedBy environment;
|
|
||||||
serviceConfig = {
|
|
||||||
inherit (fresh.serviceConfig) Type User Group StateDirectory WorkingDirectory
|
|
||||||
# hardening options
|
|
||||||
CapabilityBoundingSet DeviceAllow LockPersonality NoNewPrivileges PrivateDevices PrivateTmp PrivateUsers ProcSubset ProtectClock ProtectControlGroups ProtectHome ProtectHostname ProtectKernelLogs ProtectKernelModules ProtectKernelTunables ProtectProc ProtectSystem RemoveIPC RestrictNamespaces RestrictRealtime RestrictSUIDSGID SystemCallArchitectures SystemCallFilter UMask;
|
|
||||||
};
|
|
||||||
description = "import sane RSS feed list";
|
|
||||||
after = [ "freshrss-config.service" ];
|
|
||||||
script = ''
|
|
||||||
${pkgs.freshrss}/cli/import-for-user.php --user admin --filename ${opml}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# the default ("*:0/5") is to run every 5 minutes.
|
|
||||||
# `systemctl list-timers` to show
|
|
||||||
systemd.services.freshrss-updater.startAt = lib.mkForce "*:3/30";
|
|
||||||
|
|
||||||
services.nginx.virtualHosts."rss.uninsane.org" = {
|
|
||||||
addSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
# the routing is handled by services.freshrss.virtualHost
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."rss" = "native";
|
|
||||||
}
|
|
@@ -1,68 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
# based on <https://bytes.fyi/real-time-goaccess-reports-with-nginx/>
|
|
||||||
# log-format setting can be derived with this tool if custom:
|
|
||||||
# - <https://github.com/stockrt/nginx2goaccess>
|
|
||||||
# config options:
|
|
||||||
# - <https://github.com/allinurl/goaccess/blob/master/config/goaccess.conf>
|
|
||||||
|
|
||||||
systemd.services.goaccess = {
|
|
||||||
description = "GoAccess server monitoring";
|
|
||||||
serviceConfig = {
|
|
||||||
ExecStart = ''
|
|
||||||
${pkgs.goaccess}/bin/goaccess \
|
|
||||||
-f /var/log/nginx/public.log \
|
|
||||||
--log-format=VCOMBINED \
|
|
||||||
--real-time-html \
|
|
||||||
--html-refresh=30 \
|
|
||||||
--no-query-string \
|
|
||||||
--anonymize-ip \
|
|
||||||
--ignore-panel=HOSTS \
|
|
||||||
--ws-url=wss://sink.uninsane.org:443/ws \
|
|
||||||
--port=7890 \
|
|
||||||
-o /var/lib/uninsane/sink/index.html
|
|
||||||
'';
|
|
||||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
|
||||||
Type = "simple";
|
|
||||||
Restart = "on-failure";
|
|
||||||
RestartSec = "10s";
|
|
||||||
|
|
||||||
# hardening
|
|
||||||
WorkingDirectory = "/tmp";
|
|
||||||
NoNewPrivileges = true;
|
|
||||||
PrivateTmp = true;
|
|
||||||
ProtectHome = "read-only";
|
|
||||||
ProtectSystem = "strict";
|
|
||||||
SystemCallFilter = "~@clock @cpu-emulation @debug @keyring @memlock @module @mount @obsolete @privileged @reboot @resources @setuid @swap @raw-io";
|
|
||||||
ReadOnlyPaths = "/";
|
|
||||||
ReadWritePaths = [ "/proc/self" "/var/lib/uninsane/sink" ];
|
|
||||||
PrivateDevices = "yes";
|
|
||||||
ProtectKernelModules = "yes";
|
|
||||||
ProtectKernelTunables = "yes";
|
|
||||||
};
|
|
||||||
after = [ "network.target" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
# server statistics
|
|
||||||
services.nginx.virtualHosts."sink.uninsane.org" = {
|
|
||||||
addSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
root = "/var/lib/uninsane/sink";
|
|
||||||
|
|
||||||
locations."/ws" = {
|
|
||||||
proxyPass = "http://127.0.0.1:7890";
|
|
||||||
# XXX not sure how much of this is necessary
|
|
||||||
extraConfig = ''
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection $connection_upgrade;
|
|
||||||
proxy_buffering off;
|
|
||||||
proxy_read_timeout 7d;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."sink" = "native";
|
|
||||||
}
|
|
@@ -1,93 +0,0 @@
|
|||||||
# admin:
|
|
||||||
# - view stats:
|
|
||||||
# - sudo -u ipfs -g ipfs ipfs -c /var/lib/ipfs/ stats bw
|
|
||||||
# - sudo -u ipfs -g ipfs ipfs -c /var/lib/ipfs/ stats dht
|
|
||||||
# - sudo -u ipfs -g ipfs ipfs -c /var/lib/ipfs/ bitswap stat
|
|
||||||
# - number of open peer connections:
|
|
||||||
# - sudo -u ipfs -g ipfs ipfs -c /var/lib/ipfs/ swarm peers | wc -l
|
|
||||||
|
|
||||||
{ lib, ... }:
|
|
||||||
|
|
||||||
lib.mkIf false # i don't actively use ipfs anymore
|
|
||||||
{
|
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
# TODO: mode? could be more granular
|
|
||||||
{ user = "261"; group = "261"; directory = "/var/lib/ipfs"; }
|
|
||||||
];
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ 4001 ];
|
|
||||||
networking.firewall.allowedUDPPorts = [ 4001 ];
|
|
||||||
|
|
||||||
services.nginx.virtualHosts."ipfs.uninsane.org" = {
|
|
||||||
# don't default to ssl upgrades, since this may be dnslink'd from a different domain.
|
|
||||||
# ideally we'd disable ssl entirely, but some places assume it?
|
|
||||||
addSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
|
|
||||||
locations."/" = {
|
|
||||||
proxyPass = "http://127.0.0.1:8080";
|
|
||||||
extraConfig = ''
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Ipfs-Gateway-Prefix "";
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."ipfs" = "native";
|
|
||||||
|
|
||||||
# services.ipfs.enable = true;
|
|
||||||
services.kubo.localDiscovery = true;
|
|
||||||
services.kubo.settings = {
|
|
||||||
Addresses = {
|
|
||||||
Announce = [
|
|
||||||
# "/dns4/ipfs.uninsane.org/tcp/4001"
|
|
||||||
"/dns4/ipfs.uninsane.org/udp/4001/quic"
|
|
||||||
];
|
|
||||||
Swarm = [
|
|
||||||
# "/dns4/ipfs.uninsane.org/tcp/4001"
|
|
||||||
# "/ip4/0.0.0.0/tcp/4001"
|
|
||||||
"/dns4/ipfs.uninsane.org/udp/4001/quic"
|
|
||||||
"/ip4/0.0.0.0/udp/4001/quic"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
Gateway = {
|
|
||||||
# the gateway can only be used to serve content already replicated on this host
|
|
||||||
NoFetch = true;
|
|
||||||
};
|
|
||||||
Swarm = {
|
|
||||||
ConnMgr = {
|
|
||||||
# maintain between LowWater and HighWater peer connections
|
|
||||||
# taken from: https://github.com/ipfs/ipfs-desktop/pull/2055
|
|
||||||
# defaults are 600-900: https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmconnmgr
|
|
||||||
LowWater = 20;
|
|
||||||
HighWater = 40;
|
|
||||||
# default is 20s. i guess more grace period = less churn
|
|
||||||
GracePeriod = "1m";
|
|
||||||
};
|
|
||||||
ResourceMgr = {
|
|
||||||
# docs: https://github.com/libp2p/go-libp2p-resource-manager#resource-scopes
|
|
||||||
Enabled = true;
|
|
||||||
Limits = {
|
|
||||||
System = {
|
|
||||||
Conns = 196;
|
|
||||||
ConnsInbound = 128;
|
|
||||||
ConnsOutbound = 128;
|
|
||||||
FD = 512;
|
|
||||||
Memory = 1073741824; # 1GiB
|
|
||||||
Streams = 1536;
|
|
||||||
StreamsInbound = 1024;
|
|
||||||
StreamsOutbound = 1024;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
Transports = {
|
|
||||||
Network = {
|
|
||||||
# disable TCP, force QUIC, for lighter resources
|
|
||||||
TCP = false;
|
|
||||||
QUIC = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,32 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
# TODO: mode? we only need this to save Indexer creds ==> migrate to config?
|
|
||||||
{ user = "root"; group = "root"; directory = "/var/lib/jackett"; }
|
|
||||||
];
|
|
||||||
services.jackett.enable = true;
|
|
||||||
|
|
||||||
systemd.services.jackett.after = [ "wireguard-wg0.service" ];
|
|
||||||
systemd.services.jackett.partOf = [ "wireguard-wg0.service" ];
|
|
||||||
systemd.services.jackett.serviceConfig = {
|
|
||||||
# run this behind the OVPN static VPN
|
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
|
||||||
# patch jackett to listen on the public interfaces
|
|
||||||
# ExecStart = lib.mkForce "${pkgs.jackett}/bin/Jackett --NoUpdates --DataFolder /var/lib/jackett/.config/Jackett --ListenPublic";
|
|
||||||
};
|
|
||||||
|
|
||||||
# jackett torrent search
|
|
||||||
services.nginx.virtualHosts."jackett.uninsane.org" = {
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
locations."/" = {
|
|
||||||
# proxyPass = "http://ovpns.uninsane.org:9117";
|
|
||||||
proxyPass = "http://10.0.1.6:9117";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."jackett" = "native";
|
|
||||||
}
|
|
||||||
|
|
@@ -1,67 +0,0 @@
|
|||||||
{ config, lib, ... }:
|
|
||||||
|
|
||||||
# TODO: re-enable after migrating media dir to /var/lib/uninsane/media
|
|
||||||
# else it's too spammy
|
|
||||||
lib.mkIf false
|
|
||||||
{
|
|
||||||
networking.firewall.allowedUDPPorts = [
|
|
||||||
1900 7359 # DLNA: https://jellyfin.org/docs/general/networking/index.html
|
|
||||||
];
|
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
# TODO: mode? could be more granular
|
|
||||||
{ user = "jellyfin"; group = "jellyfin"; directory = "/var/lib/jellyfin"; }
|
|
||||||
];
|
|
||||||
|
|
||||||
# Jellyfin multimedia server
|
|
||||||
# this is mostly taken from the official jellfin.org docs
|
|
||||||
services.nginx.virtualHosts."jelly.uninsane.org" = {
|
|
||||||
addSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
|
|
||||||
locations."/" = {
|
|
||||||
proxyPass = "http://127.0.0.1:8096";
|
|
||||||
extraConfig = ''
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
proxy_set_header X-Forwarded-Protocol $scheme;
|
|
||||||
proxy_set_header X-Forwarded-Host $http_host;
|
|
||||||
|
|
||||||
# Disable buffering when the nginx proxy gets very resource heavy upon streaming
|
|
||||||
proxy_buffering off;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
# locations."/web/" = {
|
|
||||||
# proxyPass = "http://127.0.0.1:8096/web/index.html";
|
|
||||||
# extraConfig = ''
|
|
||||||
# proxy_set_header Host $host;
|
|
||||||
# proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
# proxy_set_header X-Forwarded-Protocol $scheme;
|
|
||||||
# proxy_set_header X-Forwarded-Host $http_host;
|
|
||||||
# '';
|
|
||||||
# };
|
|
||||||
locations."/socket" = {
|
|
||||||
proxyPass = "http://127.0.0.1:8096";
|
|
||||||
extraConfig = ''
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
proxy_set_header X-Forwarded-Protocol $scheme;
|
|
||||||
proxy_set_header X-Forwarded-Host $http_host;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."jelly" = "native";
|
|
||||||
|
|
||||||
services.jellyfin.enable = true;
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
{
|
|
||||||
sane.services.kiwix-serve = {
|
|
||||||
enable = true;
|
|
||||||
port = 8013;
|
|
||||||
zimPaths = [ "/var/lib/uninsane/www-archive/wikipedia_en_all_maxi_2022-05.zim" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
services.nginx.virtualHosts."w.uninsane.org" = {
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
locations."/".proxyPass = "http://127.0.0.1:8013";
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."w" = "native";
|
|
||||||
}
|
|
@@ -1,134 +0,0 @@
|
|||||||
# docs: https://nixos.wiki/wiki/Matrix
|
|
||||||
# docs: https://nixos.org/manual/nixos/stable/index.html#module-services-matrix-synapse
|
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./discord-puppet.nix
|
|
||||||
# ./irc.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
{ user = "matrix-synapse"; group = "matrix-synapse"; directory = "/var/lib/matrix-synapse"; }
|
|
||||||
];
|
|
||||||
services.matrix-synapse.enable = true;
|
|
||||||
services.matrix-synapse.settings.log_config = ./synapse-log_level.yaml;
|
|
||||||
services.matrix-synapse.settings.server_name = "uninsane.org";
|
|
||||||
|
|
||||||
# services.matrix-synapse.enable_registration_captcha = true;
|
|
||||||
# services.matrix-synapse.enable_registration_without_verification = true;
|
|
||||||
services.matrix-synapse.settings.enable_registration = true;
|
|
||||||
# services.matrix-synapse.registration_shared_secret = "<shared key goes here>";
|
|
||||||
|
|
||||||
# default for listeners is port = 8448, tls = true, x_forwarded = false.
|
|
||||||
# we change this because the server is situated behind nginx.
|
|
||||||
services.matrix-synapse.settings.listeners = [
|
|
||||||
{
|
|
||||||
port = 8008;
|
|
||||||
bind_addresses = [ "127.0.0.1" ];
|
|
||||||
type = "http";
|
|
||||||
tls = false;
|
|
||||||
x_forwarded = true;
|
|
||||||
resources = [
|
|
||||||
{
|
|
||||||
names = [ "client" "federation" ];
|
|
||||||
compress = false;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
services.matrix-synapse.settings.admin_contact = "admin.matrix@uninsane.org";
|
|
||||||
services.matrix-synapse.settings.registrations_require_3pid = [ "email" ];
|
|
||||||
|
|
||||||
services.matrix-synapse.extraConfigFiles = [
|
|
||||||
config.sops.secrets.matrix_synapse_secrets.path
|
|
||||||
];
|
|
||||||
|
|
||||||
# services.matrix-synapse.extraConfigFiles = [builtins.toFile "matrix-synapse-extra-config" ''
|
|
||||||
# admin_contact: "admin.matrix@uninsane.org"
|
|
||||||
# registrations_require_3pid:
|
|
||||||
# - email
|
|
||||||
# email:
|
|
||||||
# smtp_host: "mx.uninsane.org"
|
|
||||||
# smtp_port: 587
|
|
||||||
# smtp_user: "matrix-synapse"
|
|
||||||
# smtp_pass: "${secrets.matrix-synapse.smtp_pass}"
|
|
||||||
# require_transport_security: true
|
|
||||||
# enable_tls: true
|
|
||||||
# notif_from: "%(app)s <notify.matrix@uninsane.org>"
|
|
||||||
# app_name: "Uninsane Matrix"
|
|
||||||
# enable_notifs: true
|
|
||||||
# validation_token_lifetime: 96h
|
|
||||||
# invite_client_location: "https://web.matrix.uninsane.org"
|
|
||||||
# subjects:
|
|
||||||
# email_validation: "[%(server_name)s] Validate your email"
|
|
||||||
# ''];
|
|
||||||
|
|
||||||
# new users may be registered on the CLI:
|
|
||||||
# register_new_matrix_user -c /nix/store/8n6kcka37jhmi4qpd2r03aj71pkyh21s-homeserver.yaml http://localhost:8008
|
|
||||||
#
|
|
||||||
# or provide an registration token then can use to register through the client.
|
|
||||||
# docs: https://github.com/matrix-org/synapse/blob/develop/docs/usage/administration/admin_api/registration_tokens.md
|
|
||||||
# first, grab your own user's access token (Help & About section in Element). then:
|
|
||||||
# curl --header "Authorization: Bearer <my_token>" localhost:8008/_synapse/admin/v1/registration_tokens
|
|
||||||
# create a token with unlimited uses:
|
|
||||||
# curl -d '{}' --header "Authorization: Bearer <my_token>" localhost:8008/_synapse/admin/v1/registration_tokens/new
|
|
||||||
# create a token with limited uses:
|
|
||||||
# curl -d '{ "uses_allowed": 1 }' --header "Authorization: Bearer <my_token>" localhost:8008/_synapse/admin/v1/registration_tokens/new
|
|
||||||
|
|
||||||
# matrix chat server
|
|
||||||
# TODO: was `publog`
|
|
||||||
services.nginx.virtualHosts."matrix.uninsane.org" = {
|
|
||||||
addSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
|
|
||||||
# TODO colin: replace this with something helpful to the viewer
|
|
||||||
# locations."/".extraConfig = ''
|
|
||||||
# return 404;
|
|
||||||
# '';
|
|
||||||
|
|
||||||
locations."/" = {
|
|
||||||
proxyPass = "http://127.0.0.1:8008";
|
|
||||||
};
|
|
||||||
# redirect browsers to the web client.
|
|
||||||
# i don't think native matrix clients ever fetch the root.
|
|
||||||
# ideally this would be put behind some user-agent test though.
|
|
||||||
locations."= /" = {
|
|
||||||
return = "301 https://web.matrix.uninsane.org";
|
|
||||||
};
|
|
||||||
|
|
||||||
# locations."/_matrix" = {
|
|
||||||
# proxyPass = "http://127.0.0.1:8008";
|
|
||||||
# };
|
|
||||||
};
|
|
||||||
|
|
||||||
# matrix web client
|
|
||||||
# docs: https://nixos.org/manual/nixos/stable/index.html#module-services-matrix-element-web
|
|
||||||
services.nginx.virtualHosts."web.matrix.uninsane.org" = {
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
|
|
||||||
root = pkgs.element-web.override {
|
|
||||||
conf = {
|
|
||||||
default_server_config."m.homeserver" = {
|
|
||||||
"base_url" = "https://matrix.uninsane.org";
|
|
||||||
"server_name" = "uninsane.org";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".inet = {
|
|
||||||
CNAME."matrix" = "native";
|
|
||||||
CNAME."web.matrix" = "native";
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
sops.secrets.matrix_synapse_secrets = {
|
|
||||||
sopsFile = ../../../../secrets/servo.yaml;
|
|
||||||
owner = config.users.users.matrix-synapse.name;
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,52 +0,0 @@
|
|||||||
{ lib, ... }:
|
|
||||||
{
|
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
{ user = "matrix-synapse"; group = "matrix-synapse"; directory = "/var/lib/mx-puppet-discord"; }
|
|
||||||
];
|
|
||||||
|
|
||||||
services.matrix-synapse.settings.app_service_config_files = [
|
|
||||||
# auto-created by mx-puppet-discord service
|
|
||||||
"/var/lib/mx-puppet-discord/discord-registration.yaml"
|
|
||||||
];
|
|
||||||
|
|
||||||
services.mx-puppet-discord.enable = true;
|
|
||||||
# schema/example: <https://gitlab.com/mx-puppet/discord/mx-puppet-discord/-/blob/main/sample.config.yaml>
|
|
||||||
services.mx-puppet-discord.settings = {
|
|
||||||
bridge = {
|
|
||||||
# port = 8434
|
|
||||||
bindAddress = "127.0.0.1";
|
|
||||||
domain = "uninsane.org";
|
|
||||||
homeserverUrl = "http://127.0.0.1:8008";
|
|
||||||
# displayName = "mx-discord-puppet"; # matrix name for the bot
|
|
||||||
# matrix "groups" were an earlier version of spaces.
|
|
||||||
# maybe the puppet understands this, maybe not?
|
|
||||||
enableGroupSync = false;
|
|
||||||
};
|
|
||||||
presence = {
|
|
||||||
enabled = false;
|
|
||||||
interval = 30000;
|
|
||||||
};
|
|
||||||
provisioning = {
|
|
||||||
# allow these users to control the puppet
|
|
||||||
whitelist = [ "@colin:uninsane\\.org" ];
|
|
||||||
};
|
|
||||||
relay = {
|
|
||||||
whitelist = [ "@colin:uninsane\\.org" ];
|
|
||||||
};
|
|
||||||
selfService = {
|
|
||||||
# who's allowed to use plumbed rooms (idk what that means)
|
|
||||||
whitelist = [ "@colin:uninsane\\.org" ];
|
|
||||||
};
|
|
||||||
logging = {
|
|
||||||
# silly, debug, verbose, info, warn, error
|
|
||||||
console = "debug";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.mx-puppet-discord.serviceConfig = {
|
|
||||||
# fix up to not use /var/lib/private, but just /var/lib
|
|
||||||
DynamicUser = lib.mkForce false;
|
|
||||||
User = "matrix-synapse";
|
|
||||||
Group = "matrix-synapse";
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,97 +0,0 @@
|
|||||||
{ config, lib, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
# TODO: mode?
|
|
||||||
# user and group are both "matrix-appservice-irc"
|
|
||||||
{ user = "993"; group = "992"; directory = "/var/lib/matrix-appservice-irc"; }
|
|
||||||
];
|
|
||||||
|
|
||||||
services.matrix-synapse.settings.app_service_config_files = [
|
|
||||||
"/var/lib/matrix-appservice-irc/registration.yml" # auto-created by irc appservice
|
|
||||||
];
|
|
||||||
|
|
||||||
# note: Rizon allows only FOUR simultaneous IRC connections per IP: https://wiki.rizon.net/index.php?title=Connection/Session_Limit_Exemptions
|
|
||||||
# Rizon supports CertFP for auth: https://wiki.rizon.net/index.php?title=CertFP
|
|
||||||
services.matrix-appservice-irc.enable = true;
|
|
||||||
services.matrix-appservice-irc.registrationUrl = "http://127.0.0.1:8009";
|
|
||||||
# settings documented here: https://github.com/matrix-org/matrix-appservice-irc/blob/develop/config.sample.yaml
|
|
||||||
services.matrix-appservice-irc.settings = {
|
|
||||||
homeserver = {
|
|
||||||
url = "http://127.0.0.1:8008";
|
|
||||||
dropMatrixMessagesAfterSecs = 300;
|
|
||||||
domain = "uninsane.org";
|
|
||||||
enablePresence = true;
|
|
||||||
bindPort = 9999;
|
|
||||||
bindHost = "127.0.0.1";
|
|
||||||
};
|
|
||||||
|
|
||||||
ircService = {
|
|
||||||
servers = {
|
|
||||||
"irc.rizon.net" = {
|
|
||||||
name = "Rizon";
|
|
||||||
port = 6697; # SSL port
|
|
||||||
ssl = true;
|
|
||||||
sasl = true; # appservice doesn't support NickServ identification
|
|
||||||
botConfig = {
|
|
||||||
# bot has no presence in IRC channel; only real Matrix users
|
|
||||||
enabled = false;
|
|
||||||
# nick = "UninsaneDotOrg";
|
|
||||||
nick = "uninsane";
|
|
||||||
username = "uninsane";
|
|
||||||
};
|
|
||||||
dynamicChannels = {
|
|
||||||
enabled = true;
|
|
||||||
aliasTemplate = "#irc_rizon_$CHANNEL";
|
|
||||||
};
|
|
||||||
ircClients = {
|
|
||||||
nickTemplate = "$LOCALPARTsane";
|
|
||||||
# by default, Matrix will convert messages greater than (3) lines into a pastebin-like URL to send to IRC.
|
|
||||||
lineLimit = 20;
|
|
||||||
};
|
|
||||||
matrixClients = {
|
|
||||||
userTemplate = "@irc_rizon_$NICK"; # the :uninsane.org part is appended automatically
|
|
||||||
};
|
|
||||||
|
|
||||||
# this will let this user message the appservice with `!join #<IRCChannel>` and the rest "Just Works"
|
|
||||||
"@colin:uninsane.org" = "admin";
|
|
||||||
|
|
||||||
membershipLists = {
|
|
||||||
enabled = true;
|
|
||||||
global = {
|
|
||||||
ircToMatrix = {
|
|
||||||
initial = true;
|
|
||||||
incremental = true;
|
|
||||||
requireMatrixJoined = false;
|
|
||||||
};
|
|
||||||
matrixToIrc = {
|
|
||||||
initial = true;
|
|
||||||
incremental = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
# sync room description?
|
|
||||||
bridgeInfoState = {
|
|
||||||
enabled = true;
|
|
||||||
initial = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# hardcoded mappings, for when dynamicChannels fails us. TODO: probably safe to remove these.
|
|
||||||
# mappings = {
|
|
||||||
# "#chat" = {
|
|
||||||
# roomIds = [ "!GXJSOTdbtxRboGtDep:uninsane.org" ];
|
|
||||||
# };
|
|
||||||
# # BakaBT requires account registration, which i think means my user needs to be added before the appservice user
|
|
||||||
# "#BakaBT" = {
|
|
||||||
# roomIds = [ "!feZKttuYuHilqPFSkD:uninsane.org" ];
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
# for per-user IRC password:
|
|
||||||
# invite @irc_rizon_NickServ:uninsane.org to a DM and type `help` => register
|
|
||||||
# invite the matrix-appservice-irc user to a DM and type `!help` => add PW to database
|
|
||||||
# passwordEncryptionKeyPath = "/path/to/privkey"; # appservice will generate its own if unspecified
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,27 +0,0 @@
|
|||||||
version: 1
|
|
||||||
|
|
||||||
# In systemd's journal, loglevel is implicitly stored, so let's omit it
|
|
||||||
# from the message text.
|
|
||||||
formatters:
|
|
||||||
journal_fmt:
|
|
||||||
format: '%(name)s: [%(request)s] %(message)s'
|
|
||||||
|
|
||||||
filters:
|
|
||||||
context:
|
|
||||||
(): synapse.util.logcontext.LoggingContextFilter
|
|
||||||
request: ""
|
|
||||||
|
|
||||||
handlers:
|
|
||||||
journal:
|
|
||||||
class: systemd.journal.JournalHandler
|
|
||||||
formatter: journal_fmt
|
|
||||||
filters: [context]
|
|
||||||
SYSLOG_IDENTIFIER: synapse
|
|
||||||
|
|
||||||
# default log level: INFO
|
|
||||||
root:
|
|
||||||
level: WARN
|
|
||||||
handlers: [journal]
|
|
||||||
|
|
||||||
disable_existing_loggers: False
|
|
||||||
|
|
@@ -1,29 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
# TODO: we don't have a static user allocated for navidrome!
|
|
||||||
# the chown would happen too early for us to set static perms
|
|
||||||
"/var/lib/private/navidrome"
|
|
||||||
# { user = "navidrome"; group = "navidrome"; directory = "/var/lib/private/navidrome"; }
|
|
||||||
];
|
|
||||||
services.navidrome.enable = true;
|
|
||||||
services.navidrome.settings = {
|
|
||||||
# docs: https://www.navidrome.org/docs/usage/configuration-options/
|
|
||||||
Address = "127.0.0.1";
|
|
||||||
Port = 4533;
|
|
||||||
MusicFolder = "/var/lib/uninsane/media/Music";
|
|
||||||
CovertArtPriority = "*.jpg, *.JPG, *.png, *.PNG, embedded";
|
|
||||||
AutoImportPlaylists = false;
|
|
||||||
ScanSchedule = "@every 1h";
|
|
||||||
};
|
|
||||||
|
|
||||||
services.nginx.virtualHosts."music.uninsane.org" = {
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
locations."/".proxyPass = "http://127.0.0.1:4533";
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."music" = "native";
|
|
||||||
}
|
|
@@ -1,166 +0,0 @@
|
|||||||
# docs: https://nixos.wiki/wiki/Nginx
|
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
# make the logs for this host "public" so that they show up in e.g. metrics
|
|
||||||
publog = vhost: lib.attrsets.unionOfDisjoint vhost {
|
|
||||||
extraConfig = (vhost.extraConfig or "") + ''
|
|
||||||
access_log /var/log/nginx/public.log vcombined;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# kTLS = true; # in-kernel TLS for better perf
|
|
||||||
in
|
|
||||||
{
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
|
||||||
|
|
||||||
services.nginx.enable = true;
|
|
||||||
services.nginx.appendConfig = ''
|
|
||||||
# use 1 process per core.
|
|
||||||
# may want to increase worker_connections too, but `ulimit -n` must be increased first.
|
|
||||||
worker_processes auto;
|
|
||||||
'';
|
|
||||||
|
|
||||||
# this is the standard `combined` log format, with the addition of $host
|
|
||||||
# so that we have the virtualHost in the log.
|
|
||||||
# KEEP IN SYNC WITH GOACCESS
|
|
||||||
# goaccess calls this VCOMBINED:
|
|
||||||
# - <https://gist.github.com/jyap808/10570005>
|
|
||||||
services.nginx.commonHttpConfig = ''
|
|
||||||
log_format vcombined '$host:$server_port $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referrer" "$http_user_agent"';
|
|
||||||
access_log /var/log/nginx/private.log vcombined;
|
|
||||||
'';
|
|
||||||
# sets gzip_comp_level = 5
|
|
||||||
services.nginx.recommendedGzipSettings = true;
|
|
||||||
# enables OCSP stapling (so clients don't need contact the OCSP server -- i do instead)
|
|
||||||
# - doesn't seem to, actually: <https://www.ssllabs.com/ssltest/analyze.html?d=uninsane.org>
|
|
||||||
# caches TLS sessions for 10m
|
|
||||||
services.nginx.recommendedTlsSettings = true;
|
|
||||||
# enables sendfile, tcp_nopush, tcp_nodelay, keepalive_timeout 65
|
|
||||||
services.nginx.recommendedOptimisation = true;
|
|
||||||
|
|
||||||
# web blog/personal site
|
|
||||||
services.nginx.virtualHosts."uninsane.org" = publog {
|
|
||||||
root = "${pkgs.uninsane-dot-org}/share/uninsane-dot-org";
|
|
||||||
# a lot of places hardcode https://uninsane.org,
|
|
||||||
# and then when we mix http + non-https, we get CORS violations
|
|
||||||
# and things don't look right. so force SSL.
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
# for OCSP stapling
|
|
||||||
sslTrustedCertificate = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
|
|
||||||
|
|
||||||
# uninsane.org/share/foo => /var/lib/uninsane/root/share/foo.
|
|
||||||
# yes, nginx does not strip the prefix when evaluating against the root.
|
|
||||||
locations."/share".root = "/var/lib/uninsane/root";
|
|
||||||
|
|
||||||
# allow matrix users to discover that @user:uninsane.org is reachable via matrix.uninsane.org
|
|
||||||
locations."= /.well-known/matrix/server".extraConfig =
|
|
||||||
let
|
|
||||||
# use 443 instead of the default 8448 port to unite
|
|
||||||
# the client-server and server-server port for simplicity
|
|
||||||
server = { "m.server" = "matrix.uninsane.org:443"; };
|
|
||||||
in ''
|
|
||||||
add_header Content-Type application/json;
|
|
||||||
return 200 '${builtins.toJSON server}';
|
|
||||||
'';
|
|
||||||
locations."= /.well-known/matrix/client".extraConfig =
|
|
||||||
let
|
|
||||||
client = {
|
|
||||||
"m.homeserver" = { "base_url" = "https://matrix.uninsane.org"; };
|
|
||||||
"m.identity_server" = { "base_url" = "https://vector.im"; };
|
|
||||||
};
|
|
||||||
# ACAO required to allow element-web on any URL to request this json file
|
|
||||||
in ''
|
|
||||||
add_header Content-Type application/json;
|
|
||||||
add_header Access-Control-Allow-Origin *;
|
|
||||||
return 200 '${builtins.toJSON client}';
|
|
||||||
'';
|
|
||||||
|
|
||||||
# static URLs might not be aware of .well-known (e.g. registration confirmation URLs),
|
|
||||||
# so hack around that.
|
|
||||||
locations."/_matrix" = {
|
|
||||||
proxyPass = "http://127.0.0.1:8008";
|
|
||||||
};
|
|
||||||
locations."/_synapse" = {
|
|
||||||
proxyPass = "http://127.0.0.1:8008";
|
|
||||||
};
|
|
||||||
|
|
||||||
# allow ActivityPub clients to discover how to reach @user@uninsane.org
|
|
||||||
# TODO: waiting on https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3361/
|
|
||||||
# locations."/.well-known/nodeinfo" = {
|
|
||||||
# proxyPass = "http://127.0.0.1:4000";
|
|
||||||
# extraConfig = pleromaExtraConfig;
|
|
||||||
# };
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
# serve any site not listed above, if it's static.
|
|
||||||
# because we define it dynamically, SSL isn't trivial. support only http
|
|
||||||
# documented <https://nginx.org/en/docs/http/ngx_http_core_module.html#server_name>
|
|
||||||
services.nginx.virtualHosts."~^(?<domain>.+)$" = {
|
|
||||||
default = true;
|
|
||||||
addSSL = true;
|
|
||||||
enableACME = false;
|
|
||||||
sslCertificate = "/var/www/certs/wildcard/cert.pem";
|
|
||||||
sslCertificateKey = "/var/www/certs/wildcard/key.pem";
|
|
||||||
# sslCertificate = "/var/lib/acme/.minica/cert.pem";
|
|
||||||
# sslCertificateKey = "/var/lib/acme/.minica/key.pem";
|
|
||||||
# serverName = null;
|
|
||||||
locations."/" = {
|
|
||||||
# somehow this doesn't escape -- i get error 400 if i:
|
|
||||||
# curl 'http://..' --resolve '..:80:127.0.0.1'
|
|
||||||
root = "/var/www/sites/$domain";
|
|
||||||
# tryFiles = "$domain/$uri $domain/$uri/ =404";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
security.acme.acceptTerms = true;
|
|
||||||
security.acme.defaults.email = "admin.acme@uninsane.org";
|
|
||||||
|
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
# TODO: mode?
|
|
||||||
{ user = "acme"; group = "acme"; directory = "/var/lib/acme"; }
|
|
||||||
{ user = "colin"; group = "users"; directory = "/var/www/sites"; }
|
|
||||||
];
|
|
||||||
|
|
||||||
# let's encrypt default chain looks like:
|
|
||||||
# - End-entity certificate ← R3 ← ISRG Root X1 ← DST Root CA X3
|
|
||||||
# - <https://community.letsencrypt.org/t/production-chain-changes/150739>
|
|
||||||
# DST Root CA X3 expired in 2021 (?)
|
|
||||||
# the alternative chain is:
|
|
||||||
# - End-entity certificate ← R3 ← ISRG Root X1 (self-signed)
|
|
||||||
# using this alternative chain grants more compatibility for services like ejabberd
|
|
||||||
# but might decrease compatibility with very old clients that don't get updates (e.g. old android, iphone <= 4).
|
|
||||||
# security.acme.defaults.extraLegoFlags = [
|
|
||||||
security.acme.certs."uninsane.org" = rec {
|
|
||||||
# ISRG Root X1 results in lets encrypt sending the same chain as default,
|
|
||||||
# just without the final ISRG Root X1 ← DST Root CA X3 link.
|
|
||||||
# i.e. we could alternative clip the last item and achieve the exact same thing.
|
|
||||||
extraLegoRunFlags = [
|
|
||||||
"--preferred-chain" "ISRG Root X1"
|
|
||||||
];
|
|
||||||
extraLegoRenewFlags = extraLegoRunFlags;
|
|
||||||
};
|
|
||||||
# TODO: alternatively, we could clip the last cert IF it's expired,
|
|
||||||
# optionally outputting that to a new cert file.
|
|
||||||
# security.acme.defaults.postRun = "";
|
|
||||||
|
|
||||||
# create a self-signed SSL certificate for use with literally any domain.
|
|
||||||
# browsers will reject this, but proxies and local testing tools can be configured
|
|
||||||
# to accept it.
|
|
||||||
system.activationScripts.generate-x509-self-signed.text = ''
|
|
||||||
mkdir -p /var/www/certs/wildcard
|
|
||||||
test -f /var/www/certs/wildcard/key.pem || ${pkgs.openssl}/bin/openssl \
|
|
||||||
req -x509 -newkey rsa:4096 \
|
|
||||||
-keyout /var/www/certs/wildcard/key.pem \
|
|
||||||
-out /var/www/certs/wildcard/cert.pem \
|
|
||||||
-sha256 -nodes -days 3650 \
|
|
||||||
-addext 'subjectAltName=DNS:*' \
|
|
||||||
-subj '/CN=self-signed'
|
|
||||||
chmod 640 /var/www/certs/wildcard/{key,cert}.pem
|
|
||||||
chown root:nginx /var/www/certs/wildcard /var/www/certs/wildcard/{key,cert}.pem
|
|
||||||
'';
|
|
||||||
}
|
|
@@ -1,21 +0,0 @@
|
|||||||
{ config, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
services.nginx.virtualHosts."nixcache.uninsane.org" = {
|
|
||||||
addSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
# serverAliases = [ "nixcache" ];
|
|
||||||
locations."/".extraConfig = ''
|
|
||||||
proxy_pass http://localhost:${toString config.services.nix-serve.port};
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."nixcache" = "native";
|
|
||||||
|
|
||||||
sane.services.nixserve.enable = true;
|
|
||||||
sane.services.nixserve.sopsFile = ../../../secrets/servo.yaml;
|
|
||||||
}
|
|
@@ -1,64 +0,0 @@
|
|||||||
# example configs:
|
|
||||||
# - <https://github.com/kittywitch/nixfiles/blob/main/services/prosody.nix>
|
|
||||||
# create users with:
|
|
||||||
# - `sudo -u prosody prosodyctl adduser colin@uninsane.org`
|
|
||||||
|
|
||||||
{ lib, ... }:
|
|
||||||
|
|
||||||
# XXX disabled: doesn't send messages to nixnet.social (only receives them).
|
|
||||||
# nixnet runs ejabberd, so revisiting that.
|
|
||||||
lib.mkIf false
|
|
||||||
{
|
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
{ user = "prosody"; group = "prosody"; directory = "/var/lib/prosody"; }
|
|
||||||
];
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
|
||||||
5222 # XMPP client -> server
|
|
||||||
5269 # XMPP server -> server
|
|
||||||
5280 # bosh
|
|
||||||
5281 # Prosody HTTPS port (necessary?)
|
|
||||||
];
|
|
||||||
|
|
||||||
# provide access to certs
|
|
||||||
users.users.prosody.extraGroups = [ "nginx" ];
|
|
||||||
|
|
||||||
security.acme.certs."uninsane.org".extraDomainNames = [
|
|
||||||
"conference.xmpp.uninsane.org"
|
|
||||||
"upload.xmpp.uninsane.org"
|
|
||||||
];
|
|
||||||
|
|
||||||
services.prosody = {
|
|
||||||
enable = true;
|
|
||||||
admins = [ "colin@uninsane.org" ];
|
|
||||||
# allowRegistration = false;
|
|
||||||
# extraConfig = ''
|
|
||||||
# s2s_require_encryption = true
|
|
||||||
# c2s_require_encryption = true
|
|
||||||
# '';
|
|
||||||
|
|
||||||
extraModules = [ "private" "vcard" "privacy" "compression" "component" "muc" "pep" "adhoc" "lastactivity" "admin_adhoc" "blocklist"];
|
|
||||||
|
|
||||||
ssl.cert = "/var/lib/acme/uninsane.org/fullchain.pem";
|
|
||||||
ssl.key = "/var/lib/acme/uninsane.org/key.pem";
|
|
||||||
|
|
||||||
muc = [
|
|
||||||
{
|
|
||||||
domain = "conference.xmpp.uninsane.org";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
uploadHttp.domain = "upload.xmpp.uninsane.org";
|
|
||||||
|
|
||||||
virtualHosts = {
|
|
||||||
localhost = {
|
|
||||||
domain = "localhost";
|
|
||||||
enabled = true;
|
|
||||||
};
|
|
||||||
"xmpp.uninsane.org" = {
|
|
||||||
domain = "uninsane.org";
|
|
||||||
enabled = true;
|
|
||||||
ssl.cert = "/var/lib/acme/uninsane.org/fullchain.pem";
|
|
||||||
ssl.key = "/var/lib/acme/uninsane.org/key.pem";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,80 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
# TODO: mode? we need this specifically for the stats tracking in .config/
|
|
||||||
{ user = "transmission"; group = "transmission"; directory = "/var/lib/transmission"; }
|
|
||||||
];
|
|
||||||
services.transmission.enable = true;
|
|
||||||
services.transmission.settings = {
|
|
||||||
rpc-bind-address = "0.0.0.0";
|
|
||||||
#rpc-host-whitelist = "bt.uninsane.org";
|
|
||||||
#rpc-whitelist = "*.*.*.*";
|
|
||||||
rpc-authentication-required = true;
|
|
||||||
rpc-username = "colin";
|
|
||||||
# salted pw. to regenerate, set this plaintext, run nixos-rebuild, and then find the salted pw in:
|
|
||||||
# /var/lib/transmission/.config/transmission-daemon/settings.json
|
|
||||||
rpc-password = "{503fc8928344f495efb8e1f955111ca5c862ce0656SzQnQ5";
|
|
||||||
rpc-whitelist-enabled = false;
|
|
||||||
|
|
||||||
# download-dir = "/opt/uninsane/media/";
|
|
||||||
# hopefully, make the downloads world-readable
|
|
||||||
umask = 0;
|
|
||||||
|
|
||||||
# force peer connections to be encrypted
|
|
||||||
encryption = 2;
|
|
||||||
|
|
||||||
# units in kBps
|
|
||||||
speed-limit-down = 3000;
|
|
||||||
speed-limit-down-enabled = true;
|
|
||||||
speed-limit-up = 300;
|
|
||||||
speed-limit-up-enabled = true;
|
|
||||||
|
|
||||||
# see: https://git.zknt.org/mirror/transmission/commit/cfce6e2e3a9b9d31a9dafedd0bdc8bf2cdb6e876?lang=bg-BG
|
|
||||||
anti-brute-force-enabled = false;
|
|
||||||
|
|
||||||
download-dir = "/var/lib/uninsane/media";
|
|
||||||
incomplete-dir = "/var/lib/uninsane/media/incomplete";
|
|
||||||
|
|
||||||
};
|
|
||||||
# transmission will by default not allow the world to read its files.
|
|
||||||
services.transmission.downloadDirPermissions = "775";
|
|
||||||
|
|
||||||
systemd.services.transmission.after = [ "wireguard-wg0.service" ];
|
|
||||||
systemd.services.transmission.partOf = [ "wireguard-wg0.service" ];
|
|
||||||
systemd.services.transmission.serviceConfig = {
|
|
||||||
# run this behind the OVPN static VPN
|
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
|
||||||
LogLevelMax = "warning";
|
|
||||||
};
|
|
||||||
|
|
||||||
# service to automatically backup torrents i add to transmission
|
|
||||||
systemd.services.backup-torrents = {
|
|
||||||
description = "archive torrents to storage not owned by transmission";
|
|
||||||
script = ''
|
|
||||||
${pkgs.rsync}/bin/rsync -arv /var/lib/transmission/.config/transmission-daemon/torrents/ /var/backup/torrents/
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
systemd.timers.backup-torrents = {
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
timerConfig = {
|
|
||||||
OnStartupSec = "11min";
|
|
||||||
OnUnitActiveSec = "240min";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# transmission web client
|
|
||||||
services.nginx.virtualHosts."bt.uninsane.org" = {
|
|
||||||
# basicAuth is literally cleartext user/pw, so FORCE this to happen over SSL
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
locations."/" = {
|
|
||||||
# proxyPass = "http://ovpns.uninsane.org:9091";
|
|
||||||
proxyPass = "http://10.0.1.6:9091";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."bt" = "native";
|
|
||||||
}
|
|
||||||
|
|
@@ -1,66 +0,0 @@
|
|||||||
{ config, pkgs, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
sane.services.trust-dns.enable = true;
|
|
||||||
|
|
||||||
sane.services.trust-dns.listenAddrsIPv4 = [
|
|
||||||
# specify each address explicitly, instead of using "*".
|
|
||||||
# this ensures responses are sent from the address at which the request was received.
|
|
||||||
"192.168.0.5"
|
|
||||||
"10.0.1.5"
|
|
||||||
];
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".TTL = 900;
|
|
||||||
|
|
||||||
# SOA record structure: <https://en.wikipedia.org/wiki/SOA_record#Structure>
|
|
||||||
# SOA MNAME RNAME (... rest)
|
|
||||||
# MNAME = Master name server for this zone. this is where update requests should be sent.
|
|
||||||
# RNAME = admin contact (encoded email address)
|
|
||||||
# Serial = YYYYMMDDNN, where N is incremented every time this file changes, to trigger secondary NS to re-fetch it.
|
|
||||||
# Refresh = how frequently secondary NS should query master
|
|
||||||
# Retry = how long secondary NS should wait until re-querying master after a failure (must be < Refresh)
|
|
||||||
# Expire = how long secondary NS should continue to reply to queries after master fails (> Refresh + Retry)
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".inet = {
|
|
||||||
SOA."@" = ''
|
|
||||||
ns1.uninsane.org. admin-dns.uninsane.org. (
|
|
||||||
2022122101 ; Serial
|
|
||||||
4h ; Refresh
|
|
||||||
30m ; Retry
|
|
||||||
7d ; Expire
|
|
||||||
5m) ; Negative response TTL
|
|
||||||
'';
|
|
||||||
TXT."rev" = "2022122101";
|
|
||||||
|
|
||||||
# XXX NS records must also not be CNAME
|
|
||||||
# it's best that we keep this identical, or a superset of, what org. lists as our NS.
|
|
||||||
# so, org. can specify ns2/ns3 as being to the VPN, with no mention of ns1. we provide ns1 here.
|
|
||||||
A."ns1" = "%NATIVE%";
|
|
||||||
A."ns2" = "185.157.162.178";
|
|
||||||
A."ns3" = "185.157.162.178";
|
|
||||||
A."ovpns" = "185.157.162.178";
|
|
||||||
A."native" = "%NATIVE%";
|
|
||||||
A."@" = "%NATIVE%";
|
|
||||||
NS."@" = [
|
|
||||||
"ns1.uninsane.org."
|
|
||||||
"ns2.uninsane.org."
|
|
||||||
"ns3.uninsane.org."
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".file =
|
|
||||||
"/var/lib/trust-dns/uninsane.org.zone";
|
|
||||||
|
|
||||||
systemd.services.trust-dns.preStart = let
|
|
||||||
sed = "${pkgs.gnused}/bin/sed";
|
|
||||||
zone-dir = "/var/lib/trust-dns";
|
|
||||||
zone-out = "${zone-dir}/uninsane.org.zone";
|
|
||||||
zone-template = pkgs.writeText "uninsane.org.zone.in" config.sane.services.trust-dns.generatedZones."uninsane.org";
|
|
||||||
in ''
|
|
||||||
# make WAN records available to trust-dns
|
|
||||||
mkdir -p ${zone-dir}
|
|
||||||
ip=$(cat '${config.sane.services.dyn-dns.ipPath}')
|
|
||||||
${sed} s/%NATIVE%/$ip/ ${zone-template} > ${zone-out}
|
|
||||||
'';
|
|
||||||
|
|
||||||
sane.services.dyn-dns.restartOnChange = [ "trust-dns.service" ];
|
|
||||||
}
|
|
@@ -1,31 +0,0 @@
|
|||||||
# docs: <https://nixos.wiki/wiki/MediaWiki>
|
|
||||||
{ config, lib, ... }:
|
|
||||||
|
|
||||||
# XXX: working to host wikipedia with kiwix instead of mediawiki
|
|
||||||
# mediawiki does more than i need and isn't obviously superior in any way
|
|
||||||
# except that the dumps are more frequent/up-to-date.
|
|
||||||
lib.mkIf false
|
|
||||||
{
|
|
||||||
sops.secrets."mediawiki_pw" = {
|
|
||||||
owner = config.users.users.mediawiki.name;
|
|
||||||
sopsFile = ../../../secrets/servo.yaml;
|
|
||||||
};
|
|
||||||
|
|
||||||
services.mediawiki.enable = true;
|
|
||||||
services.mediawiki.name = "Uninsane Wiki";
|
|
||||||
services.mediawiki.passwordFile = config.sops.secrets.mediawiki_pw.path;
|
|
||||||
services.mediawiki.extraConfig = ''
|
|
||||||
# Disable anonymous editing
|
|
||||||
$wgGroupPermissions['*']['edit'] = false;
|
|
||||||
'';
|
|
||||||
services.mediawiki.virtualHost.listen = [
|
|
||||||
{
|
|
||||||
ip = "127.0.0.1";
|
|
||||||
port = 8013;
|
|
||||||
ssl = false;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
services.mediawiki.virtualHost.hostName = "w.uninsane.org";
|
|
||||||
services.mediawiki.virtualHost.adminAddr = "admin+mediawiki@uninsane.org";
|
|
||||||
# services.mediawiki.extensions = TODO: wikipedia sync extension?
|
|
||||||
}
|
|
21
image.nix
Normal file
21
image.nix
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{ config, lib, pkgs, modulesPath, ... }:
|
||||||
|
{
|
||||||
|
fileSystems."/" = {
|
||||||
|
# boot by label instead of unpredictable uuid
|
||||||
|
device = "/dev/disk/by-label/nixos-img";
|
||||||
|
# make-disk-image only supports ext4
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
# fileSystems."/boot".device = "/dev/vda1";
|
||||||
|
fileSystems."/boot".device = "/dev/disk/by-label/ESP";
|
||||||
|
|
||||||
|
system.build.raw = import "${toString modulesPath}/../lib/make-disk-image.nix" {
|
||||||
|
inherit lib config pkgs;
|
||||||
|
partitionTableType = "efi";
|
||||||
|
label = "nixos-img";
|
||||||
|
fsType = config.fileSystems."/".fsType;
|
||||||
|
diskSize = "auto";
|
||||||
|
format = "raw";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
25
machines/desko/default.nix
Normal file
25
machines/desko/default.nix
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./../../helpers/universal
|
||||||
|
./../../helpers/hardware-x86_64.nix
|
||||||
|
# ./../../helpers/gui/gnome.nix
|
||||||
|
#./../../helpers/gui/i3.nix
|
||||||
|
./../../helpers/gui/sway.nix
|
||||||
|
./fs.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
home-manager.users.colin = import ./../../helpers/home-manager-gen-colin.nix {
|
||||||
|
inherit pkgs lib;
|
||||||
|
system = "x86_64-linux";
|
||||||
|
# gui = "gnome";
|
||||||
|
# gui = "i3";
|
||||||
|
gui = "sway";
|
||||||
|
extraPackages = [
|
||||||
|
pkgs.electrum
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
|
||||||
|
system.stateVersion = "21.05";
|
||||||
|
}
|
17
machines/desko/fs.nix
Normal file
17
machines/desko/fs.nix
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
fileSystems."/" = lib.mkDefault {
|
||||||
|
device = "/dev/disk/by-uuid/d969ee61-12cf-4490-be07-4440c7be593f";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [
|
||||||
|
"compress=zstd"
|
||||||
|
"defaults"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/boot" = {
|
||||||
|
device = lib.mkDefault "/dev/disk/by-uuid/F826-6192";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
}
|
18
machines/lappy/default.nix
Normal file
18
machines/lappy/default.nix
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./../../helpers/universal
|
||||||
|
./../../helpers/hardware-x86_64.nix
|
||||||
|
./../../helpers/gui/gnome.nix
|
||||||
|
./fs.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
home-manager.users.colin = import ./../../helpers/home-manager-gen-colin.nix {
|
||||||
|
inherit pkgs lib;
|
||||||
|
system = "x86_64-linux";
|
||||||
|
gui = "gnome";
|
||||||
|
};
|
||||||
|
|
||||||
|
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
|
||||||
|
system.stateVersion = "21.05";
|
||||||
|
}
|
17
machines/lappy/fs.nix
Normal file
17
machines/lappy/fs.nix
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
fileSystems."/" = lib.mkDefault {
|
||||||
|
device = "/dev/disk/by-uuid/75230e56-2c69-4e41-b03e-68475f119980";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [
|
||||||
|
"compress=zstd"
|
||||||
|
"defaults"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/boot" = {
|
||||||
|
device = lib.mkDefault "/dev/disk/by-uuid/BD79-D6BB";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
}
|
56
machines/moby/default.nix
Normal file
56
machines/moby/default.nix
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./../../helpers/universal
|
||||||
|
./../../helpers/gui/phosh.nix
|
||||||
|
# ./../../helpers/gui/plasma-mobile.nix
|
||||||
|
# ./../../helpers/gui/gnome.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
# XXX colin: phosh doesn't work well with passwordless login
|
||||||
|
users.users.colin.initialPassword = "147147";
|
||||||
|
|
||||||
|
home-manager.users.colin = import ./../../helpers/home-manager-gen-colin.nix {
|
||||||
|
inherit pkgs lib;
|
||||||
|
system = "aarch64-linux";
|
||||||
|
gui = "phosh";
|
||||||
|
extraPackages = [
|
||||||
|
# for web browsers see: https://forum.pine64.org/showthread.php?tid=13669
|
||||||
|
pkgs.angelfish # plasma mobile web browser; broken on phosh (poor wayland support)
|
||||||
|
# pkgs.plasma5Packages.index # file browser
|
||||||
|
pkgs.plasma5Packages.konsole # terminal
|
||||||
|
# pkgs.plasma5Packages.pix # picture viewer
|
||||||
|
pkgs.plasma5Packages.kalk # calculator; broken on phosh
|
||||||
|
# pkgs.plasma5Packages.buho # (plasma mobile?) note application
|
||||||
|
pkgs.plasma5Packages.kasts # podcast app; works on phosh after setting QT envar
|
||||||
|
pkgs.plasma5Packages.koko # image gallery; broken on phosh
|
||||||
|
pkgs.plasma5Packages.kwave # media player.
|
||||||
|
# pkgs.plasma5Packages.neochat # matrix client. needs qcoro => no aarch64 support
|
||||||
|
# pkgs.plasma5Packages.plasma-dialer # phone dialer
|
||||||
|
# pkgs.plasma5Packages.plasma-mobile # the whole shebang?
|
||||||
|
# pkgs.plasma5Packages.plasma-settings
|
||||||
|
pkgs.plasma5Packages.bomber # arcade game; broken on phosh
|
||||||
|
pkgs.plasma5Packages.kapman # pacman
|
||||||
|
pkgs.w3m # text-based web browser; works!
|
||||||
|
pkgs.st # suckless terminal; broken on phosh
|
||||||
|
# pkgs.alacritty # terminal; crashes phosh
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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 = "21.11"; # Did you read the comment?
|
||||||
|
|
||||||
|
# defined: https://www.freedesktop.org/software/systemd/man/machine-info.html
|
||||||
|
# XXX colin: not sure which, if any, software makes use of this
|
||||||
|
environment.etc."machine-info".text = ''
|
||||||
|
CHASSIS="handset"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# enable rotation sensor
|
||||||
|
hardware.sensor.iio.enable = true;
|
||||||
|
}
|
39
machines/uninsane/default.nix
Normal file
39
machines/uninsane/default.nix
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{ pkgs, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./../../helpers/universal
|
||||||
|
./fs.nix
|
||||||
|
./hardware.nix
|
||||||
|
./net.nix
|
||||||
|
./users.nix
|
||||||
|
./services/ddns-he.nix
|
||||||
|
./services/duplicity.nix
|
||||||
|
./services/gitea.nix
|
||||||
|
./services/jackett.nix
|
||||||
|
./services/jellyfin.nix
|
||||||
|
./services/matrix.nix
|
||||||
|
./services/nginx.nix
|
||||||
|
./services/nix-serve.nix
|
||||||
|
./services/pleroma.nix
|
||||||
|
./services/postfix.nix
|
||||||
|
./services/postgres.nix
|
||||||
|
./services/transmission.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
home-manager.users.colin = import ../../helpers/home-manager-gen-colin.nix {
|
||||||
|
inherit pkgs lib;
|
||||||
|
system = "aarch64-linux";
|
||||||
|
gui = null;
|
||||||
|
extraPackages = [ pkgs.matrix-synapse ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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 = "21.11"; # Did you read the comment?
|
||||||
|
}
|
||||||
|
|
37
machines/uninsane/fs.nix
Normal file
37
machines/uninsane/fs.nix
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
fileSystems."/" = lib.mkDefault {
|
||||||
|
device = "/dev/disk/by-uuid/2be70d38-79f4-41b6-bee2-bce5a25f8f7b";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
fileSystems."/boot" = {
|
||||||
|
device = lib.mkDefault "/dev/disk/by-uuid/B318-A67E";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
fileSystems."/var/lib/pleroma" = {
|
||||||
|
device = "/opt/pleroma";
|
||||||
|
options = [ "bind" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/var/lib/transmission/Downloads" = {
|
||||||
|
device = "/opt/uninsane/media";
|
||||||
|
options = [ "bind" ];
|
||||||
|
};
|
||||||
|
fileSystems."/var/lib/transmission/.incomplete" = {
|
||||||
|
device = "/opt/uninsane/media/incomplete";
|
||||||
|
options = [ "bind" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# in-memory compressed RAM (seems to be dynamically sized)
|
||||||
|
zramSwap = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
swapDevices = [
|
||||||
|
{ device = "/swapfile"; size = 4096; }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
94
machines/uninsane/hardware.nix
Normal file
94
machines/uninsane/hardware.nix
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
# this file originates from ‘nixos-generate-config’
|
||||||
|
# but has been heavily modified
|
||||||
|
{ config, lib, pkgs, modulesPath, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# enables non-free firmware
|
||||||
|
hardware.enableRedistributableFirmware = true;
|
||||||
|
|
||||||
|
# i changed this becuse linux 5.10 didn't have rpi-400 device tree blob.
|
||||||
|
# nixos-22.05 linux 5.15 DOES have these now.
|
||||||
|
# it should be possible to remove this if desired, but i'm not sure how the rpi-specific kernel differs.
|
||||||
|
# see: https://github.com/raspberrypi/linux
|
||||||
|
boot.kernelPackages = pkgs.linuxPackages_rpi4;
|
||||||
|
|
||||||
|
# NixOS defaults to grub: we don't want that.
|
||||||
|
boot.loader.grub.enable = false;
|
||||||
|
# raspberryPi boot loader creates extlinux.conf.
|
||||||
|
# otherwise, enable the generic-extlinux-compatible loader below.
|
||||||
|
# note: THESE ARE MUTUALLY EXCLUSIVE. generic-extlinux-compatible causes uboot to not be built
|
||||||
|
# boot.loader.generic-extlinux-compatible.enable = true;
|
||||||
|
boot.loader.raspberryPi.enable = true;
|
||||||
|
boot.loader.raspberryPi.uboot.enable = true;
|
||||||
|
boot.loader.raspberryPi.version = 4;
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [
|
||||||
|
"bcm2711_thermal"
|
||||||
|
"bcm_phy_lib"
|
||||||
|
"brcmfmac"
|
||||||
|
"brcmutil"
|
||||||
|
"broadcom"
|
||||||
|
"clk_raspberrypi"
|
||||||
|
"drm" # Direct Render Manager
|
||||||
|
"enclosure" # SCSI ?
|
||||||
|
"fuse"
|
||||||
|
"mdio_bcm_unimac"
|
||||||
|
"pcie_brcmstb"
|
||||||
|
"raspberrypi_cpufreq"
|
||||||
|
"raspberrypi_hwmon"
|
||||||
|
"ses" # SCSI Enclosure Services
|
||||||
|
"uas" # USB attached storage
|
||||||
|
"uio" # userspace IO
|
||||||
|
"uio_pdrv_genirq"
|
||||||
|
"xhci_pci"
|
||||||
|
"xhci_pci_renesas"
|
||||||
|
];
|
||||||
|
# boot.initrd.compressor = "gzip"; # defaults to zstd
|
||||||
|
# hack in the `boot.shell_on_fail` arg since it doesn't seem to work otherwise
|
||||||
|
boot.initrd.preFailCommands = "allowShell=1";
|
||||||
|
# default: 4 (warn). 7 is debug
|
||||||
|
boot.consoleLogLevel = 7;
|
||||||
|
# boot.kernelParams = [
|
||||||
|
# "boot.shell_on_fail"
|
||||||
|
# # "boot.trace"
|
||||||
|
# # "systemd.log_level=debug"
|
||||||
|
# # "systemd.log_target=console"
|
||||||
|
# ];
|
||||||
|
|
||||||
|
# ondemand power scaling keeps the cpu at low frequency when idle, and sets to max frequency
|
||||||
|
# when load is detected. (v.s. the "performance" default, which always uses the max frequency)
|
||||||
|
powerManagement.cpuFreqGovernor = "ondemand";
|
||||||
|
|
||||||
|
# XXX colin: this allows one to `systemctl halt` and then not remove power until the HDD has spun down.
|
||||||
|
# however, it doesn't work with reboot because systemd will spin the drive up again to read its reboot bin.
|
||||||
|
# a better solution would be to put the drive behind a powered USB hub (or get a SSD).
|
||||||
|
# systemd.services.diskguard = {
|
||||||
|
# description = "Safely power off spinning media";
|
||||||
|
# before = [ "shutdown.target" ];
|
||||||
|
# wantedBy = [ "sysinit.target" ];
|
||||||
|
# # old (creates dep loop, but works)
|
||||||
|
# # before = [ "systemd-remount-fs.service" "shutdown.target" ];
|
||||||
|
# # wantedBy = [ "systemd-remount-fs.service" ];
|
||||||
|
# serviceConfig = {
|
||||||
|
# Type = "oneshot";
|
||||||
|
# RemainAfterExit = true;
|
||||||
|
# ExecStart = "${pkgs.coreutils}/bin/true";
|
||||||
|
# ExecStop = with pkgs; writeScript "diskguard" ''
|
||||||
|
# #!${bash}/bin/bash
|
||||||
|
# if ${procps}/bin/pgrep nixos-rebuild ;
|
||||||
|
# then
|
||||||
|
# exit 0 # don't halt drives unless we're actually shutting down. maybe better way to do this (check script args?)
|
||||||
|
# fi
|
||||||
|
# # ${coreutils}/bin/sync
|
||||||
|
# # ${util-linux}/bin/mount -o remount,ro /nix/store
|
||||||
|
# # ${util-linux}/bin/mount -o remount,ro /
|
||||||
|
# # -S 1 retracts the spindle after 5 seconds of idle
|
||||||
|
# # -B 1 spins down the drive after <vendor specific duration>
|
||||||
|
# ${hdparm}/sbin/hdparm -S 1 -B 1 /dev/sda
|
||||||
|
# # TODO: monitor smartmonctl until disk is idle? or try hdparm -Y
|
||||||
|
# # ${coreutils}/bin/sleep 20
|
||||||
|
# # exec ${util-linux}/bin/umount --all -t ext4,vfat,ext2
|
||||||
|
# '';
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
}
|
132
machines/uninsane/net.nix
Normal file
132
machines/uninsane/net.nix
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
{ config, pkgs, secrets, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
networking.domain = "uninsane.org";
|
||||||
|
|
||||||
|
# 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
|
||||||
|
# replicates the default behaviour.
|
||||||
|
networking.useDHCP = false;
|
||||||
|
networking.interfaces.eth0.useDHCP = true;
|
||||||
|
# XXX colin: probably don't need this. wlan0 won't be populated unless i touch a value in networking.interfaces.wlan0
|
||||||
|
networking.wireless.enable = false;
|
||||||
|
|
||||||
|
# networking.firewall.enable = false;
|
||||||
|
networking.firewall.enable = true;
|
||||||
|
networking.firewall.allowedTCPPorts = [
|
||||||
|
25 # SMTP
|
||||||
|
80 # HTTP
|
||||||
|
143 # IMAP
|
||||||
|
443 # HTTPS
|
||||||
|
465 # SMTPS (maybe not required?)
|
||||||
|
587 # SMTPS/submission (maybe not required?)
|
||||||
|
993 # IMAPS
|
||||||
|
];
|
||||||
|
# DLNA ports: https://jellyfin.org/docs/general/networking/index.html
|
||||||
|
networking.firewall.allowedUDPPorts = [ 1900 7359 ];
|
||||||
|
|
||||||
|
# we need to use externally-visible nameservers in order for VPNs to be able to resolve hosts.
|
||||||
|
networking.nameservers = [
|
||||||
|
"1.1.1.1"
|
||||||
|
"9.9.9.9"
|
||||||
|
];
|
||||||
|
|
||||||
|
# OVPN CONFIG (https://www.ovpn.com):
|
||||||
|
# DOCS: https://nixos.wiki/wiki/WireGuard
|
||||||
|
networking.wireguard.enable = true;
|
||||||
|
networking.wireguard.interfaces.wg0 = {
|
||||||
|
privateKey = secrets.wireguard.privateKey;
|
||||||
|
# wg is active only in this namespace.
|
||||||
|
# run e.g. ip netns exec ovpns <some command like ping/curl/etc, it'll go through wg>
|
||||||
|
# sudo ip netns exec ovpns ping www.google.com
|
||||||
|
# note: without the namespace, you'll need to add a specific route through eth0 for the peer (185.157.162.178/32)
|
||||||
|
interfaceNamespace = "ovpns";
|
||||||
|
preSetup = "${pkgs.iproute2}/bin/ip netns add ovpns || true";
|
||||||
|
postShutdown = "${pkgs.iproute2}/bin/ip netns delete ovpns";
|
||||||
|
ips = [
|
||||||
|
"185.157.162.178/32"
|
||||||
|
];
|
||||||
|
peers = [
|
||||||
|
{
|
||||||
|
publicKey = "SkkEZDCBde22KTs/Hc7FWvDBfdOCQA4YtBEuC3n5KGs=";
|
||||||
|
endpoint = "vpn36.prd.amsterdam.ovpn.com:9930";
|
||||||
|
allowedIPs = [ "0.0.0.0/0" ];
|
||||||
|
# nixOS says this is important for keeping NATs active
|
||||||
|
persistentKeepalive = 25;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.wg0veth = {
|
||||||
|
description = "veth pair to allow communication between host and wg0 netns";
|
||||||
|
after = [ "wireguard-wg0.service" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
|
||||||
|
ExecStart = with pkgs; writeScript "wg0veth-start" ''
|
||||||
|
#!${bash}/bin/bash
|
||||||
|
# create veth pair
|
||||||
|
${iproute2}/bin/ip link add ovpns-veth-a type veth peer name ovpns-veth-b
|
||||||
|
${iproute2}/bin/ip addr add 10.0.1.5/24 dev ovpns-veth-a
|
||||||
|
${iproute2}/bin/ip link set ovpns-veth-a up
|
||||||
|
# mv veth-b into the ovpns namespace
|
||||||
|
${iproute2}/bin/ip link set ovpns-veth-b netns ovpns
|
||||||
|
${iproute2}/bin/ip -n ovpns addr add 10.0.1.6/24 dev ovpns-veth-b
|
||||||
|
${iproute2}/bin/ip -n ovpns link set ovpns-veth-b up
|
||||||
|
# forward HTTP traffic, which we need for letsencrypt to work
|
||||||
|
${iproute2}/bin/ip netns exec ovpns ${socat}/bin/socat TCP4-LISTEN:80,reuseaddr,fork,su=nobody TCP4:10.0.1.5:80 &
|
||||||
|
'';
|
||||||
|
|
||||||
|
ExecStop = with pkgs; writeScript "wg0veth-stop" ''
|
||||||
|
#!${bash}/bin/bash
|
||||||
|
${iproute2}/bin/ip -n wg0 link del ovpns-veth-b
|
||||||
|
${iproute2}/bin/ip link del ovpns-veth-a
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# HURRICANE ELECTRIC CONFIG:
|
||||||
|
# networking.sits = {
|
||||||
|
# hurricane = {
|
||||||
|
# remote = "216.218.226.238";
|
||||||
|
# local = "192.168.0.5";
|
||||||
|
# # local = "10.0.0.5";
|
||||||
|
# # remote = "10.0.0.1";
|
||||||
|
# # local = "10.0.0.22";
|
||||||
|
# dev = "eth0";
|
||||||
|
# ttl = 255;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# networking.interfaces."hurricane".ipv6 = {
|
||||||
|
# addresses = [
|
||||||
|
# # mx.uninsane.org (publically routed /64)
|
||||||
|
# {
|
||||||
|
# address = "2001:470:b:465::1";
|
||||||
|
# prefixLength = 128;
|
||||||
|
# }
|
||||||
|
# # client addr
|
||||||
|
# # {
|
||||||
|
# # address = "2001:470:a:466::2";
|
||||||
|
# # prefixLength = 64;
|
||||||
|
# # }
|
||||||
|
# ];
|
||||||
|
# routes = [
|
||||||
|
# {
|
||||||
|
# address = "::";
|
||||||
|
# prefixLength = 0;
|
||||||
|
# # via = "2001:470:a:466::1";
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
|
||||||
|
# # after configuration, we want the hurricane device to look like this:
|
||||||
|
# # hurricane: flags=209<UP,POINTOPOINT,RUNNING,NOARP> mtu 1480
|
||||||
|
# # inet6 2001:470:a:450::2 prefixlen 64 scopeid 0x0<global>
|
||||||
|
# # inet6 fe80::c0a8:16 prefixlen 64 scopeid 0x20<link>
|
||||||
|
# # sit txqueuelen 1000 (IPv6-in-IPv4)
|
||||||
|
# # test with:
|
||||||
|
# # curl --interface hurricane http://[2607:f8b0:400a:80b::2004]
|
||||||
|
# # ping 2607:f8b0:400a:80b::2004
|
||||||
|
}
|
20
machines/uninsane/services/ddns-he.nix
Normal file
20
machines/uninsane/services/ddns-he.nix
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{ pkgs, secrets, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
systemd.services.ddns-he = {
|
||||||
|
description = "update dynamic DNS entries for HurricaneElectric";
|
||||||
|
# HE DDNS API is documented: https://dns.he.net/docs.html
|
||||||
|
script = let
|
||||||
|
pass = secrets.ddns-he.password;
|
||||||
|
crl = "${pkgs.curl}/bin/curl -4";
|
||||||
|
in ''
|
||||||
|
${crl} "https://he.uninsane.org:${pass}@dyn.dns.he.net/nic/update?hostname=he.uninsane.org"
|
||||||
|
${crl} "https://native.uninsane.org:${pass}@dyn.dns.he.net/nic/update?hostname=native.uninsane.org"
|
||||||
|
${crl} "https://uninsane.org:${pass}@dyn.dns.he.net/nic/update?hostname=uninsane.org"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
systemd.timers.ddns-he.timerConfig = {
|
||||||
|
OnStartupSec = "2min";
|
||||||
|
OnUnitActiveSec = "10min";
|
||||||
|
};
|
||||||
|
}
|
36
machines/uninsane/services/duplicity.nix
Normal file
36
machines/uninsane/services/duplicity.nix
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# docs: https://search.nixos.org/options?channel=21.11&query=duplicity
|
||||||
|
{ config, pkgs, lib, secrets, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
services.duplicity.enable = true;
|
||||||
|
services.duplicity.targetUrl = secrets.duplicity.url;
|
||||||
|
# format: PASSPHRASE=<cleartext>
|
||||||
|
# two sisters
|
||||||
|
services.duplicity.secretFile =
|
||||||
|
builtins.toFile "duplicity_env" "PASSPHRASE=${secrets.duplicity.passphrase}";
|
||||||
|
# NB: manually trigger with `systemctl start duplicity`
|
||||||
|
services.duplicity.frequency = "daily";
|
||||||
|
services.duplicity.exclude = [
|
||||||
|
# impermanent/inconsequential data:
|
||||||
|
"/dev"
|
||||||
|
"/proc"
|
||||||
|
"/run"
|
||||||
|
"/sys"
|
||||||
|
"/tmp"
|
||||||
|
# bind mounted (dupes):
|
||||||
|
"/var/lib/pleroma"
|
||||||
|
"/var/lib/transmission/Downloads"
|
||||||
|
"/var/lib/transmission/.incomplete"
|
||||||
|
# data that's not worth the cost to backup:
|
||||||
|
"/opt/uninsane/media"
|
||||||
|
];
|
||||||
|
|
||||||
|
services.duplicity.extraFlags = [
|
||||||
|
# without --allow-source-mismatch, duplicity will abort if you change the hostname between backups
|
||||||
|
"--allow-source-mismatch"
|
||||||
|
];
|
||||||
|
|
||||||
|
# set this for the FIRST backup, then remove it to enable incremental backups
|
||||||
|
# (that the first backup *isn't* full i think is a defect)
|
||||||
|
# services.duplicity.fullIfOlderThan = "always";
|
||||||
|
}
|
@@ -1,10 +1,6 @@
|
|||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
# TODO: mode? could be more granular
|
|
||||||
{ user = "git"; group = "gitea"; directory = "/var/lib/gitea"; }
|
|
||||||
];
|
|
||||||
services.gitea.enable = true;
|
services.gitea.enable = true;
|
||||||
services.gitea.user = "git"; # default is 'gitea'
|
services.gitea.user = "git"; # default is 'gitea'
|
||||||
services.gitea.database.type = "postgres";
|
services.gitea.database.type = "postgres";
|
||||||
@@ -12,7 +8,7 @@
|
|||||||
services.gitea.appName = "Perfectly Sane Git";
|
services.gitea.appName = "Perfectly Sane Git";
|
||||||
services.gitea.domain = "git.uninsane.org";
|
services.gitea.domain = "git.uninsane.org";
|
||||||
services.gitea.rootUrl = "https://git.uninsane.org/";
|
services.gitea.rootUrl = "https://git.uninsane.org/";
|
||||||
services.gitea.settings.session.COOKIE_SECURE = true;
|
services.gitea.cookieSecure = true;
|
||||||
# services.gitea.disableRegistration = true;
|
# services.gitea.disableRegistration = true;
|
||||||
|
|
||||||
services.gitea.settings = {
|
services.gitea.settings = {
|
||||||
@@ -59,7 +55,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
# options: "Trace", "Debug", "Info", "Warn", "Error", "Critical"
|
# options: "Trace", "Debug", "Info", "Warn", "Error", "Critical"
|
||||||
services.gitea.settings.log.LEVEL = "Warn";
|
services.gitea.log.level = "Info";
|
||||||
|
|
||||||
systemd.services.gitea.serviceConfig = {
|
systemd.services.gitea.serviceConfig = {
|
||||||
# nix default is AF_UNIX AF_INET AF_INET6.
|
# nix default is AF_UNIX AF_INET AF_INET6.
|
||||||
@@ -71,18 +67,4 @@
|
|||||||
"/var/lib/gitea"
|
"/var/lib/gitea"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# hosted git (web view and for `git <cmd>` use
|
|
||||||
# TODO: enable publog?
|
|
||||||
services.nginx.virtualHosts."git.uninsane.org" = {
|
|
||||||
forceSSL = true; # gitea complains if served over a different protocol than its config file says
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
|
|
||||||
locations."/" = {
|
|
||||||
proxyPass = "http://127.0.0.1:3000";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."git" = "native";
|
|
||||||
}
|
}
|
14
machines/uninsane/services/jackett.nix
Normal file
14
machines/uninsane/services/jackett.nix
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
services.jackett.enable = true;
|
||||||
|
|
||||||
|
systemd.services.jackett.after = ["wg0veth.service"];
|
||||||
|
systemd.services.jackett.serviceConfig = {
|
||||||
|
# run this behind the OVPN static VPN
|
||||||
|
NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
|
# patch jackett to listen on the public interfaces
|
||||||
|
# ExecStart = lib.mkForce "${pkgs.jackett}/bin/Jackett --NoUpdates --DataFolder /var/lib/jackett/.config/Jackett --ListenPublic";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
5
machines/uninsane/services/jellyfin.nix
Normal file
5
machines/uninsane/services/jellyfin.nix
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
services.jellyfin.enable = true;
|
||||||
|
}
|
175
machines/uninsane/services/matrix.nix
Normal file
175
machines/uninsane/services/matrix.nix
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
# docs: https://nixos.wiki/wiki/Matrix
|
||||||
|
# docs: https://nixos.org/manual/nixos/stable/index.html#module-services-matrix-synapse
|
||||||
|
{ config, pkgs, lib, secrets, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
services.matrix-synapse.enable = true;
|
||||||
|
services.matrix-synapse.settings.server_name = "uninsane.org";
|
||||||
|
|
||||||
|
# services.matrix-synapse.enable_registration_captcha = true;
|
||||||
|
# services.matrix-synapse.enable_registration_without_verification = true;
|
||||||
|
services.matrix-synapse.settings.enable_registration = true;
|
||||||
|
# services.matrix-synapse.registration_shared_secret = "<shared key goes here>";
|
||||||
|
|
||||||
|
# default for listeners is port = 8448, tls = true, x_forwarded = false.
|
||||||
|
# we change this because the server is situated behind nginx.
|
||||||
|
services.matrix-synapse.settings.listeners = [
|
||||||
|
{
|
||||||
|
port = 8008;
|
||||||
|
bind_addresses = [ "127.0.0.1" ];
|
||||||
|
type = "http";
|
||||||
|
tls = false;
|
||||||
|
x_forwarded = true;
|
||||||
|
resources = [
|
||||||
|
{
|
||||||
|
names = [ "client" "federation" ];
|
||||||
|
compress = false;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# services.matrix-synapse.extraConfig = ''
|
||||||
|
# registration_requires_token: true
|
||||||
|
# admin_contact: "admin.matrix@uninsane.org"
|
||||||
|
# '';
|
||||||
|
|
||||||
|
services.matrix-synapse.settings.admin_contact = "admin.matrix@uninsane.org";
|
||||||
|
services.matrix-synapse.settings.registrations_require_3pid = [ "email" ];
|
||||||
|
services.matrix-synapse.settings.email = {
|
||||||
|
smtp_host = "mx.uninsane.org";
|
||||||
|
smtp_port = 587;
|
||||||
|
smtp_user = "matrix-synapse";
|
||||||
|
smtp_pass = secrets.matrix-synapse.smtp_pass;
|
||||||
|
require_transport_security = true;
|
||||||
|
enable_tls = true;
|
||||||
|
notif_from = "%(app)s <notify.matrix@uninsane.org>";
|
||||||
|
app_name = "Uninsane Matrix";
|
||||||
|
enable_notifs = true;
|
||||||
|
validation_token_lifetime = "96h";
|
||||||
|
invite_client_location = "https://web.matrix.uninsane.org";
|
||||||
|
subjects = {
|
||||||
|
email_validation = "[%(server_name)s] Validate your email";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# services.matrix-synapse.extraConfigFiles = [builtins.toFile "matrix-synapse-extra-config" ''
|
||||||
|
# admin_contact: "admin.matrix@uninsane.org"
|
||||||
|
# registrations_require_3pid:
|
||||||
|
# - email
|
||||||
|
# email:
|
||||||
|
# smtp_host: "mx.uninsane.org"
|
||||||
|
# smtp_port: 587
|
||||||
|
# smtp_user: "matrix-synapse"
|
||||||
|
# smtp_pass: "${secrets.matrix-synapse.smtp_pass}"
|
||||||
|
# require_transport_security: true
|
||||||
|
# enable_tls: true
|
||||||
|
# notif_from: "%(app)s <notify.matrix@uninsane.org>"
|
||||||
|
# app_name: "Uninsane Matrix"
|
||||||
|
# enable_notifs: true
|
||||||
|
# validation_token_lifetime: 96h
|
||||||
|
# invite_client_location: "https://web.matrix.uninsane.org"
|
||||||
|
# subjects:
|
||||||
|
# email_validation: "[%(server_name)s] Validate your email"
|
||||||
|
# ''];
|
||||||
|
services.matrix-synapse.settings.app_service_config_files = [
|
||||||
|
"/var/lib/matrix-appservice-irc/registration.yml" # auto-created by irc appservice
|
||||||
|
];
|
||||||
|
|
||||||
|
# new users may be registered on the CLI:
|
||||||
|
# register_new_matrix_user -c /nix/store/8n6kcka37jhmi4qpd2r03aj71pkyh21s-homeserver.yaml http://localhost:8008
|
||||||
|
#
|
||||||
|
# or provide an registration token then can use to register through the client.
|
||||||
|
# docs: https://github.com/matrix-org/synapse/blob/develop/docs/usage/administration/admin_api/registration_tokens.md
|
||||||
|
# first, grab your own user's access token (Help & About section in Element). then:
|
||||||
|
# curl --header "Authorization: Bearer <my_token>" localhost:8008/_synapse/admin/v1/registration_tokens
|
||||||
|
# create a token with unlimited uses:
|
||||||
|
# curl -d '{}' --header "Authorization: Bearer <my_token>" localhost:8008/_synapse/admin/v1/registration_tokens/new
|
||||||
|
# create a token with limited uses:
|
||||||
|
# curl -d '{ "uses_allowed": 1 }' --header "Authorization: Bearer <my_token>" localhost:8008/_synapse/admin/v1/registration_tokens/new
|
||||||
|
|
||||||
|
# IRC bridging
|
||||||
|
# note: Rizon allows only FOUR simultaneous IRC connections per IP: https://wiki.rizon.net/index.php?title=Connection/Session_Limit_Exemptions
|
||||||
|
# Rizon supports CertFP for auth: https://wiki.rizon.net/index.php?title=CertFP
|
||||||
|
# services.matrix-appservice-irc.enable = true;
|
||||||
|
services.matrix-appservice-irc.registrationUrl = "http://127.0.0.1:8009";
|
||||||
|
# settings documented here: https://github.com/matrix-org/matrix-appservice-irc/blob/develop/config.sample.yaml
|
||||||
|
services.matrix-appservice-irc.settings = {
|
||||||
|
homeserver = {
|
||||||
|
url = "http://127.0.0.1:8008";
|
||||||
|
dropMatrixMessagesAfterSecs = 300;
|
||||||
|
domain = "uninsane.org";
|
||||||
|
enablePresence = true;
|
||||||
|
bindPort = 9999;
|
||||||
|
bindHost = "127.0.0.1";
|
||||||
|
};
|
||||||
|
|
||||||
|
ircService = {
|
||||||
|
servers = {
|
||||||
|
"irc.rizon.net" = {
|
||||||
|
name = "Rizon";
|
||||||
|
port = 6697; # SSL port
|
||||||
|
ssl = true;
|
||||||
|
sasl = true; # appservice doesn't support NickServ identification
|
||||||
|
botConfig = {
|
||||||
|
# bot has no presence in IRC channel; only real Matrix users
|
||||||
|
enabled = false;
|
||||||
|
# nick = "UninsaneDotOrg";
|
||||||
|
nick = "uninsane";
|
||||||
|
username = "uninsane";
|
||||||
|
};
|
||||||
|
dynamicChannels = {
|
||||||
|
enabled = true;
|
||||||
|
aliasTemplate = "#irc_rizon_$CHANNEL";
|
||||||
|
};
|
||||||
|
ircClients = {
|
||||||
|
nickTemplate = "$LOCALPARTsane";
|
||||||
|
# by default, Matrix will convert messages greater than (3) lines into a pastebin-like URL to send to IRC.
|
||||||
|
lineLimit = 20;
|
||||||
|
};
|
||||||
|
matrixClients = {
|
||||||
|
userTemplate = "@irc_rizon_$NICK"; # the :uninsane.org part is appended automatically
|
||||||
|
};
|
||||||
|
|
||||||
|
# this will let this user message the appservice with `!join #<IRCChannel>` and the rest "Just Works"
|
||||||
|
"@colin:uninsane.org" = "admin";
|
||||||
|
|
||||||
|
membershipLists = {
|
||||||
|
enabled = true;
|
||||||
|
global = {
|
||||||
|
ircToMatrix = {
|
||||||
|
initial = true;
|
||||||
|
incremental = true;
|
||||||
|
requireMatrixJoined = false;
|
||||||
|
};
|
||||||
|
matrixToIrc = {
|
||||||
|
initial = true;
|
||||||
|
incremental = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
# sync room description?
|
||||||
|
bridgeInfoState = {
|
||||||
|
enabled = true;
|
||||||
|
initial = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# hardcoded mappings, for when dynamicChannels fails us. TODO: probably safe to remove these.
|
||||||
|
# mappings = {
|
||||||
|
# "#chat" = {
|
||||||
|
# roomIds = [ "!GXJSOTdbtxRboGtDep:uninsane.org" ];
|
||||||
|
# };
|
||||||
|
# # BakaBT requires account registration, which i think means my user needs to be added before the appservice user
|
||||||
|
# "#BakaBT" = {
|
||||||
|
# roomIds = [ "!feZKttuYuHilqPFSkD:uninsane.org" ];
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# for per-user IRC password:
|
||||||
|
# invite @irc_rizon_NickServ:uninsane.org to a DM and type `help` => register
|
||||||
|
# invite the matrix-appservice-irc user to a DM and type `!help` => add PW to database
|
||||||
|
# passwordEncryptionKeyPath = "/path/to/privkey"; # appservice will generate its own if unspecified
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
237
machines/uninsane/services/nginx.nix
Normal file
237
machines/uninsane/services/nginx.nix
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
# docs: https://nixos.wiki/wiki/Nginx
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
services.nginx.enable = true;
|
||||||
|
|
||||||
|
# web blog/personal site
|
||||||
|
services.nginx.virtualHosts."uninsane.org" = {
|
||||||
|
root = "/opt/uninsane/root";
|
||||||
|
addSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
|
||||||
|
# allow matrix users to discover that @user:uninsane.org is reachable via matrix.uninsane.org
|
||||||
|
locations."= /.well-known/matrix/server".extraConfig =
|
||||||
|
let
|
||||||
|
# use 443 instead of the default 8448 port to unite
|
||||||
|
# the client-server and server-server port for simplicity
|
||||||
|
server = { "m.server" = "matrix.uninsane.org:443"; };
|
||||||
|
in ''
|
||||||
|
add_header Content-Type application/json;
|
||||||
|
return 200 '${builtins.toJSON server}';
|
||||||
|
'';
|
||||||
|
locations."= /.well-known/matrix/client".extraConfig =
|
||||||
|
let
|
||||||
|
client = {
|
||||||
|
"m.homeserver" = { "base_url" = "https://matrix.uninsane.org"; };
|
||||||
|
"m.identity_server" = { "base_url" = "https://vector.im"; };
|
||||||
|
};
|
||||||
|
# ACAO required to allow element-web on any URL to request this json file
|
||||||
|
in ''
|
||||||
|
add_header Content-Type application/json;
|
||||||
|
add_header Access-Control-Allow-Origin *;
|
||||||
|
return 200 '${builtins.toJSON client}';
|
||||||
|
'';
|
||||||
|
|
||||||
|
# static URLs might not be aware of .well-known (e.g. registration confirmation URLs),
|
||||||
|
# so hack around that.
|
||||||
|
locations."/_matrix" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8008";
|
||||||
|
};
|
||||||
|
locations."/_synapse" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8008";
|
||||||
|
};
|
||||||
|
|
||||||
|
# allow ActivityPub clients to discover how to reach @user@uninsane.org
|
||||||
|
# TODO: waiting on https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3361/
|
||||||
|
# locations."/.well-known/nodeinfo" = {
|
||||||
|
# proxyPass = "http://127.0.0.1:4000";
|
||||||
|
# extraConfig = pleromaExtraConfig;
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
|
||||||
|
# Pleroma server and web interface
|
||||||
|
services.nginx.virtualHosts."fed.uninsane.org" = {
|
||||||
|
addSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:4000";
|
||||||
|
# documented: https://git.pleroma.social/pleroma/pleroma/-/blob/develop/installation/pleroma.nginx
|
||||||
|
extraConfig = ''
|
||||||
|
# XXX colin: this block is in the nixos examples: i don't understand all of it
|
||||||
|
add_header 'Access-Control-Allow-Origin' '*' always;
|
||||||
|
add_header 'Access-Control-Allow-Methods' 'POST, PUT, DELETE, GET, PATCH, OPTIONS' always;
|
||||||
|
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Idempotency-Key' always;
|
||||||
|
add_header 'Access-Control-Expose-Headers' 'Link, X-RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-Request-Id' always;
|
||||||
|
if ($request_method = OPTIONS) {
|
||||||
|
return 204;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header X-Permitted-Cross-Domain-Policies none;
|
||||||
|
add_header X-Frame-Options DENY;
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header Referrer-Policy same-origin;
|
||||||
|
add_header X-Download-Options noopen;
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
# proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
||||||
|
# colin: added this due to Pleroma complaining in its logs
|
||||||
|
# proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
client_max_body_size 16m;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# transmission web client
|
||||||
|
services.nginx.virtualHosts."bt.uninsane.org" = {
|
||||||
|
# basicAuth is literally cleartext user/pw, so FORCE this to happen over SSL
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
locations."/" = {
|
||||||
|
# proxyPass = "http://ovpns.uninsane.org:9091";
|
||||||
|
proxyPass = "http://10.0.1.6:9091";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# jackett torrent search
|
||||||
|
services.nginx.virtualHosts."jackett.uninsane.org" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
locations."/" = {
|
||||||
|
# proxyPass = "http://ovpns.uninsane.org:9117";
|
||||||
|
proxyPass = "http://10.0.1.6:9117";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# matrix chat server
|
||||||
|
services.nginx.virtualHosts."matrix.uninsane.org" = {
|
||||||
|
addSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
|
||||||
|
# TODO colin: replace this with something helpful to the viewer
|
||||||
|
# locations."/".extraConfig = ''
|
||||||
|
# return 404;
|
||||||
|
# '';
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8008";
|
||||||
|
};
|
||||||
|
# redirect browsers to the web client.
|
||||||
|
# i don't think native matrix clients ever fetch the root.
|
||||||
|
# ideally this would be put behind some user-agent test though.
|
||||||
|
locations."= /" = {
|
||||||
|
return = "301 https://web.matrix.uninsane.org";
|
||||||
|
};
|
||||||
|
|
||||||
|
# locations."/_matrix" = {
|
||||||
|
# proxyPass = "http://127.0.0.1:8008";
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
|
||||||
|
# matrix web client
|
||||||
|
# docs: https://nixos.org/manual/nixos/stable/index.html#module-services-matrix-element-web
|
||||||
|
services.nginx.virtualHosts."web.matrix.uninsane.org" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
|
||||||
|
root = pkgs.element-web.override {
|
||||||
|
conf = {
|
||||||
|
default_server_config."m.homeserver" = {
|
||||||
|
"base_url" = "https://matrix.uninsane.org";
|
||||||
|
"server_name" = "uninsane.org";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# hosted git (web view and for `git <cmd>` use
|
||||||
|
services.nginx.virtualHosts."git.uninsane.org" = {
|
||||||
|
addSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:3000";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Jellyfin multimedia server
|
||||||
|
# this is mostly taken from the official jellfin.org docs
|
||||||
|
services.nginx.virtualHosts."jelly.uninsane.org" = {
|
||||||
|
addSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8096";
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Protocol $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Host $http_host;
|
||||||
|
|
||||||
|
# Disable buffering when the nginx proxy gets very resource heavy upon streaming
|
||||||
|
proxy_buffering off;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
# locations."/web/" = {
|
||||||
|
# proxyPass = "http://127.0.0.1:8096/web/index.html";
|
||||||
|
# extraConfig = ''
|
||||||
|
# proxy_set_header Host $host;
|
||||||
|
# proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
# proxy_set_header X-Forwarded-Protocol $scheme;
|
||||||
|
# proxy_set_header X-Forwarded-Host $http_host;
|
||||||
|
# '';
|
||||||
|
# };
|
||||||
|
locations."/socket" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8096";
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Protocol $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Host $http_host;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# exists only to manage certs for dovecot
|
||||||
|
services.nginx.virtualHosts."imap.uninsane.org" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
};
|
||||||
|
# exists only to manage certs for Postfix
|
||||||
|
services.nginx.virtualHosts."mx.uninsane.org" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
};
|
||||||
|
services.nginx.virtualHosts."nixcache.uninsane.org" = {
|
||||||
|
addSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# serverAliases = [ "nixcache" ];
|
||||||
|
locations."/".extraConfig = ''
|
||||||
|
proxy_pass http://localhost:${toString config.services.nix-serve.port};
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
security.acme.acceptTerms = true;
|
||||||
|
security.acme.defaults.email = "admin.acme@uninsane.org";
|
||||||
|
}
|
12
machines/uninsane/services/nix-serve.nix
Normal file
12
machines/uninsane/services/nix-serve.nix
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# docs: https://nixos.wiki/wiki/Binary_Cache
|
||||||
|
# to copy something to this machine's nix cache, do:
|
||||||
|
# nix copy --to ssh://nixcache.uninsane.org PACKAGE
|
||||||
|
{ secrets, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
services.nix-serve = {
|
||||||
|
enable = true;
|
||||||
|
secretKeyFile = builtins.toFile "nix-serve-priv-key.pem" secrets.nix-serve.cache-priv-key;
|
||||||
|
# "/var/cache-priv-key.pem";
|
||||||
|
};
|
||||||
|
}
|
@@ -1,27 +1,22 @@
|
|||||||
# docs:
|
# docs: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/pleroma.nix
|
||||||
# - https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/pleroma.nix
|
|
||||||
# - https://docs.pleroma.social/backend/configuration/cheatsheet/
|
|
||||||
#
|
#
|
||||||
# to run it in a oci-container: https://github.com/barrucadu/nixfiles/blob/master/services/pleroma.nix
|
# to run it in a oci-container: https://github.com/barrucadu/nixfiles/blob/master/services/pleroma.nix
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, lib, secrets, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
# TODO: mode? could be more granular
|
|
||||||
{ user = "pleroma"; group = "pleroma"; directory = "/var/lib/pleroma"; }
|
|
||||||
];
|
|
||||||
services.pleroma.enable = true;
|
services.pleroma.enable = true;
|
||||||
services.pleroma.secretConfigFile = config.sops.secrets.pleroma_secrets.path;
|
# TODO: we should write a config file somewhere outside the store... somehow.
|
||||||
|
services.pleroma.secretConfigFile = "/dev/null";
|
||||||
services.pleroma.configs = [
|
services.pleroma.configs = [
|
||||||
''
|
''
|
||||||
import Config
|
import Config
|
||||||
|
|
||||||
config :pleroma, Pleroma.Web.Endpoint,
|
config :pleroma, Pleroma.Web.Endpoint,
|
||||||
url: [host: "fed.uninsane.org", scheme: "https", port: 443],
|
url: [host: "fed.uninsane.org", scheme: "https", port: 443],
|
||||||
http: [ip: {127, 0, 0, 1}, port: 4000]
|
http: [ip: {127, 0, 0, 1}, port: 4000],
|
||||||
# secret_key_base: "{secrets.pleroma.secret_key_base}",
|
secret_key_base: "${secrets.pleroma.secret_key_base}",
|
||||||
# signing_salt: "{secrets.pleroma.signing_salt}"
|
signing_salt: "${secrets.pleroma.signing_salt}"
|
||||||
|
|
||||||
config :pleroma, :instance,
|
config :pleroma, :instance,
|
||||||
name: "Perfectly Sane",
|
name: "Perfectly Sane",
|
||||||
description: "Single-user Pleroma instance",
|
description: "Single-user Pleroma instance",
|
||||||
@@ -47,40 +42,36 @@
|
|||||||
enabled: false,
|
enabled: false,
|
||||||
redirect_on_failure: true
|
redirect_on_failure: true
|
||||||
#base_url: "https://cache.pleroma.social"
|
#base_url: "https://cache.pleroma.social"
|
||||||
|
|
||||||
# see for reference:
|
|
||||||
# - `force_custom_plan`: <https://docs.pleroma.social/backend/configuration/postgresql/#disable-generic-query-plans>
|
|
||||||
config :pleroma, Pleroma.Repo,
|
config :pleroma, Pleroma.Repo,
|
||||||
adapter: Ecto.Adapters.Postgres,
|
adapter: Ecto.Adapters.Postgres,
|
||||||
username: "pleroma",
|
username: "pleroma",
|
||||||
|
password: "${secrets.pleroma.db_password}",
|
||||||
database: "pleroma",
|
database: "pleroma",
|
||||||
hostname: "localhost",
|
hostname: "localhost",
|
||||||
pool_size: 10,
|
pool_size: 10,
|
||||||
|
prepare: :named,
|
||||||
parameters: [
|
parameters: [
|
||||||
plan_cache_mode: "force_custom_plan"
|
plan_cache_mode: "force_custom_plan"
|
||||||
]
|
]
|
||||||
# XXX: prepare: :named is needed only for PG <= 12
|
|
||||||
# prepare: :named,
|
|
||||||
# password: "{secrets.pleroma.db_password}",
|
|
||||||
|
|
||||||
# Configure web push notifications
|
# Configure web push notifications
|
||||||
config :web_push_encryption, :vapid_details,
|
config :web_push_encryption, :vapid_details,
|
||||||
subject: "mailto:notify.pleroma@uninsane.org"
|
subject: "mailto:notify.pleroma@uninsane.org",
|
||||||
# public_key: "{secrets.pleroma.vapid_public_key}",
|
public_key: "${secrets.pleroma.vapid_public_key}",
|
||||||
# private_key: "{secrets.pleroma.vapid_private_key}"
|
private_key: "${secrets.pleroma.vapid_private_key}"
|
||||||
|
|
||||||
# config :joken, default_signer: "{secrets.pleroma.joken_default_signer}"
|
|
||||||
|
|
||||||
|
config :joken, default_signer: "${secrets.pleroma.joken_default_signer}"
|
||||||
|
|
||||||
config :pleroma, :database, rum_enabled: false
|
config :pleroma, :database, rum_enabled: false
|
||||||
config :pleroma, :instance, static_dir: "/var/lib/pleroma/instance/static"
|
config :pleroma, :instance, static_dir: "/var/lib/pleroma/instance/static"
|
||||||
config :pleroma, Pleroma.Uploaders.Local, uploads: "/var/lib/pleroma/uploads"
|
config :pleroma, Pleroma.Uploaders.Local, uploads: "/var/lib/pleroma/uploads"
|
||||||
config :pleroma, configurable_from_database: false
|
config :pleroma, configurable_from_database: false
|
||||||
|
|
||||||
# strip metadata from uploaded images
|
# strip metadata from uploaded images
|
||||||
config :pleroma, Pleroma.Upload, filters: [Pleroma.Upload.Filter.Exiftool.StripLocation]
|
config :pleroma, Pleroma.Upload, filters: [Pleroma.Upload.Filter.Exiftool]
|
||||||
|
|
||||||
# TODO: GET /api/pleroma/captcha is broken
|
# TODO: GET /api/pleroma/captcha is broken
|
||||||
# there was a nixpkgs PR to fix this around 2022/10 though.
|
|
||||||
config :pleroma, Pleroma.Captcha,
|
config :pleroma, Pleroma.Captcha,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
method: Pleroma.Captcha.Native
|
method: Pleroma.Captcha.Native
|
||||||
@@ -90,11 +81,11 @@
|
|||||||
# Enable Strict-Transport-Security once SSL is working:
|
# Enable Strict-Transport-Security once SSL is working:
|
||||||
config :pleroma, :http_security,
|
config :pleroma, :http_security,
|
||||||
sts: true
|
sts: true
|
||||||
|
|
||||||
# docs: https://docs.pleroma.social/backend/configuration/cheatsheet/#logger
|
# docs: https://docs.pleroma.social/backend/configuration/cheatsheet/#logger
|
||||||
config :logger,
|
config :logger,
|
||||||
backends: [{ExSyslogger, :ex_syslogger}]
|
backends: [{ExSyslogger, :ex_syslogger}]
|
||||||
|
|
||||||
config :logger, :ex_syslogger,
|
config :logger, :ex_syslogger,
|
||||||
level: :warn
|
level: :warn
|
||||||
# level: :debug
|
# level: :debug
|
||||||
@@ -113,9 +104,9 @@
|
|||||||
|
|
||||||
systemd.services.pleroma.path = [
|
systemd.services.pleroma.path = [
|
||||||
# something inside pleroma invokes `sh` w/o specifying it by path, so this is needed to allow pleroma to start
|
# something inside pleroma invokes `sh` w/o specifying it by path, so this is needed to allow pleroma to start
|
||||||
pkgs.bash
|
pkgs.bash
|
||||||
# used by Pleroma to strip geo tags from uploads
|
# used by Pleroma to strip geo tags from uploads
|
||||||
pkgs.exiftool
|
pkgs.exiftool
|
||||||
# i saw some errors when pleroma was shutting down about it not being able to find `awk`. probably not critical
|
# i saw some errors when pleroma was shutting down about it not being able to find `awk`. probably not critical
|
||||||
pkgs.gawk
|
pkgs.gawk
|
||||||
# needed for email operations like password reset
|
# needed for email operations like password reset
|
||||||
@@ -125,7 +116,6 @@
|
|||||||
systemd.services.pleroma.serviceConfig = {
|
systemd.services.pleroma.serviceConfig = {
|
||||||
# postgres can be slow to service early requests, preventing pleroma from starting on the first try
|
# postgres can be slow to service early requests, preventing pleroma from starting on the first try
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
RestartSec = "10s";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# systemd.services.pleroma.serviceConfig = {
|
# systemd.services.pleroma.serviceConfig = {
|
||||||
@@ -134,53 +124,4 @@
|
|||||||
# PrivateTmp = lib.mkForce false;
|
# PrivateTmp = lib.mkForce false;
|
||||||
# CapabilityBoundingSet = lib.mkForce "~";
|
# CapabilityBoundingSet = lib.mkForce "~";
|
||||||
# };
|
# };
|
||||||
|
|
||||||
# Pleroma server and web interface
|
|
||||||
# TODO: enable publog?
|
|
||||||
services.nginx.virtualHosts."fed.uninsane.org" = {
|
|
||||||
forceSSL = true; # pleroma redirects to https anyway
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
locations."/" = {
|
|
||||||
proxyPass = "http://127.0.0.1:4000";
|
|
||||||
# documented: https://git.pleroma.social/pleroma/pleroma/-/blob/develop/installation/pleroma.nginx
|
|
||||||
extraConfig = ''
|
|
||||||
# XXX colin: this block is in the nixos examples: i don't understand all of it
|
|
||||||
add_header 'Access-Control-Allow-Origin' '*' always;
|
|
||||||
add_header 'Access-Control-Allow-Methods' 'POST, PUT, DELETE, GET, PATCH, OPTIONS' always;
|
|
||||||
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Idempotency-Key' always;
|
|
||||||
add_header 'Access-Control-Expose-Headers' 'Link, X-RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-Request-Id' always;
|
|
||||||
if ($request_method = OPTIONS) {
|
|
||||||
return 204;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_header X-XSS-Protection "1; mode=block";
|
|
||||||
add_header X-Permitted-Cross-Domain-Policies none;
|
|
||||||
add_header X-Frame-Options DENY;
|
|
||||||
add_header X-Content-Type-Options nosniff;
|
|
||||||
add_header Referrer-Policy same-origin;
|
|
||||||
add_header X-Download-Options noopen;
|
|
||||||
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
# proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
|
|
||||||
# colin: added this due to Pleroma complaining in its logs
|
|
||||||
# proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
|
|
||||||
client_max_body_size 16m;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."fed" = "native";
|
|
||||||
|
|
||||||
sops.secrets.pleroma_secrets = {
|
|
||||||
sopsFile = ../../../secrets/servo.yaml;
|
|
||||||
owner = config.users.users.pleroma.name;
|
|
||||||
};
|
|
||||||
}
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
{ config, lib, ... }:
|
{ config, pkgs, lib, secrets, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
submissionOptions = {
|
submissionOptions = {
|
||||||
@@ -16,70 +16,6 @@ let
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
# TODO: mode? could be more granular
|
|
||||||
{ user = "opendkim"; group = "opendkim"; directory = "/var/lib/opendkim"; }
|
|
||||||
{ user = "root"; group = "root"; directory = "/var/lib/postfix"; }
|
|
||||||
{ user = "root"; group = "root"; directory = "/var/spool/mail"; }
|
|
||||||
# *probably* don't need these dirs:
|
|
||||||
# "/var/lib/dhparams" # https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/dhparams.nix
|
|
||||||
# "/var/lib/dovecot"
|
|
||||||
];
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
|
||||||
25 # SMTP
|
|
||||||
143 # IMAP
|
|
||||||
465 # SMTPS
|
|
||||||
587 # SMTPS/submission
|
|
||||||
993 # IMAPS
|
|
||||||
];
|
|
||||||
|
|
||||||
# exists only to manage certs for dovecot
|
|
||||||
services.nginx.virtualHosts."imap.uninsane.org" = {
|
|
||||||
enableACME = true;
|
|
||||||
};
|
|
||||||
# exists only to manage certs for Postfix
|
|
||||||
services.nginx.virtualHosts."mx.uninsane.org" = {
|
|
||||||
enableACME = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
sane.services.trust-dns.zones."uninsane.org".inet = {
|
|
||||||
MX."@" = "10 mx.uninsane.org.";
|
|
||||||
# XXX: RFC's specify that the MX record CANNOT BE A CNAME
|
|
||||||
A."mx" = "185.157.162.178";
|
|
||||||
CNAME."imap" = "native";
|
|
||||||
|
|
||||||
# Sender Policy Framework:
|
|
||||||
# +mx => mail passes if it originated from the MX
|
|
||||||
# +a => mail passes if it originated from the A address of this domain
|
|
||||||
# +ip4:.. => mail passes if it originated from this IP
|
|
||||||
# -all => mail fails if none of these conditions were met
|
|
||||||
TXT."@" = "v=spf1 a mx -all";
|
|
||||||
|
|
||||||
# DKIM public key:
|
|
||||||
TXT."mx._domainkey" =
|
|
||||||
"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCkSyMufc2KrRx3j17e/LyB+3eYSBRuEFT8PUka8EDX04QzCwDPdkwgnj3GNDvnB5Ktb05Cf2SJ/S1OLqNsINxJRWtkVfZd/C339KNh9wrukMKRKNELL9HLUw0bczOI4gKKFqyrRE9qm+4csCMAR79Te9FCjGV/jVnrkLdPT0GtFwIDAQAB"
|
|
||||||
;
|
|
||||||
|
|
||||||
# DMARC fields <https://datatracker.ietf.org/doc/html/rfc7489>:
|
|
||||||
# p=none|quarantine|reject: what to do with failures
|
|
||||||
# sp = p but for subdomains
|
|
||||||
# rua = where to send aggregrate reports
|
|
||||||
# ruf = where to send individual failure reports
|
|
||||||
# fo=0|1|d|s controls WHEN to send failure reports
|
|
||||||
# (1=on bad alignment; d=on DKIM failure; s=on SPF failure);
|
|
||||||
# Additionally:
|
|
||||||
# adkim=r|s (is DKIM relaxed [default] or strict)
|
|
||||||
# aspf=r|s (is SPF relaxed [default] or strict)
|
|
||||||
# pct = sampling ratio for punishing failures (default 100 for 100%)
|
|
||||||
# rf = report format
|
|
||||||
# ri = report interval
|
|
||||||
TXT."_dmarc" =
|
|
||||||
"v=DMARC1;p=quarantine;sp=reject;rua=mailto:admin+mail@uninsane.org;ruf=mailto:admin+mail@uninsane.org;fo=1:d:s"
|
|
||||||
;
|
|
||||||
};
|
|
||||||
|
|
||||||
services.postfix.enable = true;
|
services.postfix.enable = true;
|
||||||
services.postfix.hostname = "mx.uninsane.org";
|
services.postfix.hostname = "mx.uninsane.org";
|
||||||
services.postfix.origin = "uninsane.org";
|
services.postfix.origin = "uninsane.org";
|
||||||
@@ -110,8 +46,7 @@ in
|
|||||||
services.postfix.enableSubmissions = true;
|
services.postfix.enableSubmissions = true;
|
||||||
services.postfix.submissionsOptions = submissionOptions;
|
services.postfix.submissionsOptions = submissionOptions;
|
||||||
|
|
||||||
systemd.services.postfix.after = [ "wireguard-wg0.service" ];
|
systemd.services.postfix.after = [ "wg0veth.service" ];
|
||||||
systemd.services.postfix.partOf = [ "wireguard-wg0.service" ];
|
|
||||||
systemd.services.postfix.serviceConfig = {
|
systemd.services.postfix.serviceConfig = {
|
||||||
# run this behind the OVPN static VPN
|
# run this behind the OVPN static VPN
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
@@ -132,8 +67,7 @@ in
|
|||||||
# keeping this the same as the hostname seems simplest
|
# keeping this the same as the hostname seems simplest
|
||||||
services.opendkim.selector = "mx";
|
services.opendkim.selector = "mx";
|
||||||
|
|
||||||
systemd.services.opendkim.after = [ "wireguard-wg0.service" ];
|
systemd.services.opendkim.after = [ "wg0veth.service" ];
|
||||||
systemd.services.opendkim.partOf = [ "wireguard-wg0.service" ];
|
|
||||||
systemd.services.opendkim.serviceConfig = {
|
systemd.services.opendkim.serviceConfig = {
|
||||||
# run this behind the OVPN static VPN
|
# run this behind the OVPN static VPN
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
@@ -148,7 +82,10 @@ in
|
|||||||
services.dovecot2.enablePAM = false;
|
services.dovecot2.enablePAM = false;
|
||||||
services.dovecot2.extraConfig =
|
services.dovecot2.extraConfig =
|
||||||
let
|
let
|
||||||
passwdFile = config.sops.secrets.dovecot_passwd.path;
|
passwdFile = builtins.toFile "dovecot-passwd-file" ''
|
||||||
|
colin:${secrets.dovecot.hashedPasswd.colin}:1000:1000::/var/mail/colin/run/current-system/sw/bin/nologin:
|
||||||
|
matrix-synapse:${secrets.dovecot.hashedPasswd.matrix-synapse}:224:224::/var/mail/colin:/run/current-system/sw/bin/nologin:
|
||||||
|
'';
|
||||||
in
|
in
|
||||||
''
|
''
|
||||||
passdb {
|
passdb {
|
||||||
@@ -196,11 +133,4 @@ in
|
|||||||
# pattern = "/^Subject:.*activate your account/";
|
# pattern = "/^Subject:.*activate your account/";
|
||||||
# }
|
# }
|
||||||
];
|
];
|
||||||
|
|
||||||
sops.secrets.dovecot_passwd = {
|
|
||||||
sopsFile = ../../../secrets/servo.yaml;
|
|
||||||
owner = config.users.users.dovecot2.name;
|
|
||||||
# TODO: debug why mail can't be sent without this being world-readable
|
|
||||||
mode = "0444";
|
|
||||||
};
|
|
||||||
}
|
}
|
@@ -1,12 +1,8 @@
|
|||||||
{ ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
sane.persist.sys.plaintext = [
|
|
||||||
# TODO: mode?
|
|
||||||
{ user = "postgres"; group = "postgres"; directory = "/var/lib/postgresql"; }
|
|
||||||
];
|
|
||||||
services.postgresql.enable = true;
|
services.postgresql.enable = true;
|
||||||
# services.postgresql.dataDir = "/opt/postgresql/13";
|
services.postgresql.dataDir = "/opt/postgresql/13";
|
||||||
# XXX colin: for a proper deploy, we'd want to include something for Pleroma here too.
|
# XXX colin: for a proper deploy, we'd want to include something for Pleroma here too.
|
||||||
# services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
|
# services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
|
||||||
# CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD '<password goes here>';
|
# CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD '<password goes here>';
|
||||||
@@ -17,11 +13,6 @@
|
|||||||
# LC_CTYPE = "C";
|
# LC_CTYPE = "C";
|
||||||
# '';
|
# '';
|
||||||
|
|
||||||
# TODO: perf tuning
|
|
||||||
# - for recommended values see: <https://pgtune.leopard.in.ua/>
|
|
||||||
# - for official docs (sparse), see: <https://www.postgresql.org/docs/11/config-setting.html#CONFIG-SETTING-CONFIGURATION-FILE>
|
|
||||||
# services.postgresql.settings = { ... }
|
|
||||||
|
|
||||||
# daily backups to /var/backup
|
# daily backups to /var/backup
|
||||||
services.postgresqlBackup.enable = true;
|
services.postgresqlBackup.enable = true;
|
||||||
|
|
37
machines/uninsane/services/transmission.nix
Normal file
37
machines/uninsane/services/transmission.nix
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
services.transmission.enable = true;
|
||||||
|
services.transmission.settings = {
|
||||||
|
rpc-bind-address = "0.0.0.0";
|
||||||
|
#rpc-host-whitelist = "bt.uninsane.org";
|
||||||
|
#rpc-whitelist = "*.*.*.*";
|
||||||
|
rpc-authentication-required = true;
|
||||||
|
rpc-username = "colin";
|
||||||
|
# salted pw. to regenerate, set this plaintext, run nixos-rebuild, and then find the salted pw in:
|
||||||
|
# /var/lib/transmission/.config/transmission-daemon/settings.json
|
||||||
|
rpc-password = "{503fc8928344f495efb8e1f955111ca5c862ce0656SzQnQ5";
|
||||||
|
rpc-whitelist-enabled = false;
|
||||||
|
|
||||||
|
# download-dir = "/opt/uninsane/media/";
|
||||||
|
|
||||||
|
# force peer connections to be encrypted
|
||||||
|
encryption = 2;
|
||||||
|
|
||||||
|
# units in kBps
|
||||||
|
speed-limit-down = 3000;
|
||||||
|
speed-limit-down-enabled = true;
|
||||||
|
speed-limit-up = 600;
|
||||||
|
speed-limit-up-enabled = true;
|
||||||
|
|
||||||
|
};
|
||||||
|
# transmission will by default not allow the world to read its files.
|
||||||
|
services.transmission.downloadDirPermissions = "775";
|
||||||
|
|
||||||
|
systemd.services.transmission.after = ["wg0veth.service"];
|
||||||
|
systemd.services.transmission.serviceConfig = {
|
||||||
|
# run this behind the OVPN static VPN
|
||||||
|
NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@@ -1,4 +1,4 @@
|
|||||||
{ config, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
# installer docs: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/installation-device.nix
|
# installer docs: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/installation-device.nix
|
||||||
{
|
{
|
@@ -1,12 +0,0 @@
|
|||||||
# this directory contains data of a factual nature.
|
|
||||||
# for example, public ssh keys, GPG keys, DNS-type name mappings.
|
|
||||||
#
|
|
||||||
# don't put things like fully-specific ~/.config files in here,
|
|
||||||
# even if they're "relatively unopinionated".
|
|
||||||
|
|
||||||
moduleArgs:
|
|
||||||
|
|
||||||
{
|
|
||||||
feeds = import ./feeds moduleArgs;
|
|
||||||
keys = import ./keys.nix;
|
|
||||||
}
|
|
@@ -1,51 +0,0 @@
|
|||||||
{ lib, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
inherit (builtins) concatLists concatStringsSep foldl' fromJSON map readDir readFile;
|
|
||||||
inherit (lib) hasSuffix listToAttrs mapAttrsToList removeSuffix splitString;
|
|
||||||
|
|
||||||
# given a path to a .json file relative to sources, construct the best feed object we can.
|
|
||||||
# the .json file could be empty, in which case we make assumptions about the feed based
|
|
||||||
# on its fs path.
|
|
||||||
# Type: feedFromSourcePath :: String -> { name = String; value = feed; }
|
|
||||||
feedFromSourcePath = json-path:
|
|
||||||
assert hasSuffix "/default.json" json-path;
|
|
||||||
let
|
|
||||||
canonical-name = removeSuffix "/default.json" json-path;
|
|
||||||
default-url = "https://${canonical-name}";
|
|
||||||
feed-details = { url = default-url; } // (tryImportJson (./sources/${json-path}));
|
|
||||||
in { name = canonical-name; value = mkFeed feed-details; };
|
|
||||||
|
|
||||||
# TODO: for now, feeds are just ordinary Attrs.
|
|
||||||
# in the future, we'd like to set them up with an update script.
|
|
||||||
mkFeed = { url, ... }@details: details;
|
|
||||||
|
|
||||||
# return an AttrSet representing the json at the provided path,
|
|
||||||
# or {} if the path is empty.
|
|
||||||
tryImportJson = path:
|
|
||||||
let
|
|
||||||
as-str = readFile path;
|
|
||||||
in
|
|
||||||
if as-str == "" then
|
|
||||||
{}
|
|
||||||
else
|
|
||||||
fromJSON as-str;
|
|
||||||
|
|
||||||
sources = enumerateFilePaths ./sources;
|
|
||||||
|
|
||||||
# like `lib.listFilesRecursive` but does not mangle paths.
|
|
||||||
# Type: enumerateFilePaths :: path -> [String]
|
|
||||||
enumerateFilePaths = base:
|
|
||||||
concatLists (
|
|
||||||
mapAttrsToList
|
|
||||||
(name: type:
|
|
||||||
if type == "directory" then
|
|
||||||
# enumerate this directory and then prefix each result with the directory's name
|
|
||||||
map (e: "${name}/${e}") (enumerateFilePaths (base + "/${name}"))
|
|
||||||
else
|
|
||||||
[ name ]
|
|
||||||
)
|
|
||||||
(readDir base)
|
|
||||||
);
|
|
||||||
in
|
|
||||||
listToAttrs (map feedFromSourcePath sources)
|
|
@@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"bozo": 0,
|
|
||||||
"content_length": 1369733,
|
|
||||||
"content_type": "application/rss+xml; charset=utf-8",
|
|
||||||
"description": "Every company has a story. Learn the playbooks that built the world’s greatest companies — and how you can apply them as a founder, operator, or investor.",
|
|
||||||
"favicon": null,
|
|
||||||
"hubs": [],
|
|
||||||
"is_podcast": true,
|
|
||||||
"is_push": false,
|
|
||||||
"item_count": 173,
|
|
||||||
"last_seen": "2023-01-11T15:26:37.515527+00:00",
|
|
||||||
"last_updated": "2022-12-19T07:22:28+00:00",
|
|
||||||
"score": 18,
|
|
||||||
"self_url": "https://acquired.libsyn.com/rss",
|
|
||||||
"site_name": null,
|
|
||||||
"site_url": null,
|
|
||||||
"title": "Acquired",
|
|
||||||
"url": "https://acquired.libsyn.com/rss",
|
|
||||||
"velocity": 0.066,
|
|
||||||
"version": "rss20"
|
|
||||||
}
|
|
@@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"bozo": 0,
|
|
||||||
"content_length": 1030773,
|
|
||||||
"content_type": "application/rss+xml; charset=utf-8",
|
|
||||||
"description": "Industry veterans, degenerate gamblers & besties Chamath Palihapitiya, Jason Calacanis, David Sacks & David Friedberg cover all things economic, tech, political, social & poker.",
|
|
||||||
"favicon": null,
|
|
||||||
"hubs": [],
|
|
||||||
"is_podcast": true,
|
|
||||||
"is_push": false,
|
|
||||||
"item_count": 124,
|
|
||||||
"last_seen": "2023-01-11T12:44:53.606606+00:00",
|
|
||||||
"last_updated": "2023-01-06T10:51:00+00:00",
|
|
||||||
"score": 18,
|
|
||||||
"self_url": "https://allinchamathjason.libsyn.com/rss",
|
|
||||||
"site_name": "All-In with Chamath, Jason, Sacks & Friedberg",
|
|
||||||
"site_url": "https://allinchamathjason.libsyn.com",
|
|
||||||
"title": "All-In with Chamath, Jason, Sacks & Friedberg",
|
|
||||||
"url": "https://allinchamathjason.libsyn.com/rss",
|
|
||||||
"velocity": 0.12,
|
|
||||||
"version": "rss20"
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user