Compare commits
4 Commits
master
...
2025-01-30
Author | SHA1 | Date | |
---|---|---|---|
de070bd5d8 | |||
ac58b884db | |||
d52844ddca | |||
8c660e3c07 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,5 +1,4 @@
|
|||||||
/build
|
.working
|
||||||
/.working
|
|
||||||
result
|
result
|
||||||
result-*
|
result-*
|
||||||
/secrets/local.nix
|
/secrets/local.nix
|
||||||
|
15
.sops.yaml
15
.sops.yaml
@@ -1,12 +1,10 @@
|
|||||||
keys:
|
keys:
|
||||||
- &user_desko_colin age1tnl4jfgacwkargzeqnhzernw29xx8mkv73xh6ufdyde6q7859slsnzf24x
|
- &user_desko_colin age1tnl4jfgacwkargzeqnhzernw29xx8mkv73xh6ufdyde6q7859slsnzf24x
|
||||||
- &user_flowy_colin age1nw3z25gn6l8gxneqw43tp8d2354c83d9sn3r0dqy5tapakdwhyvse0j2cc
|
|
||||||
- &user_lappy_colin age1j2pqnl8j0krdzk6npe93s4nnqrzwx978qrc0u570gzlamqpnje9sc8le2g
|
- &user_lappy_colin age1j2pqnl8j0krdzk6npe93s4nnqrzwx978qrc0u570gzlamqpnje9sc8le2g
|
||||||
- &user_servo_colin age1z8fauff34cdecr6sjkre260luzxcca05kpcwvhx988d306tpcejsp63znu
|
- &user_servo_colin age1z8fauff34cdecr6sjkre260luzxcca05kpcwvhx988d306tpcejsp63znu
|
||||||
- &user_moby_colin age1zsrsvd7j6l62fjxpfd2qnhqlk8wk4p8r0dtxpe4sdgnh2474095qdu7xj9
|
- &user_moby_colin age1zsrsvd7j6l62fjxpfd2qnhqlk8wk4p8r0dtxpe4sdgnh2474095qdu7xj9
|
||||||
- &host_crappy age1hl50ufuxnqy0jnk8fqeu4tclh4vte2xn2d59pxff0gun20vsmv5sp78chj
|
- &host_crappy age1hl50ufuxnqy0jnk8fqeu4tclh4vte2xn2d59pxff0gun20vsmv5sp78chj
|
||||||
- &host_desko age1vnw7lnfpdpjn62l3u5nyv5xt2c965k96p98kc43mcnyzpetrts9q54mc9v
|
- &host_desko age1vnw7lnfpdpjn62l3u5nyv5xt2c965k96p98kc43mcnyzpetrts9q54mc9v
|
||||||
- &host_flowy age1azm6carlm6tdjup37u5dr40585vjujajev70u4glwd9sv7swa99sk6mswx
|
|
||||||
- &host_lappy age1w7mectcjku6x3sd8plm8wkn2qfrhv9n6zhzlf329e2r2uycgke8qkf9dyn
|
- &host_lappy age1w7mectcjku6x3sd8plm8wkn2qfrhv9n6zhzlf329e2r2uycgke8qkf9dyn
|
||||||
- &host_servo age1tzlyex2z6t88tg9h82943e39shxhmqeyr7ywhlwpdjmyqsndv3qq27x0rf
|
- &host_servo age1tzlyex2z6t88tg9h82943e39shxhmqeyr7ywhlwpdjmyqsndv3qq27x0rf
|
||||||
- &host_moby age18vq5ktwgeaysucvw9t67drqmg5zd5c5k3le34yqxckkfj7wqdqgsd4ejmt
|
- &host_moby age18vq5ktwgeaysucvw9t67drqmg5zd5c5k3le34yqxckkfj7wqdqgsd4ejmt
|
||||||
@@ -15,13 +13,11 @@ creation_rules:
|
|||||||
key_groups:
|
key_groups:
|
||||||
- age:
|
- age:
|
||||||
- *user_desko_colin
|
- *user_desko_colin
|
||||||
- *user_flowy_colin
|
|
||||||
- *user_lappy_colin
|
- *user_lappy_colin
|
||||||
- *user_servo_colin
|
- *user_servo_colin
|
||||||
- *user_moby_colin
|
- *user_moby_colin
|
||||||
- *host_crappy
|
- *host_crappy
|
||||||
- *host_desko
|
- *host_desko
|
||||||
- *host_flowy
|
|
||||||
- *host_lappy
|
- *host_lappy
|
||||||
- *host_servo
|
- *host_servo
|
||||||
- *host_moby
|
- *host_moby
|
||||||
@@ -29,7 +25,6 @@ creation_rules:
|
|||||||
key_groups:
|
key_groups:
|
||||||
- age:
|
- age:
|
||||||
- *user_desko_colin
|
- *user_desko_colin
|
||||||
- *user_flowy_colin
|
|
||||||
- *user_lappy_colin
|
- *user_lappy_colin
|
||||||
- *user_servo_colin
|
- *user_servo_colin
|
||||||
- *host_servo
|
- *host_servo
|
||||||
@@ -37,28 +32,18 @@ creation_rules:
|
|||||||
key_groups:
|
key_groups:
|
||||||
- age:
|
- age:
|
||||||
- *user_desko_colin
|
- *user_desko_colin
|
||||||
- *user_flowy_colin
|
|
||||||
- *user_lappy_colin
|
- *user_lappy_colin
|
||||||
- *host_desko
|
- *host_desko
|
||||||
- path_regex: secrets/flowy*
|
|
||||||
key_groups:
|
|
||||||
- age:
|
|
||||||
- *user_lappy_colin
|
|
||||||
- *user_flowy_colin
|
|
||||||
- *user_desko_colin
|
|
||||||
- *host_flowy
|
|
||||||
- path_regex: secrets/lappy*
|
- path_regex: secrets/lappy*
|
||||||
key_groups:
|
key_groups:
|
||||||
- age:
|
- age:
|
||||||
- *user_lappy_colin
|
- *user_lappy_colin
|
||||||
- *user_flowy_colin
|
|
||||||
- *user_desko_colin
|
- *user_desko_colin
|
||||||
- *host_lappy
|
- *host_lappy
|
||||||
- path_regex: secrets/moby*
|
- path_regex: secrets/moby*
|
||||||
key_groups:
|
key_groups:
|
||||||
- age:
|
- age:
|
||||||
- *user_desko_colin
|
- *user_desko_colin
|
||||||
- *user_flowy_colin
|
|
||||||
- *user_lappy_colin
|
- *user_lappy_colin
|
||||||
- *user_moby_colin
|
- *user_moby_colin
|
||||||
- *host_moby
|
- *host_moby
|
||||||
|
17
TODO.md
17
TODO.md
@@ -20,12 +20,6 @@
|
|||||||
- rsync to ssh target fails because of restrictive sandboxing
|
- rsync to ssh target fails because of restrictive sandboxing
|
||||||
- `/mnt/.servo_ftp` retries every 10s, endlessly, rather than doing a linear backoff
|
- `/mnt/.servo_ftp` retries every 10s, endlessly, rather than doing a linear backoff
|
||||||
- repro by `systemctl stop sftpgo` on servo, then watching `mnt-.servo_ftp.{mount,timer}` on desko
|
- repro by `systemctl stop sftpgo` on servo, then watching `mnt-.servo_ftp.{mount,timer}` on desko
|
||||||
- `ovpns` (and presumably `doof`) net namespaces aren't firewalled
|
|
||||||
- not great because things like `bitmagnet` expose unprotected admin APIs by default!
|
|
||||||
- moby: NetworkManager doesn't connect to network until _after_ `systemctl restart NetworkManager`
|
|
||||||
- probably a dependency ordering issue
|
|
||||||
- e.g. we try to bring up NetworkManager before bringing up `lo`
|
|
||||||
- could be a perms issue (over-restrictive sandboxing)
|
|
||||||
|
|
||||||
## REFACTORING:
|
## REFACTORING:
|
||||||
- fold hosts/modules/ into toplevel modules/
|
- fold hosts/modules/ into toplevel modules/
|
||||||
@@ -34,10 +28,6 @@
|
|||||||
- ~/dev becomes a link to ~/ref/cat/mine
|
- ~/dev becomes a link to ~/ref/cat/mine
|
||||||
- fold hosts/common/home/ssh.nix -> hosts/common/users/colin.nix
|
- fold hosts/common/home/ssh.nix -> hosts/common/users/colin.nix
|
||||||
- don't hardcode IP addresses so much in servo
|
- don't hardcode IP addresses so much in servo
|
||||||
- modules/netns: migrate `sane.netns.$NS.services = [ FOO ]` option to be `systemd.services.$FOO.sane.netns = NS`
|
|
||||||
- then change the ExecStartPre check to not ping `ipinfo.net` or whatever.
|
|
||||||
either port all of `sane-ip-check` to use a self-hosted reflector,
|
|
||||||
or settle for something like `test -eq "$(ip route get ...)" "$expectedGateway"`
|
|
||||||
|
|
||||||
### sops/secrets
|
### sops/secrets
|
||||||
- user secrets could just use `gocryptfs`, like with ~/private?
|
- user secrets could just use `gocryptfs`, like with ~/private?
|
||||||
@@ -57,10 +47,7 @@
|
|||||||
|
|
||||||
|
|
||||||
## IMPROVEMENTS:
|
## IMPROVEMENTS:
|
||||||
- servo: expand /boot to 2 GiB like all other hosts
|
|
||||||
- moby: port to systemd-boot
|
|
||||||
- sane-deadlines: show day of the week for upcoming items
|
- sane-deadlines: show day of the week for upcoming items
|
||||||
- and only show on "first" terminal opened; not on Ctrl+N terminals
|
|
||||||
- curlftpfs: replace with something better
|
- curlftpfs: replace with something better
|
||||||
- safer (rust? actively maintained? sandboxable?)
|
- safer (rust? actively maintained? sandboxable?)
|
||||||
- handles spaces/symbols in filenames
|
- handles spaces/symbols in filenames
|
||||||
@@ -77,6 +64,7 @@
|
|||||||
- likely requires updating envelope to a more recent version (for multi-accounting), and therefore updating libadwaita...
|
- likely requires updating envelope to a more recent version (for multi-accounting), and therefore updating libadwaita...
|
||||||
|
|
||||||
### security/resilience
|
### security/resilience
|
||||||
|
- enable `snapper` btrfs snapshots (`services.snapper`)
|
||||||
- /mnt/desko/home, etc, shouldn't include secrets (~/private)
|
- /mnt/desko/home, etc, shouldn't include secrets (~/private)
|
||||||
- 95% of its use is for remote media access and stuff which isn't in VCS (~/records)
|
- 95% of its use is for remote media access and stuff which isn't in VCS (~/records)
|
||||||
- harden systemd services:
|
- harden systemd services:
|
||||||
@@ -100,7 +88,6 @@
|
|||||||
- make dconf stuff less monolithic
|
- make dconf stuff less monolithic
|
||||||
- i.e. per-app dconf profiles for those which need it. possible static config.
|
- i.e. per-app dconf profiles for those which need it. possible static config.
|
||||||
- flatpak/spectrum has some stuff to proxy dconf per-app
|
- flatpak/spectrum has some stuff to proxy dconf per-app
|
||||||
- rework `programs` API to be just an overlay which wraps each binary in an env with XDG_DATA_DIRS etc set & the config/state links placed in /nix/store instead of $HOME.
|
|
||||||
|
|
||||||
### user experience
|
### user experience
|
||||||
- setup a real calendar system, for recurring events
|
- setup a real calendar system, for recurring events
|
||||||
@@ -134,8 +121,6 @@
|
|||||||
- blurble (https://linuxphoneapps.org/games/app.drey.blurble/). nix: not as of 2024-02-05
|
- blurble (https://linuxphoneapps.org/games/app.drey.blurble/). nix: not as of 2024-02-05
|
||||||
- Trivia Quiz (https://linuxphoneapps.org/games/io.github.nokse22.trivia-quiz/)
|
- Trivia Quiz (https://linuxphoneapps.org/games/io.github.nokse22.trivia-quiz/)
|
||||||
- sane-sync-music: remove empty dirs
|
- sane-sync-music: remove empty dirs
|
||||||
- soulseek: install a CLI app usable over ssh
|
|
||||||
- moby: replace `spot` with its replacement, `riff` (<https://github.com/Diegovsky/riff>)
|
|
||||||
|
|
||||||
#### moby
|
#### moby
|
||||||
- moby: port battery support to something upstreamable
|
- moby: port battery support to something upstreamable
|
||||||
|
@@ -1,10 +1,7 @@
|
|||||||
to add a host:
|
to add a host:
|
||||||
- create the new nix targets
|
- create the new nix targets
|
||||||
- hosts/by-name/HOST
|
- hosts/by-name/HOST
|
||||||
- let the toplevel (impure.nix) know about HOST
|
- let the toplevel (flake.nix) know about HOST
|
||||||
- let the other hosts know about this host (hosts/common/hosts.nix)
|
|
||||||
- let sops know about the host's pubkey (.sops.yaml)
|
|
||||||
- re-encrypt all sops keys in secrets/common
|
|
||||||
- build and flash an image
|
- build and flash an image
|
||||||
- optionally expand the rootfs
|
- optionally expand the rootfs
|
||||||
- `cfdisk /dev/sda2` -> resize partition
|
- `cfdisk /dev/sda2` -> resize partition
|
||||||
@@ -25,9 +22,4 @@ to add a host:
|
|||||||
- instructions in hosts/common/secrets.nix
|
- instructions in hosts/common/secrets.nix
|
||||||
- run `ssh-to-age` on user/host pubkeys
|
- run `ssh-to-age` on user/host pubkeys
|
||||||
- add age key to .sops.yaml
|
- add age key to .sops.yaml
|
||||||
- update encrypted secrets: `find secrets -type f -exec sops updatekeys -y '{}' ';'`
|
- update encrypted secrets: `sops updatekeys path/to/secret.yaml`
|
||||||
- setup wireguard keys
|
|
||||||
- `pk=$(wg genkey)`
|
|
||||||
- `echo "$pk" | sops encrypt --filename-override secrets/$(hostname)/wg-home.priv.bin --output secrets/$(hostname)/wg-home.priv.bin`
|
|
||||||
- `pub=$(echo "$pk" | wg pubkey)`
|
|
||||||
- add pubkey to hosts/common/hosts.nix
|
|
||||||
|
@@ -1,49 +0,0 @@
|
|||||||
## migrating a host to a new drive
|
|
||||||
### 1. copy persistent data off of the host:
|
|
||||||
```sh
|
|
||||||
$ mkdir -p mnt old/persist
|
|
||||||
$ mount /dev/$old mnt
|
|
||||||
$ rsync -arv mnt/persist/ old/persist/
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. flash the new drive
|
|
||||||
```
|
|
||||||
$ nix-build -A hosts.moby.img
|
|
||||||
$ dd if=$(readlink ./result) of=/dev/$new bs=4M oflag=direct conv=sync status=progress
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3.1. expand the partition
|
|
||||||
```sh
|
|
||||||
$ cfdisk /dev/$new
|
|
||||||
# scroll to the last partition
|
|
||||||
> Resize
|
|
||||||
leave at default (max)
|
|
||||||
> Write
|
|
||||||
type "yes"
|
|
||||||
> Quit
|
|
||||||
```
|
|
||||||
### 3.2. expand the filesystem
|
|
||||||
```
|
|
||||||
$ mkdir -p /mnt/$new
|
|
||||||
$ mount /dev/$new /mnt/$new
|
|
||||||
$ btrfs filesystem resize max /mnt/$new
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. copy data onto the new host
|
|
||||||
```
|
|
||||||
$ mkdir /mnt/$new
|
|
||||||
$ mount /dev/$new /mnt/$new
|
|
||||||
# if you want to use btrfs snapshots (e.g. snapper), then create the data directory as a subvolume:
|
|
||||||
$ btrfs subvolume create /mnt/$new/persist
|
|
||||||
# restore the data
|
|
||||||
$ rsync -arv old/persist/ /mnt/$new/persist/
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. ensure/fix ownership
|
|
||||||
```
|
|
||||||
$ chmod -R a+rX /mnt/$new/nix
|
|
||||||
# or, let the nix daemon do it:
|
|
||||||
$ nix copy --no-check-sigs --to /mnt/$new $(nix-build -A hosts.moby)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. insert the disk into the system, and boot!
|
|
@@ -1,5 +1,5 @@
|
|||||||
## deploying to SD card
|
## deploying to SD card
|
||||||
- build a toplevel config: `nix build '.#hosts.moby.img'`
|
- build a toplevel config: `nix build '.#hostSystems.moby'`
|
||||||
- mount a system:
|
- mount a system:
|
||||||
- `mkdir -p root/{nix,boot}`
|
- `mkdir -p root/{nix,boot}`
|
||||||
- `mount /dev/sdX1 root/boot`
|
- `mount /dev/sdX1 root/boot`
|
||||||
|
@@ -1,19 +0,0 @@
|
|||||||
# MAME arcade cabinet
|
|
||||||
# Raspberry Pi 400:
|
|
||||||
# - quad-core Cortex-A72 @ 1.8 GHz (ARMv8-A 64; BCM2711)
|
|
||||||
# - 4GiB RAM
|
|
||||||
{ ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./fs.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
sane.hal.rpi-400.enable = true;
|
|
||||||
sane.roles.client = true; # for WiFi creds
|
|
||||||
|
|
||||||
# TODO: port to `sane.programs` interface
|
|
||||||
services.xserver.desktopManager.kodi.enable = true;
|
|
||||||
|
|
||||||
# /boot space is at a premium, especially with uncompressed kernels. default was 20.
|
|
||||||
# boot.loader.generic-extlinux-compatible.configurationLimit = 10;
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
fileSystems."/nix" = {
|
|
||||||
device = "/dev/disk/by-uuid/cccccccc-aaaa-dddd-eeee-000020250621";
|
|
||||||
fsType = "btrfs";
|
|
||||||
options = [
|
|
||||||
"compress=zstd"
|
|
||||||
"defaults"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems."/boot" = {
|
|
||||||
device = "/dev/disk/by-uuid/2025-0621";
|
|
||||||
fsType = "vfat";
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,13 +1,9 @@
|
|||||||
{ config, lib, ... }:
|
{ config, pkgs, ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./fs.nix
|
./fs.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
# firewall has to be open to allow clients to use services hosted on this device,
|
|
||||||
# like `ollama`
|
|
||||||
sane.ports.openFirewall = true;
|
|
||||||
|
|
||||||
# sane.programs.devPkgs.enableFor.user.colin = true;
|
# sane.programs.devPkgs.enableFor.user.colin = true;
|
||||||
# sane.guest.enable = true;
|
# sane.guest.enable = true;
|
||||||
|
|
||||||
@@ -26,9 +22,9 @@
|
|||||||
sane.roles.build-machine.enable = true;
|
sane.roles.build-machine.enable = true;
|
||||||
sane.roles.client = true;
|
sane.roles.client = true;
|
||||||
sane.roles.pc = true;
|
sane.roles.pc = true;
|
||||||
sane.roles.work = true;
|
sane.services.ollama.enable = true;
|
||||||
sane.services.ollama.enable = lib.mkIf (config.sane.maxBuildCost >= 3) true;
|
|
||||||
sane.services.wg-home.enable = true;
|
sane.services.wg-home.enable = true;
|
||||||
|
sane.services.wg-home.ip = config.sane.hosts.by-name."desko".wg-home.ip;
|
||||||
sane.ovpn.addrV4 = "172.26.55.21";
|
sane.ovpn.addrV4 = "172.26.55.21";
|
||||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:20c1:a73c";
|
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:20c1:a73c";
|
||||||
sane.services.rsync-net.enable = true;
|
sane.services.rsync-net.enable = true;
|
||||||
@@ -50,8 +46,11 @@
|
|||||||
|
|
||||||
sane.programs.mpv.config.defaultProfile = "high-quality";
|
sane.programs.mpv.config.defaultProfile = "high-quality";
|
||||||
|
|
||||||
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
|
|
||||||
# needed to use libimobiledevice/ifuse, for iphone sync
|
# needed to use libimobiledevice/ifuse, for iphone sync
|
||||||
services.usbmuxd.enable = true;
|
services.usbmuxd.enable = true;
|
||||||
|
|
||||||
hardware.amdgpu.opencl.enable = true; # desktop (AMD's opencl implementation AKA "ROCM"); probably required for ollama
|
# TODO(2025-01-01): re-enable once rocm build is fixed: <https://github.com/NixOS/nixpkgs/pull/367695>
|
||||||
|
# hardware.amdgpu.opencl.enable = true; # desktop (AMD's opencl implementation AKA "ROCM"); probably required for ollama
|
||||||
}
|
}
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
fileSystems."/tmp".options = [ "size=128G" ];
|
fileSystems."/tmp".options = [ "size=128G" ];
|
||||||
|
|
||||||
fileSystems."/nix" = {
|
fileSystems."/nix" = {
|
||||||
device = "/dev/disk/by-uuid/dddddddd-eeee-5555-cccc-000020250527";
|
device = "/dev/disk/by-uuid/845d85bf-761d-431b-a406-e6f20909154f";
|
||||||
fsType = "btrfs";
|
fsType = "btrfs";
|
||||||
options = [
|
options = [
|
||||||
"compress=zstd"
|
"compress=zstd"
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
fileSystems."/boot" = {
|
fileSystems."/boot" = {
|
||||||
device = "/dev/disk/by-uuid/2025-0527";
|
device = "/dev/disk/by-uuid/5049-9AFD";
|
||||||
fsType = "vfat";
|
fsType = "vfat";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,58 +0,0 @@
|
|||||||
{ lib, pkgs, ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./fs.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
sane.roles.client = true;
|
|
||||||
sane.roles.pc = true;
|
|
||||||
sane.roles.work = true;
|
|
||||||
sane.services.wg-home.enable = true;
|
|
||||||
# sane.ovpn.addrV4 = "172.23.119.72";
|
|
||||||
|
|
||||||
# sane.guest.enable = true;
|
|
||||||
|
|
||||||
sane.programs.sane-private-unlock-remote.enableFor.user.colin = true;
|
|
||||||
sane.programs.sane-private-unlock-remote.config.hosts = [ "servo" ];
|
|
||||||
|
|
||||||
sane.programs.firefox.config.formFactor = "laptop";
|
|
||||||
sane.programs.itgmania.enableFor.user.colin = true;
|
|
||||||
sane.programs.sway.enableFor.user.colin = true;
|
|
||||||
|
|
||||||
sops.secrets.colin-passwd.neededForUsers = true;
|
|
||||||
|
|
||||||
sane.services.rsync-net.enable = true;
|
|
||||||
|
|
||||||
# add an entry to boot into Windows, as if it had been launched directly from the BIOS.
|
|
||||||
boot.loader.systemd-boot.rebootForBitlocker = true;
|
|
||||||
boot.loader.systemd-boot.windows.primary.efiDeviceHandle = "HD0b";
|
|
||||||
|
|
||||||
system.activationScripts.makeDefaultBootEntry = {
|
|
||||||
text = let
|
|
||||||
makeDefaultBootEntry = pkgs.writeShellApplication {
|
|
||||||
name = "makeDefaultBootEntry";
|
|
||||||
runtimeInputs = with pkgs; [
|
|
||||||
efibootmgr
|
|
||||||
gnugrep
|
|
||||||
];
|
|
||||||
text = ''
|
|
||||||
# configure the EFI firmware to boot into NixOS by default.
|
|
||||||
# do this by querying the active boot entry, and just making that be the default.
|
|
||||||
# this is needed on flowy because enabling secure boot / booting into Windows
|
|
||||||
# resets the default boot order; manually reconfiguring that is tiresome.
|
|
||||||
efi=$(efibootmgr)
|
|
||||||
bootCurrent=$(echo "$efi" | grep '^BootCurrent: ')
|
|
||||||
bootCurrent=''${bootCurrent/BootCurrent: /}
|
|
||||||
bootOrder=$(echo "$efi" | grep '^BootOrder: ')
|
|
||||||
bootOrder=''${bootOrder/BootOrder: /}
|
|
||||||
if ! [[ "$bootOrder" =~ ^"$bootCurrent", ]]; then
|
|
||||||
# booted entry was not the default,
|
|
||||||
# so prepend it to the boot order:
|
|
||||||
newBootOrder="$bootCurrent,$bootOrder"
|
|
||||||
(set -x; efibootmgr -o "$newBootOrder")
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in lib.getExe makeDefaultBootEntry;
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
fileSystems."/nix" = {
|
|
||||||
device = "/dev/disk/by-uuid/ffffffff-1111-0000-eeee-000020250531";
|
|
||||||
fsType = "btrfs";
|
|
||||||
options = [
|
|
||||||
"compress=zstd"
|
|
||||||
"defaults"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems."/boot" = {
|
|
||||||
device = "/dev/disk/by-uuid/2025-0531";
|
|
||||||
fsType = "vfat";
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,4 +1,4 @@
|
|||||||
{ lib, ... }:
|
{ config, pkgs, ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./fs.nix
|
./fs.nix
|
||||||
@@ -7,10 +7,12 @@
|
|||||||
sane.roles.client = true;
|
sane.roles.client = true;
|
||||||
sane.roles.pc = true;
|
sane.roles.pc = true;
|
||||||
sane.services.wg-home.enable = true;
|
sane.services.wg-home.enable = true;
|
||||||
|
sane.services.wg-home.ip = config.sane.hosts.by-name."lappy".wg-home.ip;
|
||||||
sane.ovpn.addrV4 = "172.23.119.72";
|
sane.ovpn.addrV4 = "172.23.119.72";
|
||||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:0332:aa96/128";
|
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:0332:aa96/128";
|
||||||
|
|
||||||
# sane.guest.enable = true;
|
# sane.guest.enable = true;
|
||||||
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
|
|
||||||
sane.programs.sane-private-unlock-remote.enableFor.user.colin = true;
|
sane.programs.sane-private-unlock-remote.enableFor.user.colin = true;
|
||||||
sane.programs.sane-private-unlock-remote.config.hosts = [ "servo" ];
|
sane.programs.sane-private-unlock-remote.config.hosts = [ "servo" ];
|
||||||
@@ -28,10 +30,18 @@
|
|||||||
# 1024 solves *most* crackles, but still noticable under heavier loads.
|
# 1024 solves *most* crackles, but still noticable under heavier loads.
|
||||||
sane.programs.pipewire.config.min-quantum = 2048;
|
sane.programs.pipewire.config.min-quantum = 2048;
|
||||||
|
|
||||||
# limit how many snapshots we keep, due to extremely limited disk space (TODO: remove this override after upgrading lappy hard drive)
|
# TODO: enable snapper (need to make `/nix` or `/nix/persist` a subvolume, somehow).
|
||||||
services.snapper.configs.root.TIMELINE_LIMIT_HOURLY = lib.mkForce 2;
|
# default config: https://man.archlinux.org/man/snapper-configs.5
|
||||||
services.snapper.configs.root.TIMELINE_LIMIT_DAILY = lib.mkForce 2;
|
# defaults to something like:
|
||||||
services.snapper.configs.root.TIMELINE_LIMIT_WEEKLY = lib.mkForce 0;
|
# - hourly snapshots
|
||||||
services.snapper.configs.root.TIMELINE_LIMIT_MONTHLY = lib.mkForce 0;
|
# - auto cleanup; keep the last 10 hourlies, last 10 daylies, last 10 monthlys.
|
||||||
services.snapper.configs.root.TIMELINE_LIMIT_YEARLY = lib.mkForce 0;
|
# to list snapshots: `sudo snapper --config nix list`
|
||||||
|
# to take a snapshot: `sudo snapper --config nix create`
|
||||||
|
# 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`
|
||||||
|
# ALLOW_USERS = [ "colin" ];
|
||||||
|
# };
|
||||||
}
|
}
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
# - Mobian wiki: <https://wiki.mobian-project.org/doku.php?id=start>
|
# - Mobian wiki: <https://wiki.mobian-project.org/doku.php?id=start>
|
||||||
# - recommended apps, chatrooms
|
# - recommended apps, chatrooms
|
||||||
|
|
||||||
{ ... }:
|
{ config, ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./fs.nix
|
./fs.nix
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
sane.roles.client = true;
|
sane.roles.client = true;
|
||||||
sane.roles.handheld = true;
|
sane.roles.handheld = true;
|
||||||
sane.services.wg-home.enable = true;
|
sane.services.wg-home.enable = true;
|
||||||
|
sane.services.wg-home.ip = config.sane.hosts.by-name."moby".wg-home.ip;
|
||||||
sane.ovpn.addrV4 = "172.24.87.255";
|
sane.ovpn.addrV4 = "172.24.87.255";
|
||||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:18cd:a72b";
|
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:18cd:a72b";
|
||||||
|
|
||||||
@@ -59,9 +60,5 @@
|
|||||||
sane.programs.mpv.config.defaultProfile = "fast";
|
sane.programs.mpv.config.defaultProfile = "fast";
|
||||||
|
|
||||||
# /boot space is at a premium, especially with uncompressed kernels. default was 20.
|
# /boot space is at a premium, especially with uncompressed kernels. default was 20.
|
||||||
# boot.loader.generic-extlinux-compatible.configurationLimit = 10;
|
boot.loader.generic-extlinux-compatible.configurationLimit = 10;
|
||||||
|
|
||||||
# TODO: switch to systemd-boot
|
|
||||||
boot.loader.generic-extlinux-compatible.enable = true;
|
|
||||||
boot.loader.systemd-boot.enable = false;
|
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
{ ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./fs.nix
|
./fs.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
sane.persist.enable = false; # what we mean here is that the image is immutable; `/` is still tmpfs.
|
sane.persist.enable = false; # what we mean here is that the image is immutable; `/` is still tmpfs.
|
||||||
sane.nixcache.enable = false; # don't want to be calling out to dead machines that we're *trying* to rescue
|
sane.nixcache.enable = false; # don't want to be calling out to dead machines that we're *trying* to rescue
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
{ ... }:
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
@@ -31,6 +31,8 @@
|
|||||||
# XXX(2024-07-27): this is incompatible if using s6, which needs to auto-login as `colin` to start its user services.
|
# XXX(2024-07-27): this is incompatible if using s6, which needs to auto-login as `colin` to start its user services.
|
||||||
services.getty.autologinUser = "root";
|
services.getty.autologinUser = "root";
|
||||||
|
|
||||||
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
|
|
||||||
# both transmission and ipfs try to set different net defaults.
|
# both transmission and ipfs try to set different net defaults.
|
||||||
# we just use the most aggressive of the two here:
|
# we just use the most aggressive of the two here:
|
||||||
boot.kernel.sysctl = {
|
boot.kernel.sysctl = {
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
fileSystems."/tmp".options = [ "size=32G" ];
|
fileSystems."/tmp".options = [ "size=32G" ];
|
||||||
|
|
||||||
fileSystems."/nix" = {
|
fileSystems."/nix" = {
|
||||||
device = "/dev/disk/by-uuid/55555555-eeee-ffff-bbbb-000020250820";
|
device = "/dev/disk/by-uuid/cc81cca0-3cc7-4d82-a00c-6243af3e7776";
|
||||||
fsType = "btrfs";
|
fsType = "btrfs";
|
||||||
options = [
|
options = [
|
||||||
"compress=zstd"
|
"compress=zstd"
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
fileSystems."/boot" = {
|
fileSystems."/boot" = {
|
||||||
device = "/dev/disk/by-uuid/2025-0820";
|
device = "/dev/disk/by-uuid/6EE3-4171";
|
||||||
fsType = "vfat";
|
fsType = "vfat";
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -41,12 +41,10 @@
|
|||||||
# i don't know what guarantees NixOS/systemd make about that, so specifying all devices for now
|
# i don't know what guarantees NixOS/systemd make about that, so specifying all devices for now
|
||||||
# "device=/dev/disk/by-partuuid/14a7d00a-be53-2b4e-96f9-7e2c964674ec" #< removed 2024-11-24 (for capacity upgrade)
|
# "device=/dev/disk/by-partuuid/14a7d00a-be53-2b4e-96f9-7e2c964674ec" #< removed 2024-11-24 (for capacity upgrade)
|
||||||
"device=/dev/disk/by-partuuid/409a147e-2282-49eb-87a7-c968032ede88" #< added 2024-11-24
|
"device=/dev/disk/by-partuuid/409a147e-2282-49eb-87a7-c968032ede88" #< added 2024-11-24
|
||||||
# "device=/dev/disk/by-partuuid/6b86cc10-c3cc-ec4d-b20d-b6688f0959a6" #< removed 2025-06-04 (early drive failure; capacity upgrade)
|
"device=/dev/disk/by-partuuid/6b86cc10-c3cc-ec4d-b20d-b6688f0959a6"
|
||||||
# "device=/dev/disk/by-partuuid/7fd85cac-b6f3-8248-af4e-68e703d11020" #< removed 2024-11-13 (early drive failure)
|
# "device=/dev/disk/by-partuuid/7fd85cac-b6f3-8248-af4e-68e703d11020" #< removed 2024-11-13 (early drive failure)
|
||||||
"device=/dev/disk/by-partuuid/92ebbbfb-022f-427d-84d5-39349d4bc02a" #< added 2025-05-14
|
|
||||||
"device=/dev/disk/by-partuuid/9e6c06b0-4a39-4d69-813f-1f5992f62ed7" #< added 2025-06-05
|
|
||||||
"device=/dev/disk/by-partuuid/d9ad5ebc-0fc4-4d89-9fd0-619ce5210f1b" #< added 2024-11-13
|
"device=/dev/disk/by-partuuid/d9ad5ebc-0fc4-4d89-9fd0-619ce5210f1b" #< added 2024-11-13
|
||||||
# "device=/dev/disk/by-partuuid/ef0e5c7b-fccf-f444-bac4-534424326159" #< removed 2025-05-14 (early drive failure)
|
"device=/dev/disk/by-partuuid/ef0e5c7b-fccf-f444-bac4-534424326159"
|
||||||
"nofail"
|
"nofail"
|
||||||
# "x-systemd.before=local-fs.target"
|
# "x-systemd.before=local-fs.target"
|
||||||
"x-systemd.device-bound=false" #< don't unmount when `device` disappears (i thought this was necessary, for drive replacement, but it might not be)
|
"x-systemd.device-bound=false" #< don't unmount when `device` disappears (i thought this was necessary, for drive replacement, but it might not be)
|
||||||
@@ -69,9 +67,8 @@
|
|||||||
mode = "0775";
|
mode = "0775";
|
||||||
}];
|
}];
|
||||||
sane.fs."/var/media/archive".dir = {};
|
sane.fs."/var/media/archive".dir = {};
|
||||||
sane.fs."/var/media/archive/temp".dir = {};
|
|
||||||
# this is file.text instead of symlink.text so that it may be read over a remote mount (where consumers might not have any /nix/store/.../README.md path)
|
# this is file.text instead of symlink.text so that it may be read over a remote mount (where consumers might not have any /nix/store/.../README.md path)
|
||||||
sane.fs."/var/media/archive/temp/README.md".file.text = ''
|
sane.fs."/var/media/archive/README.md".file.text = ''
|
||||||
this directory is for media i wish to remove from my library,
|
this directory is for media i wish to remove from my library,
|
||||||
but keep for a short time in case i reverse my decision.
|
but keep for a short time in case i reverse my decision.
|
||||||
treat it like a system trash can.
|
treat it like a system trash can.
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{ config, ... }:
|
{ config, ... }:
|
||||||
{
|
{
|
||||||
sane.ovpn.addrV4 = "172.23.174.114"; #< this applies to the dynamic VPNs -- NOT the static VPN
|
sane.ovpn.addrV4 = "172.23.174.114";
|
||||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:8df3:14b0";
|
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:8df3:14b0";
|
||||||
|
|
||||||
# OVPN CONFIG (https://www.ovpn.com):
|
# OVPN CONFIG (https://www.ovpn.com):
|
||||||
@@ -12,9 +12,9 @@
|
|||||||
dns.ipv4 = "46.227.67.134"; #< DNS requests inside the namespace are forwarded here
|
dns.ipv4 = "46.227.67.134"; #< DNS requests inside the namespace are forwarded here
|
||||||
# wg.port = 51822;
|
# wg.port = 51822;
|
||||||
wg.privateKeyFile = config.sops.secrets.wg_ovpns_privkey.path;
|
wg.privateKeyFile = config.sops.secrets.wg_ovpns_privkey.path;
|
||||||
wg.address.ipv4 = "146.70.100.165"; #< IP address for my end of the VPN tunnel. for OVPN public IPv4, this is also the public IP address.
|
wg.address.ipv4 = "185.157.162.178";
|
||||||
wg.peer.publicKey = "xc9p/lf2uLg6IGDh54E0Pbc6WI/J9caaByhwD4Uiu0Q="; #< pubkey by which i can authenticate OVPN, varies per OVPN endpoint
|
wg.peer.publicKey = "SkkEZDCBde22KTs/Hc7FWvDBfdOCQA4YtBEuC3n5KGs=";
|
||||||
wg.peer.endpoint = "vpn31.prd.losangeles.ovpn.com:9930";
|
wg.peer.endpoint = "vpn36.prd.amsterdam.ovpn.com:9930";
|
||||||
# wg.peer.endpoint = "45.83.89.131:9930";
|
# wg.peer.endpoint = "185.157.162.10:9930";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
sane.services.wg-home.visibleToWan = true;
|
sane.services.wg-home.visibleToWan = true;
|
||||||
sane.services.wg-home.forwardToWan = true;
|
sane.services.wg-home.forwardToWan = true;
|
||||||
sane.services.wg-home.routeThroughServo = false;
|
sane.services.wg-home.routeThroughServo = false;
|
||||||
|
sane.services.wg-home.ip = config.sane.hosts.by-name."servo".wg-home.ip;
|
||||||
services.unbound.settings.server.interface = [
|
services.unbound.settings.server.interface = [
|
||||||
# provide DNS to my wireguard clients
|
# provide DNS to my wireguard clients
|
||||||
config.sane.hosts.by-name."servo".wg-home.ip
|
config.sane.hosts.by-name."servo".wg-home.ip
|
||||||
|
@@ -1,70 +0,0 @@
|
|||||||
# bitmagnet is a DHT crawler. it discovers publicly reachable torrents and indexes:
|
|
||||||
# - torrent's magnet URI
|
|
||||||
# - torrent's name
|
|
||||||
# - torrent's file list (the first 100 files, per torrent), including size and "type" (e.g. video)
|
|
||||||
# - seeder/leecher counts
|
|
||||||
# - torrent's size
|
|
||||||
# it provides a web UI to query these, especially a search form.
|
|
||||||
# data is stored in postgresql as `bitmagnet` db (`sudo -u bitmagnet psql`)
|
|
||||||
# after 30 days of operation:
|
|
||||||
# - 12m torrents discovered
|
|
||||||
# - 77GB database size => 6500B per torrent
|
|
||||||
{ config, ... }:
|
|
||||||
{
|
|
||||||
services.bitmagnet.enable = true;
|
|
||||||
sane.netns.ovpns.services = [ "bitmagnet" ];
|
|
||||||
sane.ports.ports."3334" = {
|
|
||||||
protocol = [ "tcp" "udp" ];
|
|
||||||
# visibleTo.ovpns = true; #< not needed: it runs in the ovpns namespace
|
|
||||||
description = "colin-bitmagnet";
|
|
||||||
};
|
|
||||||
|
|
||||||
services.bitmagnet.settings = {
|
|
||||||
# dht_crawler.scaling_factor: how rapidly to crawl the DHT.
|
|
||||||
# influences number of worker threads, buffer sizes, etc.
|
|
||||||
# default: 10.
|
|
||||||
# docs claim "diminishing returns" above 10, but seems weakly confident about that.
|
|
||||||
dht_crawler.scaling_factor = 64;
|
|
||||||
# http_server.local_address: `$addr:$port` to `listen` to.
|
|
||||||
# default is `:3333`, which listens on _all_ interfaces.
|
|
||||||
# the http server exposes unprotected admin endpoints though, so restrict to private interfaces:
|
|
||||||
http_server.local_address = "${config.sane.netns.ovpns.veth.netns.ipv4}:3333";
|
|
||||||
# tmdb.enabled: whether to query The Movie DataBase to resolve filename -> movie title.
|
|
||||||
# default: true.
|
|
||||||
# docs claim 1 query per second rate limit, unless you supply your own API key.
|
|
||||||
tmdb.enabled = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
# bitmagnet web client
|
|
||||||
# protected by passwd because it exposes some mutation operations:
|
|
||||||
# - queuing "jobs"
|
|
||||||
# - deleting torrent infos (in bulk)
|
|
||||||
# it uses graphql for _everything_, so no easy way to disable just the mutations (and remove the password) AFAICT.
|
|
||||||
services.nginx.virtualHosts."bitmagnet.uninsane.org" = {
|
|
||||||
# basicAuth is cleartext user/pw, so FORCE this to happen over SSL
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
locations."/" = {
|
|
||||||
proxyPass = "http://${config.sane.netns.ovpns.veth.netns.ipv4}:3333";
|
|
||||||
recommendedProxySettings = true;
|
|
||||||
};
|
|
||||||
basicAuthFile = config.sops.secrets.bitmagnet_passwd.path;
|
|
||||||
};
|
|
||||||
sops.secrets."bitmagnet_passwd" = {
|
|
||||||
owner = config.users.users.nginx.name;
|
|
||||||
mode = "0400";
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."bitmagnet" = "native";
|
|
||||||
|
|
||||||
systemd.services.bitmagnet = {
|
|
||||||
# hardening (systemd-analyze security bitmagnet). base nixos service is already partially hardened.
|
|
||||||
serviceConfig.CapabilityBoundingSet = "";
|
|
||||||
serviceConfig.SystemCallArchitectures = "native";
|
|
||||||
serviceConfig.PrivateDevices = true;
|
|
||||||
serviceConfig.PrivateUsers = true;
|
|
||||||
serviceConfig.ProtectProc = "invisible";
|
|
||||||
serviceConfig.ProcSubset = "pid";
|
|
||||||
serviceConfig.SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ];
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,5 +1,4 @@
|
|||||||
# as of 2023/12/02: complete blockchain is 530 GiB (on-disk size may be larger)
|
# as of 2023/12/02: complete blockchain is 530 GiB (on-disk size may be larger)
|
||||||
# as of 2025/08/06: on-disk blockchain as reported by `du` is 732 GiB
|
|
||||||
#
|
#
|
||||||
# ports:
|
# ports:
|
||||||
# - 8333: for node-to-node communications
|
# - 8333: for node-to-node communications
|
||||||
@@ -73,18 +72,13 @@ in
|
|||||||
proxy=127.0.0.1:9050
|
proxy=127.0.0.1:9050
|
||||||
'';
|
'';
|
||||||
extraCmdlineOptions = [
|
extraCmdlineOptions = [
|
||||||
# `man bitcoind` for options
|
|
||||||
# "-assumevalid=0" # to perform script validation on all blocks, instead of just the latest checkpoint published by bitcoin-core
|
|
||||||
# "-debug"
|
# "-debug"
|
||||||
# "-debug=estimatefee"
|
# "-debug=estimatefee"
|
||||||
# "-debug=leveldb"
|
|
||||||
# "-debug=http"
|
# "-debug=http"
|
||||||
# "-debug=net"
|
# "-debug=net"
|
||||||
"-debug=proxy"
|
"-debug=proxy"
|
||||||
"-debug=rpc"
|
"-debug=rpc"
|
||||||
# "-debug=validation"
|
# "-debug=validation"
|
||||||
# "-reindex" # wipe chainstate, block index, other indices; rebuild from blk*.dat (takes 2.5hrs)
|
|
||||||
# "-reindex-chainstate" # wipe chainstate; rebuild from blk*.dat
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -115,19 +115,11 @@
|
|||||||
# - fee-per-satoshi=<ppm>
|
# - fee-per-satoshi=<ppm>
|
||||||
# - feature configs (i.e. experimental-xyz options)
|
# - feature configs (i.e. experimental-xyz options)
|
||||||
sane.services.clightning.extraConfig = ''
|
sane.services.clightning.extraConfig = ''
|
||||||
# log levels: "io", "trace", "debug", "info", "unusual", "broken"
|
# log levels: "io", "debug", "info", "unusual", "broken"
|
||||||
# log-level=info
|
log-level=info
|
||||||
# log-level=info:lightningd
|
# log-level=info:lightningd
|
||||||
# log-level=debug:lightningd
|
# log-level=debug:lightningd
|
||||||
log-level=debug
|
# log-level=debug
|
||||||
# log-level=io
|
|
||||||
|
|
||||||
disable-plugin=cln-xpay
|
|
||||||
|
|
||||||
# let me use `lightning-cli dev-*` subcommands, fucktards.
|
|
||||||
developer
|
|
||||||
# `developer` enables `dev-*` but *disables* the older commands. asshats.
|
|
||||||
allow-deprecated-apis=true
|
|
||||||
|
|
||||||
# peerswap:
|
# peerswap:
|
||||||
# - config example: <https://github.com/fort-nix/nix-bitcoin/pull/462/files#diff-b357d832705b8ce8df1f41934d613f79adb77c4cd5cd9e9eb12a163fca3e16c6>
|
# - config example: <https://github.com/fort-nix/nix-bitcoin/pull/462/files#diff-b357d832705b8ce8df1f41934d613f79adb77c4cd5cd9e9eb12a163fca3e16c6>
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
{ ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./bitmagnet.nix
|
|
||||||
./coturn.nix
|
./coturn.nix
|
||||||
./cryptocurrencies
|
./cryptocurrencies
|
||||||
./email
|
./email
|
||||||
@@ -22,7 +21,7 @@
|
|||||||
./minidlna.nix
|
./minidlna.nix
|
||||||
./mumble.nix
|
./mumble.nix
|
||||||
./navidrome.nix
|
./navidrome.nix
|
||||||
./nginx
|
./nginx.nix
|
||||||
./nixos-prebuild.nix
|
./nixos-prebuild.nix
|
||||||
./ntfy
|
./ntfy
|
||||||
./pict-rs.nix
|
./pict-rs.nix
|
||||||
|
@@ -25,10 +25,10 @@
|
|||||||
#
|
#
|
||||||
# debugging: general connectivity issues
|
# debugging: general connectivity issues
|
||||||
# - test that inbound port 25 is unblocked:
|
# - test that inbound port 25 is unblocked:
|
||||||
# - `curl https://canyouseeme.org/ --data 'port=25&IP=$MX_IP' | grep 'see your service'`
|
# - `curl https://canyouseeme.org/ --data 'port=25&IP=185.157.162.178' | grep 'see your service'`
|
||||||
# - and retry with port 465, 587
|
# - and retry with port 465, 587
|
||||||
# - i think this API requires the queried IP match the source IP
|
# - i think this API requires the queried IP match the source IP
|
||||||
# - if necessary, `systemctl stop postfix` and `sudo nc -l $MX_IP 25`, then try https://canyouseeme.org
|
# - if necessary, `systemctl stop postfix` and `sudo nc -l 185.157.162.178 25`, then try https://canyouseeme.org
|
||||||
|
|
||||||
{ ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
|
@@ -124,9 +124,7 @@
|
|||||||
# ];
|
# ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
environment.systemPackages = [
|
services.dovecot2.modules = [
|
||||||
# XXX(2025-03-16): dovecot loads modules from /run/current-system/sw/lib/dovecot/modules
|
|
||||||
# see: <https://github.com/NixOS/nixpkgs/pull/387642>
|
|
||||||
pkgs.dovecot_pigeonhole # enables sieve execution (?)
|
pkgs.dovecot_pigeonhole # enables sieve execution (?)
|
||||||
];
|
];
|
||||||
services.dovecot2.sieve = {
|
services.dovecot2.sieve = {
|
||||||
@@ -143,5 +141,5 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.dovecot.serviceConfig.RestartSec = lib.mkForce "15s"; # nixos defaults this to 1s
|
systemd.services.dovecot2.serviceConfig.RestartSec = lib.mkForce "15s"; # nixos defaults this to 1s
|
||||||
}
|
}
|
||||||
|
@@ -99,10 +99,8 @@ in
|
|||||||
services.postfix.hostname = "mx.uninsane.org";
|
services.postfix.hostname = "mx.uninsane.org";
|
||||||
services.postfix.origin = "uninsane.org";
|
services.postfix.origin = "uninsane.org";
|
||||||
services.postfix.destination = [ "localhost" "uninsane.org" ];
|
services.postfix.destination = [ "localhost" "uninsane.org" ];
|
||||||
services.postfix.config.smtpd_tls_chain_files = [
|
services.postfix.sslCert = "/var/lib/acme/mx.uninsane.org/fullchain.pem";
|
||||||
"/var/lib/acme/mx.uninsane.org/key.pem"
|
services.postfix.sslKey = "/var/lib/acme/mx.uninsane.org/key.pem";
|
||||||
"/var/lib/acme/mx.uninsane.org/fullchain.pem"
|
|
||||||
];
|
|
||||||
|
|
||||||
# see: `man 5 virtual`
|
# see: `man 5 virtual`
|
||||||
services.postfix.virtual = ''
|
services.postfix.virtual = ''
|
||||||
@@ -114,7 +112,7 @@ in
|
|||||||
# smtpd_milters = local:/run/opendkim/opendkim.sock
|
# smtpd_milters = local:/run/opendkim/opendkim.sock
|
||||||
# milter docs: http://www.postfix.org/MILTER_README.html
|
# milter docs: http://www.postfix.org/MILTER_README.html
|
||||||
# mail filters for receiving email and from authorized SMTP clients (i.e. via submission)
|
# mail filters for receiving email and from authorized SMTP clients (i.e. via submission)
|
||||||
# smtpd_milters = inet:$IP:8891
|
# smtpd_milters = inet:185.157.162.190:8891
|
||||||
# opendkim.sock will add a Authentication-Results header, with `dkim=pass|fail|...` value to received messages
|
# opendkim.sock will add a Authentication-Results header, with `dkim=pass|fail|...` value to received messages
|
||||||
smtpd_milters = "unix:/run/opendkim/opendkim.sock";
|
smtpd_milters = "unix:/run/opendkim/opendkim.sock";
|
||||||
# mail filters for sendmail
|
# mail filters for sendmail
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# config options: <https://docs.gitea.io/en-us/administration/config-cheat-sheet/>
|
# config options: <https://docs.gitea.io/en-us/administration/config-cheat-sheet/>
|
||||||
# TODO: service shouldn't run as `git` user, but as `gitea`
|
# TODO: service shouldn't run as `git` user, but as `gitea`
|
||||||
{ config, pkgs, lib, ... }:
|
{ pkgs, lib, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.private = [
|
sane.persist.sys.byStore.private = [
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.gitea.wants = [ "postgresql.service" ];
|
systemd.services.gitea.requires = [ "postgresql.service" ];
|
||||||
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.
|
||||||
# we need more protos for sendmail to work. i thought it only needed +AF_LOCAL, but that didn't work.
|
# we need more protos for sendmail to work. i thought it only needed +AF_LOCAL, but that didn't work.
|
||||||
@@ -122,57 +122,24 @@
|
|||||||
|
|
||||||
# services.openssh.settings.UsePAM = true; #< required for `git` user to authenticate
|
# services.openssh.settings.UsePAM = true; #< required for `git` user to authenticate
|
||||||
|
|
||||||
services.anubis.instances."git.uninsane.org" = {
|
|
||||||
settings.TARGET = "http://127.0.0.1:3000";
|
|
||||||
# allow IM clients/etc to show embeds/previews, else they just show "please verify you aren't a bot..."
|
|
||||||
botPolicy.openGraph.enabled = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# hosted git (web view and for `git <cmd>` use
|
# hosted git (web view and for `git <cmd>` use
|
||||||
# TODO: enable publog?
|
# TODO: enable publog?
|
||||||
services.nginx.virtualHosts."git.uninsane.org" = let
|
services.nginx.virtualHosts."git.uninsane.org" = {
|
||||||
# XXX(2025-07-24): gitea's still being crawled, even with robots.txt.
|
|
||||||
# the load is less than when Anthropic first started, but it's still pretty high (like 600%).
|
|
||||||
# place behind anubis to prevent AI crawlers from hogging my CPU (gitea is slow to render pages).
|
|
||||||
proxyPassHeavy = "http://unix:${config.services.anubis.instances."git.uninsane.org".settings.BIND}";
|
|
||||||
# but anubis breaks embeds, so only protect the expensive repos.
|
|
||||||
proxyPassLight = "http://127.0.0.1:3000";
|
|
||||||
proxyTo = proxy: root: {
|
|
||||||
proxyPass = proxy;
|
|
||||||
recommendedProxySettings = true;
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
forceSSL = true; # gitea complains if served over a different protocol than its config file says
|
forceSSL = true; # gitea complains if served over a different protocol than its config file says
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
# inherit kTLS;
|
# inherit kTLS;
|
||||||
extraConfig = ''
|
|
||||||
client_max_body_size 100m;
|
|
||||||
'';
|
|
||||||
|
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = proxyPassLight;
|
proxyPass = "http://127.0.0.1:3000";
|
||||||
recommendedProxySettings = true;
|
|
||||||
};
|
};
|
||||||
# selectively proxy the heavyweight items through anubis.
|
|
||||||
# a typical interaction is:
|
|
||||||
# nginx:/colin/linux -> anubis:/colin/linux -> browser is served a loading page
|
|
||||||
# -> nginx:.within.website/x/cmd/anubis/api/pass-challenge?response=... -> anubis:.within.website/x/cmd/anubis/api/pass-challenge?response=... -> browser is forwarded to /colin/linux
|
|
||||||
# -> nginx:/colin/linux -> anubis:/colin/linux -> gitea:/colin/linux -> browser is served the actual content
|
|
||||||
locations."/.within.website/" = proxyTo proxyPassHeavy;
|
|
||||||
locations."/colin/linux" = proxyTo proxyPassHeavy;
|
|
||||||
locations."/colin/nixpkgs" = proxyTo proxyPassHeavy;
|
|
||||||
locations."/colin/opencellid-mirror" = proxyTo proxyPassHeavy;
|
|
||||||
locations."/colin/podcastindex-db-mirror" = proxyTo proxyPassHeavy;
|
|
||||||
|
|
||||||
# fuck you @anthropic
|
# fuck you @anthropic
|
||||||
# locations."= /robots.txt".extraConfig = ''
|
locations."= /robots.txt".extraConfig = ''
|
||||||
# return 200 "User-agent: *\nDisallow: /\n";
|
return 200 "User-agent: *\nDisallow: /\n";
|
||||||
# '';
|
'';
|
||||||
# gitea serves all `raw` files as content-type: plain, but i'd like to serve them as their actual content type.
|
# gitea serves all `raw` files as content-type: plain, but i'd like to serve them as their actual content type.
|
||||||
# or at least, enough to make specific pages viewable (serving unoriginal content as arbitrary content type is dangerous).
|
# or at least, enough to make specific pages viewable (serving unoriginal content as arbitrary content type is dangerous).
|
||||||
locations."~ ^/colin/phone-case-cq/raw/.*.html" = {
|
locations."~ ^/colin/phone-case-cq/raw/.*.html" = {
|
||||||
proxyPass = proxyPassLight;
|
proxyPass = "http://127.0.0.1:3000";
|
||||||
recommendedProxySettings = true;
|
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
proxy_hide_header Content-Type;
|
proxy_hide_header Content-Type;
|
||||||
default_type text/html;
|
default_type text/html;
|
||||||
@@ -180,8 +147,7 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
locations."~ ^/colin/phone-case-cq/raw/.*.js" = {
|
locations."~ ^/colin/phone-case-cq/raw/.*.js" = {
|
||||||
proxyPass = proxyPassLight;
|
proxyPass = "http://127.0.0.1:3000";
|
||||||
recommendedProxySettings = true;
|
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
proxy_hide_header Content-Type;
|
proxy_hide_header Content-Type;
|
||||||
default_type text/html;
|
default_type text/html;
|
||||||
|
@@ -56,7 +56,6 @@ lib.mkIf false #< 2024/09/30: disabled because i haven't used it in several mon
|
|||||||
|
|
||||||
locations."/ws" = {
|
locations."/ws" = {
|
||||||
proxyPass = "http://127.0.0.1:7890";
|
proxyPass = "http://127.0.0.1:7890";
|
||||||
recommendedProxySettings = true;
|
|
||||||
# XXX not sure how much of this is necessary
|
# XXX not sure how much of this is necessary
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
# TODO: split this file apart into smaller files to make it easier to understand
|
# TODO: split this file apart into smaller files to make it easier to understand
|
||||||
{ config, lib, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
dyn-dns = config.sane.services.dyn-dns;
|
dyn-dns = config.sane.services.dyn-dns;
|
||||||
@@ -55,7 +55,8 @@ in
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
services.hickory-dns.settings.zones = builtins.attrNames config.sane.dns.zones;
|
services.hickory-dns.settings.zones = [ "uninsane.org" ];
|
||||||
|
|
||||||
|
|
||||||
networking.nat.enable = true; #< TODO: try removing this?
|
networking.nat.enable = true; #< TODO: try removing this?
|
||||||
# networking.nat.extraCommands = ''
|
# networking.nat.extraCommands = ''
|
||||||
|
@@ -27,7 +27,6 @@ lib.mkIf false # i don't actively use ipfs anymore
|
|||||||
|
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://127.0.0.1:8080";
|
proxyPass = "http://127.0.0.1:8080";
|
||||||
recommendedProxySettings = true;
|
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Ipfs-Gateway-Prefix "";
|
proxy_set_header X-Ipfs-Gateway-Prefix "";
|
||||||
|
@@ -14,160 +14,158 @@
|
|||||||
#
|
#
|
||||||
# N.B.: default install DOES NOT SUPPORT DLNA out of the box.
|
# N.B.: default install DOES NOT SUPPORT DLNA out of the box.
|
||||||
# one must install it as a "plugin", which can be done through the UI.
|
# one must install it as a "plugin", which can be done through the UI.
|
||||||
{ config, lib, ... }:
|
{ lib, ... }:
|
||||||
|
|
||||||
# lib.mkIf false #< XXX(2024-11-17): disabled because it hasn't been working for months; web UI hangs on load, TVs see no files
|
# lib.mkIf false #< XXX(2024-11-17): disabled because it hasn't been working for months; web UI hangs on load, TVs see no files
|
||||||
{
|
{
|
||||||
config = lib.mkIf (config.sane.maxBuildCost >= 2) {
|
# https://jellyfin.org/docs/general/networking/index.html
|
||||||
# https://jellyfin.org/docs/general/networking/index.html
|
sane.ports.ports."1900" = {
|
||||||
sane.ports.ports."1900" = {
|
protocol = [ "udp" ];
|
||||||
protocol = [ "udp" ];
|
visibleTo.lan = true;
|
||||||
visibleTo.lan = true;
|
description = "colin-upnp-for-jellyfin";
|
||||||
description = "colin-upnp-for-jellyfin";
|
|
||||||
};
|
|
||||||
sane.ports.ports."7359" = {
|
|
||||||
protocol = [ "udp" ];
|
|
||||||
visibleTo.lan = true;
|
|
||||||
description = "colin-jellyfin-specific-client-discovery";
|
|
||||||
# ^ not sure if this is necessary: copied this port from nixos jellyfin.openFirewall
|
|
||||||
};
|
|
||||||
# not sure if 8096/8920 get used either:
|
|
||||||
sane.ports.ports."8096" = {
|
|
||||||
protocol = [ "tcp" ];
|
|
||||||
visibleTo.lan = true;
|
|
||||||
description = "colin-jellyfin-http-lan";
|
|
||||||
};
|
|
||||||
sane.ports.ports."8920" = {
|
|
||||||
protocol = [ "tcp" ];
|
|
||||||
visibleTo.lan = true;
|
|
||||||
description = "colin-jellyfin-https-lan";
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.persist.sys.byStore.plaintext = [
|
|
||||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/data"; method = "bind"; }
|
|
||||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/metadata"; method = "bind"; }
|
|
||||||
# TODO: ship plugins statically, via nix. that'll be less fragile
|
|
||||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/plugins/DLNA_5.0.0.0"; method = "bind"; }
|
|
||||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/root"; method = "bind"; }
|
|
||||||
];
|
|
||||||
sane.persist.sys.byStore.ephemeral = [
|
|
||||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/log"; method = "bind"; }
|
|
||||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/transcodes"; method = "bind"; }
|
|
||||||
];
|
|
||||||
|
|
||||||
services.jellyfin.enable = true;
|
|
||||||
users.users.jellyfin.extraGroups = [ "media" ];
|
|
||||||
|
|
||||||
sane.fs."/var/lib/jellyfin".dir.acl = {
|
|
||||||
user = "jellyfin";
|
|
||||||
group = "jellyfin";
|
|
||||||
mode = "0700";
|
|
||||||
};
|
|
||||||
|
|
||||||
# `"Jellyfin.Plugin.Dlna": "Debug"` logging: <https://jellyfin.org/docs/general/networking/dlna>
|
|
||||||
# TODO: switch Dlna back to 'Information' once satisfied with stability
|
|
||||||
sane.fs."/var/lib/jellyfin/config/logging.json".symlink.text = ''
|
|
||||||
{
|
|
||||||
"Serilog": {
|
|
||||||
"MinimumLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Override": {
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"System": "Warning",
|
|
||||||
"Jellyfin.Plugin.Dlna": "Debug"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"WriteTo": [
|
|
||||||
{
|
|
||||||
"Name": "Console",
|
|
||||||
"Args": {
|
|
||||||
"outputTemplate": "[{Timestamp:HH:mm:ss}] [{Level:u3}] [{ThreadId}] {SourceContext}: {Message:lj}{NewLine}{Exception}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Enrich": [ "FromLogContext", "WithThreadId" ]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
|
|
||||||
sane.fs."/var/lib/jellyfin/config/network.xml".file.text = ''
|
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<NetworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
|
||||||
<BaseUrl />
|
|
||||||
<EnableHttps>false</EnableHttps>
|
|
||||||
<RequireHttps>false</RequireHttps>
|
|
||||||
<InternalHttpPort>8096</InternalHttpPort>
|
|
||||||
<InternalHttpsPort>8920</InternalHttpsPort>
|
|
||||||
<PublicHttpPort>8096</PublicHttpPort>
|
|
||||||
<PublicHttpsPort>8920</PublicHttpsPort>
|
|
||||||
<AutoDiscovery>true</AutoDiscovery>
|
|
||||||
<EnableUPnP>false</EnableUPnP>
|
|
||||||
<EnableIPv4>true</EnableIPv4>
|
|
||||||
<EnableIPv6>false</EnableIPv6>
|
|
||||||
<EnableRemoteAccess>true</EnableRemoteAccess>
|
|
||||||
<LocalNetworkSubnets>
|
|
||||||
<string>10.78.76.0/22</string>
|
|
||||||
</LocalNetworkSubnets>
|
|
||||||
<KnownProxies>
|
|
||||||
<string>127.0.0.1</string>
|
|
||||||
<string>localhost</string>
|
|
||||||
<string>10.78.79.1</string>
|
|
||||||
</KnownProxies>
|
|
||||||
<IgnoreVirtualInterfaces>false</IgnoreVirtualInterfaces>
|
|
||||||
<VirtualInterfaceNames />
|
|
||||||
<EnablePublishedServerUriByRequest>false</EnablePublishedServerUriByRequest>
|
|
||||||
<PublishedServerUriBySubnet />
|
|
||||||
<RemoteIPFilter />
|
|
||||||
<IsRemoteIPFilterBlacklist>false</IsRemoteIPFilterBlacklist>
|
|
||||||
</NetworkConfiguration>
|
|
||||||
'';
|
|
||||||
|
|
||||||
# guest user id is `5ad194d60dca41de84b332950ffc4308`
|
|
||||||
sane.fs."/var/lib/jellyfin/plugins/configurations/Jellyfin.Plugin.Dlna.xml".file.text = ''
|
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<DlnaPluginConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
|
||||||
<EnablePlayTo>true</EnablePlayTo>
|
|
||||||
<ClientDiscoveryIntervalSeconds>60</ClientDiscoveryIntervalSeconds>
|
|
||||||
<BlastAliveMessages>true</BlastAliveMessages>
|
|
||||||
<AliveMessageIntervalSeconds>180</AliveMessageIntervalSeconds>
|
|
||||||
<SendOnlyMatchedHost>true</SendOnlyMatchedHost>
|
|
||||||
<DefaultUserId>5ad194d6-0dca-41de-84b3-32950ffc4308</DefaultUserId>
|
|
||||||
</DlnaPluginConfiguration>
|
|
||||||
'';
|
|
||||||
|
|
||||||
# fix LG TV to play more files.
|
|
||||||
# there are certain files for which it only supports Direct Play (not even "Direct Stream" -- but "Direct Play").
|
|
||||||
# this isn't a 100% fix: patching the profile allows e.g. Azumanga Daioh to play,
|
|
||||||
# but A Place Further Than the Universe still fails as before.
|
|
||||||
#
|
|
||||||
# profile is based on upstream: <https://github.com/jellyfin/jellyfin-plugin-dlna>
|
|
||||||
sane.fs."/var/lib/jellyfin/plugins/DLNA_5.0.0.0/profiles/LG Smart TV.xml".symlink.target = ./dlna/user/LG_Smart_TV.xml;
|
|
||||||
# XXX(2024-11-17): old method, but the file referenced seems not to be used and setting just it causes failures:
|
|
||||||
# > [DBG] Jellyfin.Plugin.Dlna.ContentDirectory.ContentDirectoryService: Not eligible for DirectPlay due to unsupported subtitles
|
|
||||||
# sane.fs."/var/lib/jellyfin/plugins/configurations/dlna/user/LG Smart TV.xml".symlink.target = ./dlna/user/LG_Smart_TV.xml;
|
|
||||||
|
|
||||||
systemd.services.jellyfin.unitConfig.RequiresMountsFor = [
|
|
||||||
"/var/media"
|
|
||||||
];
|
|
||||||
|
|
||||||
# Jellyfin multimedia server
|
|
||||||
# this is mostly taken from the official jellfin.org docs
|
|
||||||
services.nginx.virtualHosts."jelly.uninsane.org" = {
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
|
|
||||||
locations."/" = {
|
|
||||||
proxyPass = "http://127.0.0.1:8096";
|
|
||||||
proxyWebsockets = true;
|
|
||||||
recommendedProxySettings = true;
|
|
||||||
# extraConfig = ''
|
|
||||||
# # Disable buffering when the nginx proxy gets very resource heavy upon streaming
|
|
||||||
# proxy_buffering off;
|
|
||||||
# '';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."jelly" = "native";
|
|
||||||
};
|
};
|
||||||
|
sane.ports.ports."7359" = {
|
||||||
|
protocol = [ "udp" ];
|
||||||
|
visibleTo.lan = true;
|
||||||
|
description = "colin-jellyfin-specific-client-discovery";
|
||||||
|
# ^ not sure if this is necessary: copied this port from nixos jellyfin.openFirewall
|
||||||
|
};
|
||||||
|
# not sure if 8096/8920 get used either:
|
||||||
|
sane.ports.ports."8096" = {
|
||||||
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.lan = true;
|
||||||
|
description = "colin-jellyfin-http-lan";
|
||||||
|
};
|
||||||
|
sane.ports.ports."8920" = {
|
||||||
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.lan = true;
|
||||||
|
description = "colin-jellyfin-https-lan";
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.persist.sys.byStore.plaintext = [
|
||||||
|
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/data"; method = "bind"; }
|
||||||
|
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/metadata"; method = "bind"; }
|
||||||
|
# TODO: ship plugins statically, via nix. that'll be less fragile
|
||||||
|
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/plugins/DLNA_5.0.0.0"; method = "bind"; }
|
||||||
|
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/root"; method = "bind"; }
|
||||||
|
];
|
||||||
|
sane.persist.sys.byStore.ephemeral = [
|
||||||
|
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/log"; method = "bind"; }
|
||||||
|
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/transcodes"; method = "bind"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
services.jellyfin.enable = true;
|
||||||
|
users.users.jellyfin.extraGroups = [ "media" ];
|
||||||
|
|
||||||
|
sane.fs."/var/lib/jellyfin".dir.acl = {
|
||||||
|
user = "jellyfin";
|
||||||
|
group = "jellyfin";
|
||||||
|
mode = "0700";
|
||||||
|
};
|
||||||
|
|
||||||
|
# `"Jellyfin.Plugin.Dlna": "Debug"` logging: <https://jellyfin.org/docs/general/networking/dlna>
|
||||||
|
# TODO: switch Dlna back to 'Information' once satisfied with stability
|
||||||
|
sane.fs."/var/lib/jellyfin/config/logging.json".symlink.text = ''
|
||||||
|
{
|
||||||
|
"Serilog": {
|
||||||
|
"MinimumLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Override": {
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"System": "Warning",
|
||||||
|
"Jellyfin.Plugin.Dlna": "Debug"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"WriteTo": [
|
||||||
|
{
|
||||||
|
"Name": "Console",
|
||||||
|
"Args": {
|
||||||
|
"outputTemplate": "[{Timestamp:HH:mm:ss}] [{Level:u3}] [{ThreadId}] {SourceContext}: {Message:lj}{NewLine}{Exception}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Enrich": [ "FromLogContext", "WithThreadId" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
|
||||||
|
sane.fs."/var/lib/jellyfin/config/network.xml".file.text = ''
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<NetworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||||
|
<BaseUrl />
|
||||||
|
<EnableHttps>false</EnableHttps>
|
||||||
|
<RequireHttps>false</RequireHttps>
|
||||||
|
<InternalHttpPort>8096</InternalHttpPort>
|
||||||
|
<InternalHttpsPort>8920</InternalHttpsPort>
|
||||||
|
<PublicHttpPort>8096</PublicHttpPort>
|
||||||
|
<PublicHttpsPort>8920</PublicHttpsPort>
|
||||||
|
<AutoDiscovery>true</AutoDiscovery>
|
||||||
|
<EnableUPnP>false</EnableUPnP>
|
||||||
|
<EnableIPv4>true</EnableIPv4>
|
||||||
|
<EnableIPv6>false</EnableIPv6>
|
||||||
|
<EnableRemoteAccess>true</EnableRemoteAccess>
|
||||||
|
<LocalNetworkSubnets>
|
||||||
|
<string>10.78.76.0/22</string>
|
||||||
|
</LocalNetworkSubnets>
|
||||||
|
<KnownProxies>
|
||||||
|
<string>127.0.0.1</string>
|
||||||
|
<string>localhost</string>
|
||||||
|
<string>10.78.79.1</string>
|
||||||
|
</KnownProxies>
|
||||||
|
<IgnoreVirtualInterfaces>false</IgnoreVirtualInterfaces>
|
||||||
|
<VirtualInterfaceNames />
|
||||||
|
<EnablePublishedServerUriByRequest>false</EnablePublishedServerUriByRequest>
|
||||||
|
<PublishedServerUriBySubnet />
|
||||||
|
<RemoteIPFilter />
|
||||||
|
<IsRemoteIPFilterBlacklist>false</IsRemoteIPFilterBlacklist>
|
||||||
|
</NetworkConfiguration>
|
||||||
|
'';
|
||||||
|
|
||||||
|
# guest user id is `5ad194d60dca41de84b332950ffc4308`
|
||||||
|
sane.fs."/var/lib/jellyfin/plugins/configurations/Jellyfin.Plugin.Dlna.xml".file.text = ''
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<DlnaPluginConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||||
|
<EnablePlayTo>true</EnablePlayTo>
|
||||||
|
<ClientDiscoveryIntervalSeconds>60</ClientDiscoveryIntervalSeconds>
|
||||||
|
<BlastAliveMessages>true</BlastAliveMessages>
|
||||||
|
<AliveMessageIntervalSeconds>180</AliveMessageIntervalSeconds>
|
||||||
|
<SendOnlyMatchedHost>true</SendOnlyMatchedHost>
|
||||||
|
<DefaultUserId>5ad194d6-0dca-41de-84b3-32950ffc4308</DefaultUserId>
|
||||||
|
</DlnaPluginConfiguration>
|
||||||
|
'';
|
||||||
|
|
||||||
|
# fix LG TV to play more files.
|
||||||
|
# there are certain files for which it only supports Direct Play (not even "Direct Stream" -- but "Direct Play").
|
||||||
|
# this isn't a 100% fix: patching the profile allows e.g. Azumanga Daioh to play,
|
||||||
|
# but A Place Further Than the Universe still fails as before.
|
||||||
|
#
|
||||||
|
# profile is based on upstream: <https://github.com/jellyfin/jellyfin-plugin-dlna>
|
||||||
|
sane.fs."/var/lib/jellyfin/plugins/DLNA_5.0.0.0/profiles/LG Smart TV.xml".symlink.target = ./dlna/user/LG_Smart_TV.xml;
|
||||||
|
# XXX(2024-11-17): old method, but the file referenced seems not to be used and setting just it causes failures:
|
||||||
|
# > [DBG] Jellyfin.Plugin.Dlna.ContentDirectory.ContentDirectoryService: Not eligible for DirectPlay due to unsupported subtitles
|
||||||
|
# sane.fs."/var/lib/jellyfin/plugins/configurations/dlna/user/LG Smart TV.xml".symlink.target = ./dlna/user/LG_Smart_TV.xml;
|
||||||
|
|
||||||
|
systemd.services.jellyfin.unitConfig.RequiresMountsFor = [
|
||||||
|
"/var/media"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Jellyfin multimedia server
|
||||||
|
# this is mostly taken from the official jellfin.org docs
|
||||||
|
services.nginx.virtualHosts."jelly.uninsane.org" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8096";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
# extraConfig = ''
|
||||||
|
# # Disable buffering when the nginx proxy gets very resource heavy upon streaming
|
||||||
|
# proxy_buffering off;
|
||||||
|
# '';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.dns.zones."uninsane.org".inet.CNAME."jelly" = "native";
|
||||||
}
|
}
|
||||||
|
@@ -1,42 +1,37 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
config = lib.mkIf (config.sane.maxBuildCost >= 3) {
|
sane.services.kiwix-serve = {
|
||||||
sane.services.kiwix-serve = {
|
enable = true;
|
||||||
enable = true;
|
port = 8013;
|
||||||
port = 8013;
|
zimPaths = with pkgs.zimPackages; [
|
||||||
zimPaths = with pkgs.zimPackages; [
|
alpinelinux_en_all_maxi.zimPath
|
||||||
alpinelinux_en_all_maxi.zimPath
|
archlinux_en_all_maxi.zimPath
|
||||||
archlinux_en_all_maxi.zimPath
|
bitcoin_en_all_maxi.zimPath
|
||||||
bitcoin_en_all_maxi.zimPath
|
devdocs_en_nix.zimPath
|
||||||
devdocs_en_nix.zimPath
|
gentoo_en_all_maxi.zimPath
|
||||||
gentoo_en_all_maxi.zimPath
|
# khanacademy_en_all.zimPath #< TODO: enable
|
||||||
# khanacademy_en_all.zimPath #< TODO: enable
|
openstreetmap-wiki_en_all_maxi.zimPath
|
||||||
openstreetmap-wiki_en_all_maxi.zimPath
|
psychonautwiki_en_all_maxi.zimPath
|
||||||
psychonautwiki_en_all_maxi.zimPath
|
rationalwiki_en_all_maxi.zimPath
|
||||||
rationalwiki_en_all_maxi.zimPath
|
# wikipedia_en_100.zimPath
|
||||||
# wikipedia_en_100.zimPath
|
wikipedia_en_all_maxi.zimPath
|
||||||
wikipedia_en_all_maxi.zimPath
|
# wikipedia_en_all_mini.zimPath
|
||||||
# wikipedia_en_all_mini.zimPath
|
zimgit-food-preparation_en.zimPath
|
||||||
zimgit-food-preparation_en.zimPath
|
zimgit-medicine_en.zimPath
|
||||||
zimgit-medicine_en.zimPath
|
zimgit-post-disaster_en.zimPath
|
||||||
zimgit-post-disaster_en.zimPath
|
zimgit-water_en.zimPath
|
||||||
zimgit-water_en.zimPath
|
];
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
services.nginx.virtualHosts."w.uninsane.org" = {
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
locations."/" = {
|
|
||||||
proxyPass = "http://127.0.0.1:8013";
|
|
||||||
recommendedProxySettings = true;
|
|
||||||
};
|
|
||||||
locations."= /robots.txt".extraConfig = ''
|
|
||||||
return 200 "User-agent: *\nDisallow: /\n";
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."w" = "native";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
services.nginx.virtualHosts."w.uninsane.org" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
locations."/".proxyPass = "http://127.0.0.1:8013";
|
||||||
|
locations."= /robots.txt".extraConfig = ''
|
||||||
|
return 200 "User-agent: *\nDisallow: /\n";
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.dns.zones."uninsane.org".inet.CNAME."w" = "native";
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,6 @@ lib.mkIf false #< 2024/09/30: disabled because i haven't used this for several
|
|||||||
enableACME = true;
|
enableACME = true;
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://127.0.0.1:${builtins.toString port}";
|
proxyPass = "http://127.0.0.1:${builtins.toString port}";
|
||||||
recommendedProxySettings = true;
|
|
||||||
};
|
};
|
||||||
locations."= /robots.txt".extraConfig = ''
|
locations."= /robots.txt".extraConfig = ''
|
||||||
return 200 "User-agent: *\nDisallow: /\n";
|
return 200 "User-agent: *\nDisallow: /\n";
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
# - <repo:LemmyNet/lemmy:docker/nginx.conf>
|
# - <repo:LemmyNet/lemmy:docker/nginx.conf>
|
||||||
# - <repo:LemmyNet/lemmy-ansible:templates/nginx.conf>
|
# - <repo:LemmyNet/lemmy-ansible:templates/nginx.conf>
|
||||||
|
|
||||||
{ config, lib, pkgs, ... }:
|
{ lib, pkgs, ... }:
|
||||||
let
|
let
|
||||||
uiPort = 1234; # default ui port is 1234
|
uiPort = 1234; # default ui port is 1234
|
||||||
backendPort = 8536; # default backend port is 8536
|
backendPort = 8536; # default backend port is 8536
|
||||||
@@ -24,156 +24,150 @@ let
|
|||||||
media.video.max_frame_count = 30 * 60 * 60;
|
media.video.max_frame_count = 30 * 60 * 60;
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
config = lib.mkIf (config.sane.maxBuildCost >= 2) {
|
services.lemmy = {
|
||||||
services.lemmy = {
|
enable = true;
|
||||||
enable = true;
|
settings.hostname = "lemmy.uninsane.org";
|
||||||
settings.hostname = "lemmy.uninsane.org";
|
# federation.debug forces outbound federation queries to be run synchronously
|
||||||
# federation.debug forces outbound federation queries to be run synchronously
|
# N.B.: this option might not be read for 0.17.0+? <https://github.com/LemmyNet/lemmy/blob/c32585b03429f0f76d1e4ff738786321a0a9df98/RELEASES.md#upgrade-instructions>
|
||||||
# N.B.: this option might not be read for 0.17.0+? <https://github.com/LemmyNet/lemmy/blob/c32585b03429f0f76d1e4ff738786321a0a9df98/RELEASES.md#upgrade-instructions>
|
# settings.federation.debug = true;
|
||||||
# settings.federation.debug = true;
|
settings.port = backendPort;
|
||||||
settings.port = backendPort;
|
ui.port = uiPort;
|
||||||
ui.port = uiPort;
|
database.createLocally = true;
|
||||||
database.createLocally = true;
|
nginx.enable = true;
|
||||||
nginx.enable = true;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.lemmy.environment = {
|
systemd.services.lemmy.environment = {
|
||||||
RUST_BACKTRACE = "full";
|
RUST_BACKTRACE = "full";
|
||||||
RUST_LOG = "error";
|
RUST_LOG = "error";
|
||||||
# RUST_LOG = "warn";
|
# RUST_LOG = "warn";
|
||||||
# RUST_LOG = "debug";
|
# RUST_LOG = "debug";
|
||||||
# RUST_LOG = "trace";
|
# RUST_LOG = "trace";
|
||||||
# upstream defaults LEMMY_DATABASE_URL = "postgres:///lemmy?host=/run/postgresql";
|
# upstream defaults LEMMY_DATABASE_URL = "postgres:///lemmy?host=/run/postgresql";
|
||||||
# - Postgres complains that we didn't specify a user
|
# - Postgres complains that we didn't specify a user
|
||||||
# lemmy formats the url as:
|
# lemmy formats the url as:
|
||||||
# - postgres://{user}:{password}@{host}:{port}/{database}
|
# - postgres://{user}:{password}@{host}:{port}/{database}
|
||||||
# SO suggests (https://stackoverflow.com/questions/3582552/what-is-the-format-for-the-postgresql-connection-string-url):
|
# SO suggests (https://stackoverflow.com/questions/3582552/what-is-the-format-for-the-postgresql-connection-string-url):
|
||||||
# - postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...]
|
# - postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...]
|
||||||
# LEMMY_DATABASE_URL = "postgres://lemmy@/run/postgresql"; # connection to server on socket "/run/postgresql/.s.PGSQL.5432" failed: FATAL: database "run/postgresql" does not exist
|
# LEMMY_DATABASE_URL = "postgres://lemmy@/run/postgresql"; # connection to server on socket "/run/postgresql/.s.PGSQL.5432" failed: FATAL: database "run/postgresql" does not exist
|
||||||
# LEMMY_DATABASE_URL = "postgres://lemmy?host=/run/postgresql"; # no PostgreSQL user name specified in startup packet
|
# LEMMY_DATABASE_URL = "postgres://lemmy?host=/run/postgresql"; # no PostgreSQL user name specified in startup packet
|
||||||
# LEMMY_DATABASE_URL = lib.mkForce "postgres://lemmy@?host=/run/postgresql"; # WORKS
|
# LEMMY_DATABASE_URL = lib.mkForce "postgres://lemmy@?host=/run/postgresql"; # WORKS
|
||||||
LEMMY_DATABASE_URL = lib.mkForce "postgres://lemmy@/lemmy?host=/run/postgresql";
|
LEMMY_DATABASE_URL = lib.mkForce "postgres://lemmy@/lemmy?host=/run/postgresql";
|
||||||
};
|
};
|
||||||
users.groups.lemmy = {};
|
users.groups.lemmy = {};
|
||||||
users.users.lemmy = {
|
users.users.lemmy = {
|
||||||
group = "lemmy";
|
group = "lemmy";
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.nginx.virtualHosts."lemmy.uninsane.org" = {
|
services.nginx.virtualHosts."lemmy.uninsane.org" = {
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."lemmy" = "native";
|
sane.dns.zones."uninsane.org".inet.CNAME."lemmy" = "native";
|
||||||
|
|
||||||
systemd.services.lemmy = {
|
systemd.services.lemmy = {
|
||||||
# fix to use a normal user so we can configure perms correctly
|
# fix to use a normal user so we can configure perms correctly
|
||||||
# XXX(2024-07-28): this hasn't been rigorously tested:
|
# XXX(2024-07-28): this hasn't been rigorously tested:
|
||||||
# possible that i've set something too strict and won't notice right away
|
# possible that i've set something too strict and won't notice right away
|
||||||
serviceConfig.DynamicUser = lib.mkForce false;
|
serviceConfig.DynamicUser = lib.mkForce false;
|
||||||
serviceConfig.User = "lemmy";
|
serviceConfig.User = "lemmy";
|
||||||
serviceConfig.Group = "lemmy";
|
serviceConfig.Group = "lemmy";
|
||||||
|
|
||||||
# switch postgres from Requires -> Wants, so that postgres may restart without taking lemmy down with it.
|
# hardening (systemd-analyze security lemmy)
|
||||||
requires = lib.mkForce [];
|
# a handful of these are specified in upstream nixpkgs, but mostly not
|
||||||
wants = [ "postgresql.service" ];
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
|
serviceConfig.PrivateDevices = true;
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "pid";
|
||||||
|
|
||||||
# hardening (systemd-analyze security lemmy)
|
serviceConfig.ProtectClock = true;
|
||||||
# a handful of these are specified in upstream nixpkgs, but mostly not
|
serviceConfig.ProtectControlGroups = true;
|
||||||
serviceConfig.LockPersonality = true;
|
serviceConfig.ProtectHome = true;
|
||||||
serviceConfig.NoNewPrivileges = true;
|
serviceConfig.ProtectHostname = true;
|
||||||
serviceConfig.MemoryDenyWriteExecute = true;
|
serviceConfig.ProtectKernelLogs = true;
|
||||||
serviceConfig.PrivateDevices = true;
|
serviceConfig.ProtectKernelModules = true;
|
||||||
serviceConfig.PrivateMounts = true;
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
serviceConfig.PrivateTmp = true;
|
serviceConfig.ProtectProc = "invisible";
|
||||||
serviceConfig.PrivateUsers = true;
|
serviceConfig.ProtectSystem = "strict";
|
||||||
serviceConfig.ProcSubset = "pid";
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
|
||||||
serviceConfig.ProtectClock = true;
|
serviceConfig.RestrictNamespaces = true;
|
||||||
serviceConfig.ProtectControlGroups = true;
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
serviceConfig.ProtectHome = true;
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
serviceConfig.ProtectHostname = true;
|
serviceConfig.SystemCallFilter = [ "@system-service" ];
|
||||||
serviceConfig.ProtectKernelLogs = true;
|
};
|
||||||
serviceConfig.ProtectKernelModules = true;
|
|
||||||
serviceConfig.ProtectKernelTunables = true;
|
|
||||||
serviceConfig.ProtectProc = "invisible";
|
|
||||||
serviceConfig.ProtectSystem = "strict";
|
|
||||||
serviceConfig.RemoveIPC = true;
|
|
||||||
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
|
||||||
|
|
||||||
serviceConfig.RestrictNamespaces = true;
|
systemd.services.lemmy-ui = {
|
||||||
serviceConfig.RestrictSUIDSGID = true;
|
# hardening (systemd-analyze security lemmy-ui)
|
||||||
serviceConfig.SystemCallArchitectures = "native";
|
# TODO: upstream into nixpkgs
|
||||||
serviceConfig.SystemCallFilter = [ "@system-service" ];
|
serviceConfig.LockPersonality = true;
|
||||||
};
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
# serviceConfig.MemoryDenyWriteExecute = true; #< it uses v8, JIT
|
||||||
|
serviceConfig.PrivateDevices = true;
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "pid";
|
||||||
|
|
||||||
systemd.services.lemmy-ui = {
|
serviceConfig.ProtectClock = true;
|
||||||
# hardening (systemd-analyze security lemmy-ui)
|
serviceConfig.ProtectControlGroups = true;
|
||||||
# TODO: upstream into nixpkgs
|
serviceConfig.ProtectHome = true;
|
||||||
serviceConfig.LockPersonality = true;
|
serviceConfig.ProtectHostname = true;
|
||||||
serviceConfig.NoNewPrivileges = true;
|
serviceConfig.ProtectKernelLogs = true;
|
||||||
# serviceConfig.MemoryDenyWriteExecute = true; #< it uses v8, JIT
|
serviceConfig.ProtectKernelModules = true;
|
||||||
serviceConfig.PrivateDevices = true;
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
serviceConfig.PrivateMounts = true;
|
serviceConfig.ProtectProc = "invisible";
|
||||||
serviceConfig.PrivateTmp = true;
|
serviceConfig.ProtectSystem = "strict";
|
||||||
serviceConfig.PrivateUsers = true;
|
serviceConfig.RemoveIPC = true;
|
||||||
serviceConfig.ProcSubset = "pid";
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
|
||||||
serviceConfig.ProtectClock = true;
|
serviceConfig.RestrictNamespaces = true;
|
||||||
serviceConfig.ProtectControlGroups = true;
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
serviceConfig.ProtectHome = true;
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
serviceConfig.ProtectHostname = true;
|
serviceConfig.SystemCallFilter = [ "@system-service" "@pkey" "@sandbox" ];
|
||||||
serviceConfig.ProtectKernelLogs = true;
|
};
|
||||||
serviceConfig.ProtectKernelModules = true;
|
|
||||||
serviceConfig.ProtectKernelTunables = true;
|
|
||||||
serviceConfig.ProtectProc = "invisible";
|
|
||||||
serviceConfig.ProtectSystem = "strict";
|
|
||||||
serviceConfig.RemoveIPC = true;
|
|
||||||
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
|
||||||
|
|
||||||
serviceConfig.RestrictNamespaces = true;
|
#v DO NOT REMOVE: defaults to 0.3, instead of latest, so always need to explicitly set this.
|
||||||
serviceConfig.RestrictSUIDSGID = true;
|
services.pict-rs.package = pict-rs;
|
||||||
serviceConfig.SystemCallArchitectures = "native";
|
|
||||||
serviceConfig.SystemCallFilter = [ "@system-service" "@pkey" "@sandbox" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
#v DO NOT REMOVE: defaults to 0.3, instead of latest, so always need to explicitly set this.
|
systemd.services.pict-rs = {
|
||||||
services.pict-rs.package = pict-rs;
|
serviceConfig.ExecStart = lib.mkForce (lib.concatStringsSep " " [
|
||||||
|
(lib.getExe pict-rs)
|
||||||
|
"--config-file"
|
||||||
|
tomlConfig
|
||||||
|
"run"
|
||||||
|
]);
|
||||||
|
|
||||||
systemd.services.pict-rs = {
|
# hardening (systemd-analyze security pict-rs)
|
||||||
serviceConfig.ExecStart = lib.mkForce (lib.concatStringsSep " " [
|
# TODO: upstream into nixpkgs
|
||||||
(lib.getExe pict-rs)
|
serviceConfig.LockPersonality = true;
|
||||||
"--config-file"
|
serviceConfig.NoNewPrivileges = true;
|
||||||
tomlConfig
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
"run"
|
serviceConfig.PrivateDevices = true;
|
||||||
]);
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
# hardening (systemd-analyze security pict-rs)
|
serviceConfig.PrivateUsers = true;
|
||||||
# TODO: upstream into nixpkgs
|
serviceConfig.ProcSubset = "pid";
|
||||||
serviceConfig.LockPersonality = true;
|
serviceConfig.ProtectClock = true;
|
||||||
serviceConfig.NoNewPrivileges = true;
|
serviceConfig.ProtectControlGroups = true;
|
||||||
serviceConfig.MemoryDenyWriteExecute = true;
|
serviceConfig.ProtectHome = true;
|
||||||
serviceConfig.PrivateDevices = true;
|
serviceConfig.ProtectHostname = true;
|
||||||
serviceConfig.PrivateMounts = true;
|
serviceConfig.ProtectKernelLogs = true;
|
||||||
serviceConfig.PrivateTmp = true;
|
serviceConfig.ProtectKernelModules = true;
|
||||||
serviceConfig.PrivateUsers = true;
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
serviceConfig.ProcSubset = "pid";
|
serviceConfig.ProtectProc = "invisible";
|
||||||
serviceConfig.ProtectClock = true;
|
serviceConfig.ProtectSystem = "strict";
|
||||||
serviceConfig.ProtectControlGroups = true;
|
serviceConfig.RemoveIPC = true;
|
||||||
serviceConfig.ProtectHome = true;
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
serviceConfig.ProtectHostname = true;
|
serviceConfig.RestrictNamespaces = true;
|
||||||
serviceConfig.ProtectKernelLogs = true;
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
serviceConfig.ProtectKernelModules = true;
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
serviceConfig.ProtectKernelTunables = true;
|
serviceConfig.SystemCallFilter = [ "@system-service" ];
|
||||||
serviceConfig.ProtectProc = "invisible";
|
|
||||||
serviceConfig.ProtectSystem = "strict";
|
|
||||||
serviceConfig.RemoveIPC = true;
|
|
||||||
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
|
||||||
serviceConfig.RestrictNamespaces = true;
|
|
||||||
serviceConfig.RestrictSUIDSGID = true;
|
|
||||||
serviceConfig.SystemCallArchitectures = "native";
|
|
||||||
serviceConfig.SystemCallFilter = [ "@system-service" ];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -75,9 +75,6 @@ in
|
|||||||
systemd.services.matrix-synapse.serviceConfig.RestartMaxDelaySec = 20;
|
systemd.services.matrix-synapse.serviceConfig.RestartMaxDelaySec = 20;
|
||||||
systemd.services.matrix-synapse.serviceConfig.StartLimitBurst = 120;
|
systemd.services.matrix-synapse.serviceConfig.StartLimitBurst = 120;
|
||||||
systemd.services.matrix-synapse.serviceConfig.RestartSteps = 3;
|
systemd.services.matrix-synapse.serviceConfig.RestartSteps = 3;
|
||||||
# switch postgres from Requires -> Wants, so that postgres may restart without taking matrix down with it.
|
|
||||||
systemd.services.matrix-synapse.requires = lib.mkForce [];
|
|
||||||
systemd.services.matrix-synapse.wants = [ "postgresql.service" ];
|
|
||||||
|
|
||||||
systemd.services.matrix-synapse.postStart = lib.optionalString ntfy ''
|
systemd.services.matrix-synapse.postStart = lib.optionalString ntfy ''
|
||||||
ACCESS_TOKEN=$(${lib.getExe' pkgs.coreutils "cat"} ${config.sops.secrets.matrix_access_token.path})
|
ACCESS_TOKEN=$(${lib.getExe' pkgs.coreutils "cat"} ${config.sops.secrets.matrix_access_token.path})
|
||||||
@@ -123,7 +120,6 @@ in
|
|||||||
|
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://127.0.0.1:8008";
|
proxyPass = "http://127.0.0.1:8008";
|
||||||
recommendedProxySettings = true;
|
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
# allow uploading large files (matrix enforces a separate limit, downstream)
|
# allow uploading large files (matrix enforces a separate limit, downstream)
|
||||||
client_max_body_size 512m;
|
client_max_body_size 512m;
|
||||||
|
@@ -184,7 +184,6 @@ in
|
|||||||
enableACME = true;
|
enableACME = true;
|
||||||
locations."/media" = {
|
locations."/media" = {
|
||||||
proxyPass = "http://127.0.0.1:11111";
|
proxyPass = "http://127.0.0.1:11111";
|
||||||
recommendedProxySettings = true;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -34,10 +34,7 @@ lib.mkIf false #< i don't actively use navidrome
|
|||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
# inherit kTLS;
|
# inherit kTLS;
|
||||||
locations."/" = {
|
locations."/".proxyPass = "http://127.0.0.1:4533";
|
||||||
proxyPass = "http://127.0.0.1:4533";
|
|
||||||
recommendedProxySettings = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."music" = "native";
|
sane.dns.zones."uninsane.org".inet.CNAME."music" = "native";
|
||||||
|
270
hosts/by-name/servo/services/nginx.nix
Normal file
270
hosts/by-name/servo/services/nginx.nix
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
# docs: <https://nixos.wiki/wiki/Nginx>
|
||||||
|
# docs: <https://nginx.org/en/docs/>
|
||||||
|
{ 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
|
||||||
|
{
|
||||||
|
|
||||||
|
sane.ports.ports."80" = {
|
||||||
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.lan = true;
|
||||||
|
visibleTo.ovpns = true; # so that letsencrypt can procure a cert for the mx record
|
||||||
|
visibleTo.doof = true;
|
||||||
|
description = "colin-http-uninsane.org";
|
||||||
|
};
|
||||||
|
sane.ports.ports."443" = {
|
||||||
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.lan = true;
|
||||||
|
visibleTo.doof = true;
|
||||||
|
description = "colin-https-uninsane.org";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx.enable = true;
|
||||||
|
# nginxStable is one release behind nginxMainline.
|
||||||
|
# nginx itself recommends running mainline; nixos defaults to stable.
|
||||||
|
# services.nginx.package = pkgs.nginxMainline;
|
||||||
|
# XXX(2024-07-31): nixos defaults to zlib-ng -- supposedly more performant, but spams log with
|
||||||
|
# "gzip filter failed to use preallocated memory: ..."
|
||||||
|
services.nginx.package = pkgs.nginxMainline.override { zlib = pkgs.zlib; };
|
||||||
|
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;
|
||||||
|
'';
|
||||||
|
# enables gzip and sets gzip_comp_level = 5
|
||||||
|
services.nginx.recommendedGzipSettings = true;
|
||||||
|
# enables zstd and sets zstd_comp_level = 9
|
||||||
|
services.nginx.recommendedZstdSettings = 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
|
||||||
|
# alternative way to link stuff into the share:
|
||||||
|
# sane.fs."/var/www/sites/uninsane.org/share/Ubunchu".mount.bind = "/var/media/Books/Visual/HiroshiSeo/Ubunchu";
|
||||||
|
# sane.fs."/var/media/Books/Visual/HiroshiSeo/Ubunchu".dir = {};
|
||||||
|
services.nginx.virtualHosts."uninsane.org" = publog {
|
||||||
|
# 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";
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
root = "${pkgs.uninsane-dot-org}/share/uninsane-dot-org";
|
||||||
|
tryFiles = "$uri $uri/ @fallback";
|
||||||
|
};
|
||||||
|
|
||||||
|
# unversioned files
|
||||||
|
locations."@fallback" = {
|
||||||
|
root = "/var/www/sites/uninsane.org";
|
||||||
|
extraConfig = ''
|
||||||
|
# instruct Google to not index these pages.
|
||||||
|
# see: <https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#xrobotstag>
|
||||||
|
add_header X-Robots-Tag 'none, noindex, nofollow';
|
||||||
|
|
||||||
|
# best-effort attempt to block archive.org from archiving these pages.
|
||||||
|
# reply with 403: Forbidden
|
||||||
|
# User Agent is *probably* "archive.org_bot"; maybe used to be "ia_archiver"
|
||||||
|
# source: <https://archive.org/details/archive.org_bot>
|
||||||
|
# additional UAs: <https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker>
|
||||||
|
#
|
||||||
|
# validate with: `curl -H 'User-Agent: "bot;archive.org_bot;like: something else"' -v https://uninsane.org/dne`
|
||||||
|
if ($http_user_agent ~* "(?:\b)archive.org_bot(?:\b)") {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
if ($http_user_agent ~* "(?:\b)archive.org(?:\b)") {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
if ($http_user_agent ~* "(?:\b)ia_archiver(?:\b)") {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# uninsane.org/share/foo => /var/www/sites/uninsane.org/share/foo.
|
||||||
|
# special-cased to enable directory listings
|
||||||
|
locations."/share" = {
|
||||||
|
root = "/var/www/sites/uninsane.org";
|
||||||
|
extraConfig = ''
|
||||||
|
# autoindex => render directory listings
|
||||||
|
autoindex on;
|
||||||
|
# don't follow any symlinks when serving files
|
||||||
|
# otherwise it allows a directory escape
|
||||||
|
disable_symlinks on;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
locations."/share/Milkbags/" = {
|
||||||
|
alias = "/var/media/Videos/Milkbags/";
|
||||||
|
extraConfig = ''
|
||||||
|
# autoindex => render directory listings
|
||||||
|
autoindex on;
|
||||||
|
# don't follow any symlinks when serving files
|
||||||
|
# otherwise it allows a directory escape
|
||||||
|
disable_symlinks on;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
locations."/share/Ubunchu/" = {
|
||||||
|
alias = "/var/media/Books/Visual/HiroshiSeo/Ubunchu/";
|
||||||
|
extraConfig = ''
|
||||||
|
# autoindex => render directory listings
|
||||||
|
autoindex on;
|
||||||
|
# don't follow any symlinks when serving files
|
||||||
|
# otherwise it allows a directory escape
|
||||||
|
disable_symlinks on;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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
|
||||||
|
# see: https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3361/
|
||||||
|
# not sure this makes sense while i run multiple AP services (pleroma, lemmy)
|
||||||
|
# locations."/.well-known/nodeinfo" = {
|
||||||
|
# proxyPass = "http://127.0.0.1:4000";
|
||||||
|
# extraConfig = pleromaExtraConfig;
|
||||||
|
# };
|
||||||
|
|
||||||
|
# redirect common feed URIs to the canonical feed
|
||||||
|
locations."= /atom".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /feed".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /feed.xml".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /rss".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /rss.xml".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /blog/atom".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /blog/atom.xml".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /blog/feed".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /blog/feed.xml".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /blog/rss".extraConfig = "return 301 /atom.xml;";
|
||||||
|
locations."= /blog/rss.xml".extraConfig = "return 301 /atom.xml;";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
# 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.byStore.plaintext = [
|
||||||
|
{ user = "acme"; group = "acme"; path = "/var/lib/acme"; method = "bind"; }
|
||||||
|
];
|
||||||
|
sane.persist.sys.byStore.private = [
|
||||||
|
{ user = "colin"; group = "users"; path = "/var/www/sites"; method = "bind"; }
|
||||||
|
];
|
||||||
|
sane.persist.sys.byStore.ephemeral = [
|
||||||
|
# logs *could* be persisted to private storage, but then there's the issue of
|
||||||
|
# "what if servo boots, isn't unlocked, and the whole / tmpfs is consumed by logs"
|
||||||
|
{ user = "nginx"; group = "nginx"; path = "/var/log/nginx"; method = "bind"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
# 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 || ${lib.getExe pkgs.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,111 +0,0 @@
|
|||||||
# docs: <https://nixos.wiki/wiki/Nginx>
|
|
||||||
# docs: <https://nginx.org/en/docs/>
|
|
||||||
{ lib, pkgs, ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./uninsane.org.nix
|
|
||||||
./waka.laka.osaka
|
|
||||||
];
|
|
||||||
|
|
||||||
sane.ports.ports."80" = {
|
|
||||||
protocol = [ "tcp" ];
|
|
||||||
visibleTo.lan = true;
|
|
||||||
visibleTo.ovpns = true; # so that letsencrypt can procure a cert for the mx record
|
|
||||||
visibleTo.doof = true;
|
|
||||||
description = "colin-http-uninsane.org";
|
|
||||||
};
|
|
||||||
sane.ports.ports."443" = {
|
|
||||||
protocol = [ "tcp" ];
|
|
||||||
visibleTo.lan = true;
|
|
||||||
visibleTo.doof = true;
|
|
||||||
description = "colin-https-uninsane.org";
|
|
||||||
};
|
|
||||||
|
|
||||||
services.nginx.enable = true;
|
|
||||||
|
|
||||||
users.users.nginx.extraGroups = [ "anubis" ];
|
|
||||||
# nginxStable is one release behind nginxMainline.
|
|
||||||
# nginx itself recommends running mainline; nixos defaults to stable.
|
|
||||||
# services.nginx.package = pkgs.nginxMainline;
|
|
||||||
# XXX(2024-07-31): nixos defaults to zlib-ng -- supposedly more performant, but spams log with
|
|
||||||
# "gzip filter failed to use preallocated memory: ..."
|
|
||||||
# XXX(2025-07-24): "gzip filter" spam is gone => use default nginx package
|
|
||||||
# services.nginx.package = pkgs.nginxMainline.override { zlib = pkgs.zlib; };
|
|
||||||
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;
|
|
||||||
'';
|
|
||||||
# enables gzip and sets gzip_comp_level = 5
|
|
||||||
services.nginx.recommendedGzipSettings = true;
|
|
||||||
# enables zstd and sets zstd_comp_level = 9
|
|
||||||
# services.nginx.recommendedZstdSettings = true; #< XXX(2025-07-18): nginx zstd integration is unmaintained in NixOS
|
|
||||||
# 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;
|
|
||||||
|
|
||||||
|
|
||||||
# serve any site not otherwise declared, 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.byStore.plaintext = [
|
|
||||||
{ user = "acme"; group = "acme"; path = "/var/lib/acme"; method = "bind"; }
|
|
||||||
];
|
|
||||||
sane.persist.sys.byStore.private = [
|
|
||||||
{ user = "colin"; group = "users"; path = "/var/www/sites"; method = "bind"; }
|
|
||||||
];
|
|
||||||
sane.persist.sys.byStore.ephemeral = [
|
|
||||||
# logs *could* be persisted to private storage, but then there's the issue of
|
|
||||||
# "what if servo boots, isn't unlocked, and the whole / tmpfs is consumed by logs"
|
|
||||||
{ user = "nginx"; group = "nginx"; path = "/var/log/nginx"; method = "bind"; }
|
|
||||||
];
|
|
||||||
|
|
||||||
# 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 || ${lib.getExe pkgs.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,132 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
# alternative way to link stuff into the share:
|
|
||||||
# sane.fs."/var/www/sites/uninsane.org/share/Ubunchu".mount.bind = "/var/media/Books/Visual/HiroshiSeo/Ubunchu";
|
|
||||||
# sane.fs."/var/media/Books/Visual/HiroshiSeo/Ubunchu".dir = {};
|
|
||||||
services.nginx.virtualHosts."uninsane.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;
|
|
||||||
|
|
||||||
# extraConfig = ''
|
|
||||||
# # "public" log so requests show up in goaccess metrics
|
|
||||||
# access_log /var/log/nginx/public.log vcombined;
|
|
||||||
# '';
|
|
||||||
|
|
||||||
locations."/" = {
|
|
||||||
root = "${pkgs.uninsane-dot-org}/share/uninsane-dot-org";
|
|
||||||
tryFiles = "$uri $uri/ @fallback";
|
|
||||||
};
|
|
||||||
|
|
||||||
# unversioned files
|
|
||||||
locations."@fallback" = {
|
|
||||||
root = "/var/www/sites/uninsane.org";
|
|
||||||
extraConfig = ''
|
|
||||||
# instruct Google to not index these pages.
|
|
||||||
# see: <https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#xrobotstag>
|
|
||||||
add_header X-Robots-Tag 'none, noindex, nofollow';
|
|
||||||
|
|
||||||
# best-effort attempt to block archive.org from archiving these pages.
|
|
||||||
# reply with 403: Forbidden
|
|
||||||
# User Agent is *probably* "archive.org_bot"; maybe used to be "ia_archiver"
|
|
||||||
# source: <https://archive.org/details/archive.org_bot>
|
|
||||||
# additional UAs: <https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker>
|
|
||||||
#
|
|
||||||
# validate with: `curl -H 'User-Agent: "bot;archive.org_bot;like: something else"' -v https://uninsane.org/dne`
|
|
||||||
if ($http_user_agent ~* "(?:\b)archive.org_bot(?:\b)") {
|
|
||||||
return 403;
|
|
||||||
}
|
|
||||||
if ($http_user_agent ~* "(?:\b)archive.org(?:\b)") {
|
|
||||||
return 403;
|
|
||||||
}
|
|
||||||
if ($http_user_agent ~* "(?:\b)ia_archiver(?:\b)") {
|
|
||||||
return 403;
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# uninsane.org/share/foo => /var/www/sites/uninsane.org/share/foo.
|
|
||||||
# special-cased to enable directory listings
|
|
||||||
locations."/share" = {
|
|
||||||
root = "/var/www/sites/uninsane.org";
|
|
||||||
extraConfig = ''
|
|
||||||
# autoindex => render directory listings
|
|
||||||
autoindex on;
|
|
||||||
# don't follow any symlinks when serving files
|
|
||||||
# otherwise it allows a directory escape
|
|
||||||
disable_symlinks on;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
locations."/share/Milkbags/" = {
|
|
||||||
alias = "/var/media/Videos/Milkbags/";
|
|
||||||
extraConfig = ''
|
|
||||||
# autoindex => render directory listings
|
|
||||||
autoindex on;
|
|
||||||
# don't follow any symlinks when serving files
|
|
||||||
# otherwise it allows a directory escape
|
|
||||||
disable_symlinks on;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
locations."/share/Ubunchu/" = {
|
|
||||||
alias = "/var/media/Books/Visual/HiroshiSeo/Ubunchu/";
|
|
||||||
extraConfig = ''
|
|
||||||
# autoindex => render directory listings
|
|
||||||
autoindex on;
|
|
||||||
# don't follow any symlinks when serving files
|
|
||||||
# otherwise it allows a directory escape
|
|
||||||
disable_symlinks on;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# 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".extraConfig = "return 301 https://matrix.uninsane.org$request_uri;";
|
|
||||||
locations."/_synapse".extraConfig = "return 301 https://matrix.uninsane.org$request_uri;";
|
|
||||||
|
|
||||||
# allow ActivityPub clients to discover how to reach @user@uninsane.org
|
|
||||||
# see: https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3361/
|
|
||||||
# not sure this makes sense while i run multiple AP services (pleroma, lemmy)
|
|
||||||
# locations."/.well-known/nodeinfo" = {
|
|
||||||
# proxyPass = "http://127.0.0.1:4000";
|
|
||||||
# extraConfig = pleromaExtraConfig;
|
|
||||||
# };
|
|
||||||
|
|
||||||
# redirect common feed URIs to the canonical feed
|
|
||||||
locations."= /atom".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /feed".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /feed.xml".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /rss".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /rss.xml".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /blog/atom".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /blog/atom.xml".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /blog/feed".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /blog/feed.xml".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /blog/rss".extraConfig = "return 301 /atom.xml;";
|
|
||||||
locations."= /blog/rss.xml".extraConfig = "return 301 /atom.xml;";
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,35 +0,0 @@
|
|||||||
{ config, pkgs, ... }:
|
|
||||||
let
|
|
||||||
wakaLakaOsaka = pkgs.linkFarm "waka-laka-osaka" {
|
|
||||||
"index.html" = ./index.html;
|
|
||||||
"waka.laka.for.osaka.mp4" = pkgs.fetchurl {
|
|
||||||
# saved from: <https://www.youtube.com/watch?v=ehB_7bBKprY>
|
|
||||||
url = "https://uninsane.org/share/Milkbags/PG_Plays_Video_Games-Waka_Laka_For_Osaka_4K.mp4";
|
|
||||||
hash = "sha256-UW0qR4btX4pZ1bJp4Oxk20m3mvQGj9HweLKO27JBTFs=";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
services.nginx.virtualHosts."laka.osaka" = {
|
|
||||||
addSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
locations."/" = {
|
|
||||||
# redirect everything to waka.laka.osaka
|
|
||||||
return = "301 https://waka.laka.osaka$request_uri";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
services.nginx.virtualHosts."waka.laka.osaka" = {
|
|
||||||
addSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
locations."/" = {
|
|
||||||
root = wakaLakaOsaka;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.dns.zones."laka.osaka".inet = {
|
|
||||||
SOA."@" = config.sane.dns.zones."uninsane.org".inet.SOA."@";
|
|
||||||
A."@" = config.sane.dns.zones."uninsane.org".inet.A."@";
|
|
||||||
NS."@" = config.sane.dns.zones."uninsane.org".inet.NS."@";
|
|
||||||
CNAME."waka" = "native.uninsane.org.";
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,46 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width initial-scale=1" />
|
|
||||||
<meta name="description" content="Waka Laka (for Osaka)" />
|
|
||||||
<title>Waka Laka (for Osaka)</title>
|
|
||||||
<style>
|
|
||||||
html,body {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
max-height: 100%;
|
|
||||||
}
|
|
||||||
* {
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
border: 0px;
|
|
||||||
}
|
|
||||||
.bg-image {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
min-width: 100%;
|
|
||||||
min-height: 100%;
|
|
||||||
position: fixed;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: 50% 50%;
|
|
||||||
background-size: contain;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
background-color: #000000;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<!-- TODO: how to autoplay video _without_ it being muted? -->
|
|
||||||
<video class="bg-image" id="waka-video" width="1440" height="1080"
|
|
||||||
autoplay loop muted
|
|
||||||
onclick="document.getElementById('waka-video').muted = !document.getElementById('waka-video').muted;"
|
|
||||||
>
|
|
||||||
<!-- from https://www.youtube.com/watch?v=ehB_7bBKprY -->
|
|
||||||
<!-- original and more info at https://www.aquilinestudios.org/wakalaka.html -->
|
|
||||||
<source src="waka.laka.for.osaka.mp4" type="video/mp4">
|
|
||||||
</video>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@@ -6,7 +6,7 @@ lib.optionalAttrs false # disabled until i can be sure it's not gonna OOM my se
|
|||||||
description = "build a nixos image with all updated deps";
|
description = "build a nixos image with all updated deps";
|
||||||
path = with pkgs; [ coreutils git nix ];
|
path = with pkgs; [ coreutils git nix ];
|
||||||
script = ''
|
script = ''
|
||||||
working=$(mktemp -d nixos-prebuild.XXXXXX --tmpdir)
|
working=$(mktemp -d /tmp/nixos-prebuild.XXXXXX)
|
||||||
pushd "$working"
|
pushd "$working"
|
||||||
git clone https://git.uninsane.org/colin/nix-files.git \
|
git clone https://git.uninsane.org/colin/nix-files.git \
|
||||||
&& cd nix-files \
|
&& cd nix-files \
|
||||||
|
@@ -14,209 +14,207 @@ let
|
|||||||
# logLevel = "debug";
|
# logLevel = "debug";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = lib.mkIf (config.sane.maxBuildCost >= 2) {
|
sane.persist.sys.byStore.private = [
|
||||||
sane.persist.sys.byStore.private = [
|
# contains media i've uploaded to the server
|
||||||
# contains media i've uploaded to the server
|
{ user = "pleroma"; group = "pleroma"; path = "/var/lib/pleroma"; method = "bind"; }
|
||||||
{ user = "pleroma"; group = "pleroma"; path = "/var/lib/pleroma"; method = "bind"; }
|
];
|
||||||
];
|
services.pleroma.enable = true;
|
||||||
services.pleroma.enable = true;
|
services.pleroma.secretConfigFile = config.sops.secrets.pleroma_secrets.path;
|
||||||
services.pleroma.secretConfigFile = config.sops.secrets.pleroma_secrets.path;
|
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: 4040]
|
http: [ip: {127, 0, 0, 1}, port: 4040]
|
||||||
# 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",
|
||||||
email: "admin.pleroma@uninsane.org",
|
email: "admin.pleroma@uninsane.org",
|
||||||
notify_email: "notify.pleroma@uninsane.org",
|
notify_email: "notify.pleroma@uninsane.org",
|
||||||
limit: 5000,
|
limit: 5000,
|
||||||
registrations_open: true,
|
registrations_open: true,
|
||||||
account_approval_required: true,
|
account_approval_required: true,
|
||||||
max_pinned_statuses: 5,
|
max_pinned_statuses: 5,
|
||||||
external_user_synchronization: true
|
external_user_synchronization: true
|
||||||
|
|
||||||
# docs: https://hexdocs.pm/swoosh/Swoosh.Adapters.Sendmail.html
|
# docs: https://hexdocs.pm/swoosh/Swoosh.Adapters.Sendmail.html
|
||||||
# test mail config with sudo -u pleroma ./bin/pleroma_ctl email test --to someone@somewhere.net
|
# test mail config with sudo -u pleroma ./bin/pleroma_ctl email test --to someone@somewhere.net
|
||||||
config :pleroma, Pleroma.Emails.Mailer,
|
config :pleroma, Pleroma.Emails.Mailer,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
adapter: Swoosh.Adapters.Sendmail,
|
adapter: Swoosh.Adapters.Sendmail,
|
||||||
cmd_path: "${lib.getExe' pkgs.postfix "sendmail"}"
|
cmd_path: "${lib.getExe' pkgs.postfix "sendmail"}"
|
||||||
|
|
||||||
config :pleroma, Pleroma.User,
|
config :pleroma, Pleroma.User,
|
||||||
restricted_nicknames: [ "admin", "uninsane", "root" ]
|
restricted_nicknames: [ "admin", "uninsane", "root" ]
|
||||||
|
|
||||||
config :pleroma, :media_proxy,
|
config :pleroma, :media_proxy,
|
||||||
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:
|
# see for reference:
|
||||||
# - `force_custom_plan`: <https://docs.pleroma.social/backend/configuration/postgresql/#disable-generic-query-plans>
|
# - `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",
|
||||||
database: "pleroma",
|
database: "pleroma",
|
||||||
hostname: "localhost",
|
hostname: "localhost",
|
||||||
pool_size: 10,
|
pool_size: 10,
|
||||||
prepare: :named,
|
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
|
# XXX: prepare: :named is needed only for PG <= 12
|
||||||
# prepare: :named,
|
# prepare: :named,
|
||||||
# password: "{secrets.pleroma.db_password}",
|
# 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.StripLocation]
|
||||||
|
|
||||||
# fix log spam: <https://git.pleroma.social/pleroma/pleroma/-/issues/1659>
|
# fix log spam: <https://git.pleroma.social/pleroma/pleroma/-/issues/1659>
|
||||||
# specifically, remove LAN addresses from `reserved`
|
# specifically, remove LAN addresses from `reserved`
|
||||||
config :pleroma, Pleroma.Web.Plugs.RemoteIp,
|
config :pleroma, Pleroma.Web.Plugs.RemoteIp,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
reserved: ["127.0.0.0/8", "::1/128", "fc00::/7", "172.16.0.0/12"]
|
reserved: ["127.0.0.0/8", "::1/128", "fc00::/7", "172.16.0.0/12"]
|
||||||
|
|
||||||
# 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.
|
# 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
|
||||||
|
|
||||||
|
|
||||||
# (enabled by colin)
|
# (enabled by colin)
|
||||||
# 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: :${logLevel}
|
level: :${logLevel}
|
||||||
|
|
||||||
# policies => list of message rewriting facilities to be enabled
|
# policies => list of message rewriting facilities to be enabled
|
||||||
# transparence => whether to publish these rules in node_info (and /about)
|
# transparence => whether to publish these rules in node_info (and /about)
|
||||||
config :pleroma, :mrf,
|
config :pleroma, :mrf,
|
||||||
policies: [Pleroma.Web.ActivityPub.MRF.SimplePolicy],
|
policies: [Pleroma.Web.ActivityPub.MRF.SimplePolicy],
|
||||||
transparency: true
|
transparency: true
|
||||||
|
|
||||||
# reject => { host, reason }
|
# reject => { host, reason }
|
||||||
config :pleroma, :mrf_simple,
|
config :pleroma, :mrf_simple,
|
||||||
reject: [ {"threads.net", "megacorp"}, {"*.threads.net", "megacorp"} ]
|
reject: [ {"threads.net", "megacorp"}, {"*.threads.net", "megacorp"} ]
|
||||||
# reject: [ [host: "threads.net", reason: "megacorp"], [host: "*.threads.net", reason: "megacorp"] ]
|
# reject: [ [host: "threads.net", reason: "megacorp"], [host: "*.threads.net", reason: "megacorp"] ]
|
||||||
|
|
||||||
# XXX colin: not sure if this actually _does_ anything
|
# XXX colin: not sure if this actually _does_ anything
|
||||||
# better to steal emoji from other instances?
|
# better to steal emoji from other instances?
|
||||||
# - <https://docs.pleroma.social/backend/configuration/cheatsheet/#mrf_steal_emoji>
|
# - <https://docs.pleroma.social/backend/configuration/cheatsheet/#mrf_steal_emoji>
|
||||||
config :pleroma, :emoji,
|
config :pleroma, :emoji,
|
||||||
shortcode_globs: ["/emoji/**/*.png"],
|
shortcode_globs: ["/emoji/**/*.png"],
|
||||||
groups: [
|
groups: [
|
||||||
"Cirno": "/emoji/cirno/*.png",
|
"Cirno": "/emoji/cirno/*.png",
|
||||||
"Kirby": "/emoji/kirby/*.png",
|
"Kirby": "/emoji/kirby/*.png",
|
||||||
"Bun": "/emoji/bun/*.png",
|
"Bun": "/emoji/bun/*.png",
|
||||||
"Yuru Camp": "/emoji/yuru_camp/*.png",
|
"Yuru Camp": "/emoji/yuru_camp/*.png",
|
||||||
]
|
]
|
||||||
''
|
''
|
||||||
];
|
];
|
||||||
|
|
||||||
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
|
||||||
# config.sane.programs.exiftool.package #< XXX(2024-10-20): breaks image uploading
|
# config.sane.programs.exiftool.package #< XXX(2024-10-20): breaks image uploading
|
||||||
# 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
|
||||||
# config.sane.programs.gawk.package
|
# config.sane.programs.gawk.package
|
||||||
# needed for email operations like password reset
|
# needed for email operations like password reset
|
||||||
pkgs.postfix
|
pkgs.postfix
|
||||||
];
|
];
|
||||||
|
|
||||||
systemd.services.pleroma = {
|
systemd.services.pleroma = {
|
||||||
# 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
|
||||||
serviceConfig.Restart = "on-failure";
|
serviceConfig.Restart = "on-failure";
|
||||||
serviceConfig.RestartSec = "10s";
|
serviceConfig.RestartSec = "10s";
|
||||||
|
|
||||||
# hardening (systemd-analyze security pleroma)
|
# hardening (systemd-analyze security pleroma)
|
||||||
# XXX(2024-07-28): this hasn't been rigorously tested:
|
# XXX(2024-07-28): this hasn't been rigorously tested:
|
||||||
# possible that i've set something too strict and won't notice right away
|
# possible that i've set something too strict and won't notice right away
|
||||||
# make sure to test:
|
# make sure to test:
|
||||||
# - image/media uploading
|
# - image/media uploading
|
||||||
serviceConfig.CapabilityBoundingSet = lib.mkForce [ "" "" ]; # nixos default is `~CAP_SYS_ADMIN`
|
serviceConfig.CapabilityBoundingSet = lib.mkForce [ "" "" ]; # nixos default is `~CAP_SYS_ADMIN`
|
||||||
serviceConfig.LockPersonality = true;
|
serviceConfig.LockPersonality = true;
|
||||||
serviceConfig.NoNewPrivileges = true;
|
serviceConfig.NoNewPrivileges = true;
|
||||||
serviceConfig.MemoryDenyWriteExecute = true;
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
serviceConfig.PrivateDevices = lib.mkForce true; #< dunno why nixpkgs has this set false; it seems to work as true
|
serviceConfig.PrivateDevices = lib.mkForce true; #< dunno why nixpkgs has this set false; it seems to work as true
|
||||||
serviceConfig.PrivateMounts = true;
|
serviceConfig.PrivateMounts = true;
|
||||||
serviceConfig.PrivateTmp = true;
|
serviceConfig.PrivateTmp = true;
|
||||||
serviceConfig.PrivateUsers = true;
|
serviceConfig.PrivateUsers = true;
|
||||||
|
|
||||||
serviceConfig.ProtectProc = "invisible";
|
serviceConfig.ProtectProc = "invisible";
|
||||||
serviceConfig.ProcSubset = "all"; #< needs /proc/sys/kernel/overflowuid for bwrap
|
serviceConfig.ProcSubset = "all"; #< needs /proc/sys/kernel/overflowuid for bwrap
|
||||||
|
|
||||||
serviceConfig.ProtectClock = true;
|
serviceConfig.ProtectClock = true;
|
||||||
serviceConfig.ProtectControlGroups = true;
|
serviceConfig.ProtectControlGroups = true;
|
||||||
serviceConfig.ProtectHome = true;
|
serviceConfig.ProtectHome = true;
|
||||||
serviceConfig.ProtectKernelModules = true;
|
serviceConfig.ProtectKernelModules = true;
|
||||||
serviceConfig.ProtectSystem = lib.mkForce "strict";
|
serviceConfig.ProtectSystem = lib.mkForce "strict";
|
||||||
serviceConfig.RemoveIPC = true;
|
serviceConfig.RemoveIPC = true;
|
||||||
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
|
||||||
|
|
||||||
serviceConfig.RestrictSUIDSGID = true;
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
serviceConfig.SystemCallArchitectures = "native";
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
serviceConfig.SystemCallFilter = [ "@system-service" "@mount" "@sandbox" ]; #< "sandbox" might not actually be necessary
|
serviceConfig.SystemCallFilter = [ "@system-service" "@mount" "@sandbox" ]; #< "sandbox" might not actually be necessary
|
||||||
|
|
||||||
serviceConfig.ProtectHostname = false; #< else brap can't mount /proc
|
serviceConfig.ProtectHostname = false; #< else brap can't mount /proc
|
||||||
serviceConfig.ProtectKernelLogs = false; #< else breaks exiftool ("bwrap: Can't mount proc on /newroot/proc: Operation not permitted")
|
serviceConfig.ProtectKernelLogs = false; #< else breaks exiftool ("bwrap: Can't mount proc on /newroot/proc: Operation not permitted")
|
||||||
serviceConfig.ProtectKernelTunables = false; #< else breaks exiftool
|
serviceConfig.ProtectKernelTunables = false; #< else breaks exiftool
|
||||||
serviceConfig.RestrictNamespaces = false; # media uploads require bwrap
|
serviceConfig.RestrictNamespaces = false; # media uploads require bwrap
|
||||||
};
|
};
|
||||||
|
|
||||||
# this is required to allow pleroma to send email.
|
# this is required to allow pleroma to send email.
|
||||||
# raw `sendmail` works, but i think pleroma's passing it some funny flags or something, idk.
|
# raw `sendmail` works, but i think pleroma's passing it some funny flags or something, idk.
|
||||||
# hack to fix that.
|
# hack to fix that.
|
||||||
users.users.pleroma.extraGroups = [ "postdrop" ];
|
users.users.pleroma.extraGroups = [ "postdrop" ];
|
||||||
|
|
||||||
# Pleroma server and web interface
|
# Pleroma server and web interface
|
||||||
# TODO: enable publog?
|
# TODO: enable publog?
|
||||||
services.nginx.virtualHosts."fed.uninsane.org" = {
|
services.nginx.virtualHosts."fed.uninsane.org" = {
|
||||||
forceSSL = true; # pleroma redirects to https anyway
|
forceSSL = true; # pleroma redirects to https anyway
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
# inherit kTLS;
|
# inherit kTLS;
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://127.0.0.1:4040";
|
proxyPass = "http://127.0.0.1:4040";
|
||||||
recommendedProxySettings = true;
|
recommendedProxySettings = true;
|
||||||
# documented: https://git.pleroma.social/pleroma/pleroma/-/blob/develop/installation/pleroma.nginx
|
# documented: https://git.pleroma.social/pleroma/pleroma/-/blob/develop/installation/pleroma.nginx
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
# client_max_body_size defines the maximum upload size
|
# client_max_body_size defines the maximum upload size
|
||||||
client_max_body_size 16m;
|
client_max_body_size 16m;
|
||||||
'';
|
'';
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."fed" = "native";
|
|
||||||
|
|
||||||
sops.secrets."pleroma_secrets" = {
|
|
||||||
owner = config.users.users.pleroma.name;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sane.dns.zones."uninsane.org".inet.CNAME."fed" = "native";
|
||||||
|
|
||||||
|
sops.secrets."pleroma_secrets" = {
|
||||||
|
owner = config.users.users.pleroma.name;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
{ lib, pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
GiB = n: MiB 1024*n;
|
GiB = n: MiB 1024*n;
|
||||||
@@ -78,7 +78,7 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
# regulate the restarts, so that systemd never disables it
|
# regulate the restarts, so that systemd never disables it
|
||||||
systemd.services.postgresql.serviceConfig.Restart = lib.mkForce "on-failure";
|
systemd.services.postgresql.serviceConfig.Restart = "on-failure";
|
||||||
systemd.services.postgresql.serviceConfig.RestartSec = 2;
|
systemd.services.postgresql.serviceConfig.RestartSec = 2;
|
||||||
systemd.services.postgresql.serviceConfig.RestartMaxDelaySec = 10;
|
systemd.services.postgresql.serviceConfig.RestartMaxDelaySec = 10;
|
||||||
systemd.services.postgresql.serviceConfig.RestartSteps = 4;
|
systemd.services.postgresql.serviceConfig.RestartSteps = 4;
|
||||||
|
@@ -173,7 +173,7 @@ in
|
|||||||
domain = "conference.xmpp.uninsane.org";
|
domain = "conference.xmpp.uninsane.org";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
httpFileShare.domain = "upload.xmpp.uninsane.org";
|
uploadHttp.domain = "upload.xmpp.uninsane.org";
|
||||||
|
|
||||||
virtualHosts = {
|
virtualHosts = {
|
||||||
# "Prosody requires at least one enabled VirtualHost to function. You can
|
# "Prosody requires at least one enabled VirtualHost to function. You can
|
||||||
@@ -282,7 +282,6 @@ in
|
|||||||
ntfy_binary = "${lib.getExe' pkgs.ntfy-sh "ntfy"}"
|
ntfy_binary = "${lib.getExe' pkgs.ntfy-sh "ntfy"}"
|
||||||
ntfy_topic = readAll("/run/secrets/ntfy-sh-topic")
|
ntfy_topic = readAll("/run/secrets/ntfy-sh-topic")
|
||||||
'';
|
'';
|
||||||
checkConfig = false; # secrets aren't available at build time
|
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.prosody = {
|
systemd.services.prosody = {
|
||||||
|
@@ -36,7 +36,6 @@
|
|||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://${config.sane.netns.ovpns.veth.netns.ipv4}:5030";
|
proxyPass = "http://${config.sane.netns.ovpns.veth.netns.ipv4}:5030";
|
||||||
proxyWebsockets = true;
|
proxyWebsockets = true;
|
||||||
recommendedProxySettings = true;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -159,7 +159,6 @@ in
|
|||||||
locations."/" = {
|
locations."/" = {
|
||||||
# proxyPass = "http://ovpns.uninsane.org:9091";
|
# proxyPass = "http://ovpns.uninsane.org:9091";
|
||||||
proxyPass = "http://${config.sane.netns.ovpns.veth.netns.ipv4}:9091";
|
proxyPass = "http://${config.sane.netns.ovpns.veth.netns.ipv4}:9091";
|
||||||
recommendedProxySettings = true;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -3,20 +3,8 @@
|
|||||||
|
|
||||||
# transmission invokes this with no args, and the following env vars:
|
# transmission invokes this with no args, and the following env vars:
|
||||||
# - TR_TORRENT_DIR: full path to the folder i told transmission to download it to.
|
# - TR_TORRENT_DIR: full path to the folder i told transmission to download it to.
|
||||||
# e.g. "/var/media/torrents/Videos/Film/Jason.Bourne-2016"
|
# e.g. /var/media/torrents/Videos/Film/Jason.Bourne-2016
|
||||||
# - TR_APP_VERSION
|
# optionally:
|
||||||
# - TR_TIME_LOCALTIME
|
|
||||||
# - TR_TORRENT_BYTES_DOWNLOADED
|
|
||||||
# - TR_TORRENT_HASH
|
|
||||||
# - TR_TORRENT_ID: local number to uniquely identify this torrent, used by e.g. transmission-remote.
|
|
||||||
# e.g. "67"
|
|
||||||
# - TR_TORRENT_LABELS
|
|
||||||
# - TR_TORRENT_NAME: file/folder name of the toplevel torrent item
|
|
||||||
# e.g. "Jason Bourne (2016) [2160p] [4K] [BluRay] [5.1] [YTS.MX]"
|
|
||||||
# - TR_TORRENT_PRIORITY
|
|
||||||
# - TR_TORRENT_TRACKERS
|
|
||||||
|
|
||||||
# optionally, set these variables for debugging (these are specific to my script and not used upstream):
|
|
||||||
# - TR_DRY_RUN=1
|
# - TR_DRY_RUN=1
|
||||||
# - TR_DEBUG=1
|
# - TR_DEBUG=1
|
||||||
|
|
||||||
@@ -36,7 +24,7 @@ debug() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "TR_TORRENT_DIR=$TR_TORRENT_DIR TR_TORRENT_NAME=$TR_TORRENT_NAME torrent-done $*"
|
echo "TR_TORRENT_DIR=$TR_TORRENT_DIR torrent-done $*"
|
||||||
|
|
||||||
if [[ "$TR_TORRENT_DIR" =~ ^.*freeleech.*$ ]]; then
|
if [[ "$TR_TORRENT_DIR" =~ ^.*freeleech.*$ ]]; then
|
||||||
# freeleech torrents have no place in my permanent library
|
# freeleech torrents have no place in my permanent library
|
||||||
@@ -45,35 +33,20 @@ if [[ "$TR_TORRENT_DIR" =~ ^.*freeleech.*$ ]]; then
|
|||||||
fi
|
fi
|
||||||
if ! [[ "$TR_TORRENT_DIR" =~ ^$DOWNLOAD_DIR/.*$ ]]; then
|
if ! [[ "$TR_TORRENT_DIR" =~ ^$DOWNLOAD_DIR/.*$ ]]; then
|
||||||
echo "unexpected torrent dir, aborting: $TR_TORRENT_DIR"
|
echo "unexpected torrent dir, aborting: $TR_TORRENT_DIR"
|
||||||
exit 1
|
exit 0
|
||||||
fi
|
|
||||||
|
|
||||||
TORRENT_PATH="$TR_TORRENT_DIR/$TR_TORRENT_NAME"
|
|
||||||
if [[ ! -e "$TORRENT_PATH" ]]; then
|
|
||||||
echo "torrent unexpectedly doesn't exist at $TORRENT_PATH. will try fallback"
|
|
||||||
TORRENT_PATH="$TR_TORRENT_DIR"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -d "$TORRENT_PATH" ]]; then
|
|
||||||
# trailing slash so that rsync copies the directory contents, without creating an extra toplevel dir.
|
|
||||||
TORRENT_PATH="$TORRENT_PATH/"
|
|
||||||
elif [[ ! -e "$TORRENT_PATH" ]]; then
|
|
||||||
echo "torrent unexpectedly doesn't exist at TR_TORRENT_DIR=$TORRENT_PATH: bailing"
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
REL_DIR="${TR_TORRENT_DIR#$DOWNLOAD_DIR/}"
|
REL_DIR="${TR_TORRENT_DIR#$DOWNLOAD_DIR/}"
|
||||||
MEDIA_DIR="/var/media/$REL_DIR"
|
MEDIA_DIR="/var/media/$REL_DIR"
|
||||||
|
|
||||||
destructive mkdir -p "$(dirname "$MEDIA_DIR")"
|
destructive mkdir -p "$(dirname "$MEDIA_DIR")"
|
||||||
destructive rsync -rlv "$TORRENT_PATH" "$MEDIA_DIR/"
|
destructive rsync -rlv "$TR_TORRENT_DIR/" "$MEDIA_DIR/"
|
||||||
# make the media rwx by anyone in the group
|
# make the media rwx by anyone in the group
|
||||||
destructive find "$MEDIA_DIR" -type d -exec setfacl --recursive --modify d:g::rwx,o::rx {} \;
|
destructive find "$MEDIA_DIR" -type d -exec setfacl --recursive --modify d:g::rwx,o::rx {} \;
|
||||||
destructive find "$MEDIA_DIR" -type d -exec chmod g+rw,a+rx {} \;
|
destructive find "$MEDIA_DIR" -type d -exec chmod g+rw,a+rx {} \;
|
||||||
destructive find "$MEDIA_DIR" -type f -exec chmod g+rw,a+r {} \;
|
destructive find "$MEDIA_DIR" -type f -exec chmod g+rw,a+r {} \;
|
||||||
|
|
||||||
# if there's a single directory inside the media dir, then inline that.
|
# if there's a single directory inside the media dir, then inline that
|
||||||
# TODO: this is probably obsolete now that i process TR_TORRENT_NAME
|
|
||||||
subdirs=("$MEDIA_DIR"/*)
|
subdirs=("$MEDIA_DIR"/*)
|
||||||
debug "top-level items in torrent dir:" "${subdirs[@]}"
|
debug "top-level items in torrent dir:" "${subdirs[@]}"
|
||||||
if [ ${#subdirs[@]} -eq 1 ]; then
|
if [ ${#subdirs[@]} -eq 1 ]; then
|
||||||
@@ -88,24 +61,10 @@ fi
|
|||||||
# -iname means "insensitive", but the syntax is NOT regex -- more similar to shell matching
|
# -iname means "insensitive", but the syntax is NOT regex -- more similar to shell matching
|
||||||
destructive find "$MEDIA_DIR/" -type f \(\
|
destructive find "$MEDIA_DIR/" -type f \(\
|
||||||
-iname '*downloaded?from*' \
|
-iname '*downloaded?from*' \
|
||||||
-o -iname '(xxxpav69).txt' \
|
-o -iname 'source.txt' \
|
||||||
-o -iname '*upcoming?releases*' \
|
-o -iname '*upcoming?releases*' \
|
||||||
-o -iname 'ETRG.mp4' \
|
-o -iname 'www.YTS*.jpg' \
|
||||||
-o -iname 'Encoded by*.txt' \
|
|
||||||
-o -iname 'PSArips.com.txt' \
|
|
||||||
-o -iname 'RARBG.com*' \
|
|
||||||
-o -iname 'RARBG.txt' \
|
|
||||||
-o -iname 'RARBG_DO_NOT_MIRROR.exe' \
|
|
||||||
-o -iname 'Tellytorrent.net.txt' \
|
|
||||||
-o -iname 'WWW.VPPV.LA.txt' \
|
|
||||||
-o -iname 'WWW.YIFY*.COM.jpg' \
|
-o -iname 'WWW.YIFY*.COM.jpg' \
|
||||||
-o -iname 'YIFY*.com.txt' \
|
-o -iname 'YIFY*.com.txt' \
|
||||||
-o -iname 'YTS*.com.txt' \
|
-o -iname 'YTS*.com.txt' \
|
||||||
-o -iname 'YTSYify*.txt' \
|
|
||||||
-o -iname 'www.YTS*.jpg' \
|
|
||||||
\) -exec rm {} \;
|
\) -exec rm {} \;
|
||||||
|
|
||||||
# might want to keep, might want to remove:
|
|
||||||
# -o -iname 'info.txt'
|
|
||||||
# -o -iname 'source.txt'
|
|
||||||
# -o -iname 'sample.mkv'
|
|
||||||
|
@@ -4,12 +4,11 @@
|
|||||||
# useful emergency utils
|
# useful emergency utils
|
||||||
boot.initrd.extraUtilsCommands = ''
|
boot.initrd.extraUtilsCommands = ''
|
||||||
copy_bin_and_libs ${lib.getExe' pkgs.btrfs-progs "btrfstune"}
|
copy_bin_and_libs ${lib.getExe' pkgs.btrfs-progs "btrfstune"}
|
||||||
copy_bin_and_libs ${lib.getExe' pkgs.e2fsprogs "resize2fs"}
|
|
||||||
copy_bin_and_libs ${lib.getExe' pkgs.gptfdisk "{cgdisk,gdisk}"}
|
|
||||||
copy_bin_and_libs ${lib.getExe' pkgs.mtools "mlabel"}
|
|
||||||
copy_bin_and_libs ${lib.getExe pkgs.nvme-cli}
|
|
||||||
copy_bin_and_libs ${lib.getExe' pkgs.smartmontools "smartctl"}
|
|
||||||
copy_bin_and_libs ${lib.getExe' pkgs.util-linux "{cfdisk,lsblk,lscpu}"}
|
copy_bin_and_libs ${lib.getExe' pkgs.util-linux "{cfdisk,lsblk,lscpu}"}
|
||||||
|
copy_bin_and_libs ${lib.getExe' pkgs.gptfdisk "{cgdisk,gdisk}"}
|
||||||
|
copy_bin_and_libs ${lib.getExe' pkgs.smartmontools "smartctl"}
|
||||||
|
copy_bin_and_libs ${lib.getExe' pkgs.e2fsprogs "resize2fs"}
|
||||||
|
copy_bin_and_libs ${lib.getExe pkgs.nvme-cli}
|
||||||
'';
|
'';
|
||||||
boot.kernelParams = [
|
boot.kernelParams = [
|
||||||
"boot.shell_on_fail"
|
"boot.shell_on_fail"
|
||||||
@@ -29,7 +28,6 @@
|
|||||||
# simpler to keep near the latest kernel on all devices,
|
# simpler to keep near the latest kernel on all devices,
|
||||||
# and also makes certain that any weird system-level bugs i see aren't likely to be stale kernel bugs.
|
# and also makes certain that any weird system-level bugs i see aren't likely to be stale kernel bugs.
|
||||||
boot.kernelPackages = lib.mkDefault pkgs.linuxPackages_latest;
|
boot.kernelPackages = lib.mkDefault pkgs.linuxPackages_latest;
|
||||||
# boot.kernelPackages = lib.mkDefault pkgs.linuxPackages_testing;
|
|
||||||
|
|
||||||
# hack in the `boot.shell_on_fail` arg since that doesn't always seem to work.
|
# hack in the `boot.shell_on_fail` arg since that doesn't always seem to work.
|
||||||
boot.initrd.preFailCommands = "allowShell=1";
|
boot.initrd.preFailCommands = "allowShell=1";
|
||||||
@@ -38,12 +36,7 @@
|
|||||||
boot.consoleLogLevel = 7;
|
boot.consoleLogLevel = 7;
|
||||||
|
|
||||||
boot.loader.grub.enable = lib.mkDefault false;
|
boot.loader.grub.enable = lib.mkDefault false;
|
||||||
# boot.loader.generic-extlinux-compatible.enable = lib.mkDefault true;
|
boot.loader.generic-extlinux-compatible.enable = lib.mkDefault true;
|
||||||
boot.loader.systemd-boot.enable = lib.mkDefault true;
|
|
||||||
boot.loader.systemd-boot.configurationLimit = lib.mkDefault 20;
|
|
||||||
boot.loader.systemd-boot.edk2-uefi-shell.enable = lib.mkDefault true;
|
|
||||||
boot.loader.systemd-boot.memtest86.enable = lib.mkDefault
|
|
||||||
(lib.meta.availableOn pkgs.stdenv.hostPlatform pkgs.memtest86plus);
|
|
||||||
|
|
||||||
hardware.enableAllFirmware = true; # firmware with licenses that don't allow for redistribution. fuck lawyers, fuck IP, give me the goddamn firmware.
|
hardware.enableAllFirmware = true; # firmware with licenses that don't allow for redistribution. fuck lawyers, fuck IP, give me the goddamn firmware.
|
||||||
# hardware.enableRedistributableFirmware = true; # proprietary but free-to-distribute firmware (extraneous to `enableAllFirmware` option)
|
# hardware.enableRedistributableFirmware = true; # proprietary but free-to-distribute firmware (extraneous to `enableAllFirmware` option)
|
||||||
|
@@ -30,7 +30,6 @@
|
|||||||
sane.persist.enable = lib.mkDefault true;
|
sane.persist.enable = lib.mkDefault true;
|
||||||
sane.root-on-tmpfs = lib.mkDefault true;
|
sane.root-on-tmpfs = lib.mkDefault true;
|
||||||
sane.programs.sysadminUtils.enableFor.system = lib.mkDefault true;
|
sane.programs.sysadminUtils.enableFor.system = lib.mkDefault true;
|
||||||
sane.programs.sysadminExtraUtils.enableFor.system = lib.mkDefault true;
|
|
||||||
sane.programs.consoleUtils.enableFor.user.colin = lib.mkDefault true;
|
sane.programs.consoleUtils.enableFor.user.colin = lib.mkDefault true;
|
||||||
|
|
||||||
services.buffyboard.enable = true;
|
services.buffyboard.enable = true;
|
||||||
|
@@ -9,7 +9,6 @@
|
|||||||
# - active lemmy: <https://slrpnk.net/c/podcasts>
|
# - active lemmy: <https://slrpnk.net/c/podcasts>
|
||||||
# - old thread: <https://lemmy.ml/post/1565858>
|
# - old thread: <https://lemmy.ml/post/1565858>
|
||||||
#
|
#
|
||||||
# - paywall bypass / bootlegs: <https://jumble.top/>
|
|
||||||
{ lib, sane-data, ... }:
|
{ lib, sane-data, ... }:
|
||||||
let
|
let
|
||||||
hourly = { freq = "hourly"; };
|
hourly = { freq = "hourly"; };
|
||||||
@@ -67,15 +66,12 @@ let
|
|||||||
(fromDb "api.oyez.org/podcasts/oral-arguments/2015" // pol) # Supreme Court Oral Arguments ("2015" in URL means nothing -- it's still updated)
|
(fromDb "api.oyez.org/podcasts/oral-arguments/2015" // pol) # Supreme Court Oral Arguments ("2015" in URL means nothing -- it's still updated)
|
||||||
(fromDb "anchor.fm/s/34c7232c/podcast/rss" // tech) # Civboot -- https://anchor.fm/civboot
|
(fromDb "anchor.fm/s/34c7232c/podcast/rss" // tech) # Civboot -- https://anchor.fm/civboot
|
||||||
(fromDb "anchor.fm/s/2da69154/podcast/rss" // tech) # POD OF JAKE -- https://podofjake.com/
|
(fromDb "anchor.fm/s/2da69154/podcast/rss" // tech) # POD OF JAKE -- https://podofjake.com/
|
||||||
(fromDb "bluecityblues.org.podcastpage.io" // pol) # hosts overlap with Seattle Nice
|
|
||||||
(fromDb "buzzsprout.com/2126417" // tech) # Mystery AI Hype Theater 3000
|
|
||||||
(fromDb "cast.postmarketos.org" // tech)
|
(fromDb "cast.postmarketos.org" // tech)
|
||||||
(fromDb "congressionaldish.libsyn.com" // pol) # Jennifer Briney
|
(fromDb "congressionaldish.libsyn.com" // pol) # Jennifer Briney
|
||||||
(fromDb "craphound.com" // pol) # Cory Doctorow -- both podcast & text entries
|
(fromDb "craphound.com" // pol) # Cory Doctorow -- both podcast & text entries
|
||||||
(fromDb "darknetdiaries.com" // tech)
|
(fromDb "darknetdiaries.com" // tech)
|
||||||
(fromDb "dwarkeshpatel.com" // tech)
|
(fromDb "dwarkeshpatel.com" // tech)
|
||||||
(fromDb "feeds.99percentinvisible.org/99percentinvisible" // pol) # 99% Invisible -- also available here: <https://feeds.simplecast.com/BqbsxVfO>
|
(fromDb "feeds.99percentinvisible.org/99percentinvisible" // pol) # 99% Invisible -- also available here: <https://feeds.simplecast.com/BqbsxVfO>
|
||||||
(fromDb "feeds.acast.com/public/shows/lawfare" // pol) # <https://www.lawfaremedia.org/podcasts-multimedia/podcast/the-lawfare-podcast>
|
|
||||||
(fromDb "feeds.buzzsprout.com/2412334.rss") # Matt Stoller's _Organized Money_ <https://www.organizedmoney.fm/>
|
(fromDb "feeds.buzzsprout.com/2412334.rss") # Matt Stoller's _Organized Money_ <https://www.organizedmoney.fm/>
|
||||||
(fromDb "feeds.eff.org/howtofixtheinternet" // pol)
|
(fromDb "feeds.eff.org/howtofixtheinternet" // pol)
|
||||||
(fromDb "feeds.feedburner.com/80000HoursPodcast" // rat)
|
(fromDb "feeds.feedburner.com/80000HoursPodcast" // rat)
|
||||||
@@ -91,6 +87,7 @@ let
|
|||||||
(fromDb "feeds.megaphone.fm/thiswontlast" // tech) # <https://www.podpage.com/thiswontlast/>
|
(fromDb "feeds.megaphone.fm/thiswontlast" // tech) # <https://www.podpage.com/thiswontlast/>
|
||||||
(fromDb "feeds.megaphone.fm/unexplainable")
|
(fromDb "feeds.megaphone.fm/unexplainable")
|
||||||
(fromDb "feeds.simplecast.com/wgl4xEgL" // rat) # Econ Talk
|
(fromDb "feeds.simplecast.com/wgl4xEgL" // rat) # Econ Talk
|
||||||
|
(fromDb "feeds.simplecast.com/whlwDbyc" // tech) # Tech Lounge: <https://chrischinchilla.com/podcast/techlounge/>
|
||||||
(fromDb "feeds.transistor.fm/acquired" // tech)
|
(fromDb "feeds.transistor.fm/acquired" // tech)
|
||||||
(fromDb "feeds.transistor.fm/complex-systems-with-patrick-mckenzie-patio11" // tech) # Patrick Mackenzie (from Bits About Money)
|
(fromDb "feeds.transistor.fm/complex-systems-with-patrick-mckenzie-patio11" // tech) # Patrick Mackenzie (from Bits About Money)
|
||||||
(fromDb "feeds.twit.tv/floss.xml" // tech)
|
(fromDb "feeds.twit.tv/floss.xml" // tech)
|
||||||
@@ -100,11 +97,8 @@ let
|
|||||||
(fromDb "lexfridman.com/podcast" // rat)
|
(fromDb "lexfridman.com/podcast" // rat)
|
||||||
(fromDb "linktr.ee/betteroffline" // pol)
|
(fromDb "linktr.ee/betteroffline" // pol)
|
||||||
(fromDb "linuxdevtime.com" // tech)
|
(fromDb "linuxdevtime.com" // tech)
|
||||||
(fromDb "malicious.life" // tech)
|
|
||||||
(fromDb "mapspodcast.libsyn.com" // uncat) # Multidisciplinary Association for Psychedelic Studies
|
(fromDb "mapspodcast.libsyn.com" // uncat) # Multidisciplinary Association for Psychedelic Studies
|
||||||
(fromDb "motherearthnewsandfriends.libsyn.com" // uncat) # off-grid living
|
|
||||||
(fromDb "microarch.club" // tech)
|
(fromDb "microarch.club" // tech)
|
||||||
(fromDb "nocturnepodcast.org")
|
|
||||||
(fromDb "omegataupodcast.net" // tech) # 3/4 German; 1/4 eps are English
|
(fromDb "omegataupodcast.net" // tech) # 3/4 German; 1/4 eps are English
|
||||||
(fromDb "omny.fm/shows/cool-people-who-did-cool-stuff" // pol) # Maggie Killjoy -- referenced by Cory Doctorow
|
(fromDb "omny.fm/shows/cool-people-who-did-cool-stuff" // pol) # Maggie Killjoy -- referenced by Cory Doctorow
|
||||||
(fromDb "omny.fm/shows/money-stuff-the-podcast") # Matt Levine
|
(fromDb "omny.fm/shows/money-stuff-the-podcast") # Matt Levine
|
||||||
@@ -112,8 +106,8 @@ let
|
|||||||
(fromDb "omny.fm/shows/the-dollop-with-dave-anthony-and-gareth-reynolds") # The Dollop history/comedy
|
(fromDb "omny.fm/shows/the-dollop-with-dave-anthony-and-gareth-reynolds") # The Dollop history/comedy
|
||||||
(fromDb "omny.fm/shows/weird-little-guys") # Cool Zone Media
|
(fromDb "omny.fm/shows/weird-little-guys") # Cool Zone Media
|
||||||
(fromDb "originstories.libsyn.com" // uncat)
|
(fromDb "originstories.libsyn.com" // uncat)
|
||||||
|
(fromDb "politicspoliticspolitics.com" // pol) # don't judge me. Justin Robert Young.
|
||||||
(fromDb "podcast.ergaster.org/@flintandsilicon" // tech) # Thib's podcast: public interest tech, gnome, etc: <https://fed.uninsane.org/users/$ALLO9MZ5g5CsQTCBH6>
|
(fromDb "podcast.ergaster.org/@flintandsilicon" // tech) # Thib's podcast: public interest tech, gnome, etc: <https://fed.uninsane.org/users/$ALLO9MZ5g5CsQTCBH6>
|
||||||
(fromDb "pods.media/api/rss/feed/channel/unchained" // tech) # cryptocurrency happenings; rec via patio11
|
|
||||||
(fromDb "politicalorphanage.libsyn.com" // pol)
|
(fromDb "politicalorphanage.libsyn.com" // pol)
|
||||||
(fromDb "reverseengineering.libsyn.com/rss" // tech) # UnNamed Reverse Engineering Podcast
|
(fromDb "reverseengineering.libsyn.com/rss" // tech) # UnNamed Reverse Engineering Podcast
|
||||||
(fromDb "rss.acast.com/ft-tech-tonic" // tech) # Financial Time's: Tech Tonic
|
(fromDb "rss.acast.com/ft-tech-tonic" // tech) # Financial Time's: Tech Tonic
|
||||||
@@ -126,6 +120,7 @@ let
|
|||||||
(fromDb "sscpodcast.libsyn.com" // rat) # Astral Codex Ten; Scott Alexander
|
(fromDb "sscpodcast.libsyn.com" // rat) # Astral Codex Ten; Scott Alexander
|
||||||
(fromDb "talesfromthebridge.buzzsprout.com" // tech) # Sci-Fi? has Peter Watts; author of No Moods, Ads or Cutesy Fucking Icons (rifters.com)
|
(fromDb "talesfromthebridge.buzzsprout.com" // tech) # Sci-Fi? has Peter Watts; author of No Moods, Ads or Cutesy Fucking Icons (rifters.com)
|
||||||
(fromDb "techtalesshow.com" // tech) # Corbin Davenport
|
(fromDb "techtalesshow.com" // tech) # Corbin Davenport
|
||||||
|
(fromDb "techwontsave.us" // pol) # rec by Cory Doctorow
|
||||||
(fromDb "theamphour.com" // tech) # The Amp Hour
|
(fromDb "theamphour.com" // tech) # The Amp Hour
|
||||||
(fromDb "the-ben-marc-show.simplecast.com" // tech // pol) # Ben Horowitz + Marc Andreessen; love to hate em
|
(fromDb "the-ben-marc-show.simplecast.com" // tech // pol) # Ben Horowitz + Marc Andreessen; love to hate em
|
||||||
(fromDb "timclicks.dev/compose-podcast" // tech) # Rust-heavy dev interviews
|
(fromDb "timclicks.dev/compose-podcast" // tech) # Rust-heavy dev interviews
|
||||||
@@ -140,23 +135,18 @@ let
|
|||||||
# (fromDb "feeds.simplecast.com/54nAGcIl" // pol) # The Daily
|
# (fromDb "feeds.simplecast.com/54nAGcIl" // pol) # The Daily
|
||||||
# (fromDb "feeds.simplecast.com/82FI35Px" // pol) # Ezra Klein Show
|
# (fromDb "feeds.simplecast.com/82FI35Px" // pol) # Ezra Klein Show
|
||||||
# (fromDb "feeds.simplecast.com/l2i9YnTd" // tech // pol) # Hard Fork (NYtimes tech)
|
# (fromDb "feeds.simplecast.com/l2i9YnTd" // tech // pol) # Hard Fork (NYtimes tech)
|
||||||
# (fromDb "feeds.simplecast.com/whlwDbyc" // tech) # Tech Lounge: <https://chrischinchilla.com/podcast/techlounge/>
|
|
||||||
# (fromDb "feeds.simplecast.com/xKJ93w_w" // uncat) # Atlas Obscura
|
# (fromDb "feeds.simplecast.com/xKJ93w_w" // uncat) # Atlas Obscura
|
||||||
# (fromDb "iheart.com/podcast/1119-away-days-podcast-reporti-275359753" // pol) # Away Days (Cool Zone Media)
|
|
||||||
# (fromDb "lastweekinai.com" // tech) # Last Week in AI
|
# (fromDb "lastweekinai.com" // tech) # Last Week in AI
|
||||||
# (fromDb "mintcast.org" // tech)
|
# (fromDb "mintcast.org" // tech)
|
||||||
# (fromDb "podcast.posttv.com/itunes/post-reports.xml" // pol)
|
# (fromDb "podcast.posttv.com/itunes/post-reports.xml" // pol)
|
||||||
# (fromDb "podcast.sustainoss.org" // tech) # "Sustainable tech", only... it somehow manages to avoid any tech which is actually sustainable, and most of the time doesn't even talk about Open Source Software (!). normie/surface-level/"feel good"
|
# (fromDb "podcast.sustainoss.org" // tech) # "Sustainable tech", only... it somehow manages to avoid any tech which is actually sustainable, and most of the time doesn't even talk about Open Source Software (!). normie/surface-level/"feel good"
|
||||||
# (fromDb "podcast.thelinuxexp.com" // tech) # low-brow linux/foss PR announcements
|
# (fromDb "podcast.thelinuxexp.com" // tech) # low-brow linux/foss PR announcements
|
||||||
# (fromDb "politicspoliticspolitics.com" // pol) # don't judge me. Justin Robert Young.
|
|
||||||
# (fromDb "rss.acast.com/deconstructed") # The Intercept - Deconstructed
|
# (fromDb "rss.acast.com/deconstructed") # The Intercept - Deconstructed
|
||||||
# (fromDb "rss.acast.com/intercepted-with-jeremy-scahill") # The Intercept - Intercepted
|
# (fromDb "rss.acast.com/intercepted-with-jeremy-scahill") # The Intercept - Intercepted
|
||||||
# (fromDb "rss.art19.com/60-minutes" // pol)
|
# (fromDb "rss.art19.com/60-minutes" // pol)
|
||||||
# (fromDb "rss.art19.com/your-welcome" // pol) # Michael Malice - Your Welcome -- also available here: <https://origin.podcastone.com/podcast?categoryID2=2232>
|
# (fromDb "rss.art19.com/your-welcome" // pol) # Michael Malice - Your Welcome -- also available here: <https://origin.podcastone.com/podcast?categoryID2=2232>
|
||||||
# (fromDb "rss.prod.firstlook.media/deconstructed/podcast.rss" // pol) #< possible URL rot
|
# (fromDb "rss.prod.firstlook.media/deconstructed/podcast.rss" // pol) #< possible URL rot
|
||||||
# (fromDb "rss.prod.firstlook.media/intercepted/podcast.rss" // pol) #< possible URL rot
|
# (fromDb "rss.prod.firstlook.media/intercepted/podcast.rss" // pol) #< possible URL rot
|
||||||
# (fromDb "sites.libsyn.com/438684" // humor) # Quorators - digging up *weird* Quota questions
|
|
||||||
# (fromDb "techwontsave.us" // pol) # rec by Cory Doctorow, but way too info-sparse
|
|
||||||
# (fromDb "trashfuturepodcast.podbean.com" // pol) # rec by Cory Doctorow, but way rambly
|
# (fromDb "trashfuturepodcast.podbean.com" // pol) # rec by Cory Doctorow, but way rambly
|
||||||
# (fromDb "wakingup.libsyn.com" // pol) # Sam Harris, but he just repeats himself now
|
# (fromDb "wakingup.libsyn.com" // pol) # Sam Harris, but he just repeats himself now
|
||||||
# (mkPod "https://anchor.fm/s/21bc734/podcast/rss" // pol // infrequent) # Emerge: making sense of what's next -- <https://www.whatisemerging.com/emergepodcast>
|
# (mkPod "https://anchor.fm/s/21bc734/podcast/rss" // pol // infrequent) # Emerge: making sense of what's next -- <https://www.whatisemerging.com/emergepodcast>
|
||||||
@@ -279,26 +269,20 @@ let
|
|||||||
(fromDb "youtube.com/@Exurb1a")
|
(fromDb "youtube.com/@Exurb1a")
|
||||||
(fromDb "youtube.com/@hbomberguy")
|
(fromDb "youtube.com/@hbomberguy")
|
||||||
(fromDb "youtube.com/@JackStauber")
|
(fromDb "youtube.com/@JackStauber")
|
||||||
(fromDb "youtube.com/@jaketran")
|
|
||||||
(fromDb "youtube.com/@kurzgesagt")
|
|
||||||
(fromDb "youtube.com/@mii_beta" // tech) # Baby Wogue / gnome reviewer
|
(fromDb "youtube.com/@mii_beta" // tech) # Baby Wogue / gnome reviewer
|
||||||
(fromDb "youtube.com/@Matrixdotorg" // tech) # Matrix Live
|
(fromDb "youtube.com/@Matrixdotorg" // tech) # Matrix Live
|
||||||
(fromDb "youtube.com/@NativLang")
|
(fromDb "youtube.com/@NativLang")
|
||||||
(fromDb "youtube.com/@PolyMatter")
|
(fromDb "youtube.com/@PolyMatter")
|
||||||
(fromDb "youtube.com/@scenesbyben" // pol) # video essays
|
|
||||||
(fromDb "youtube.com/@TechnologyConnections" // tech)
|
(fromDb "youtube.com/@TechnologyConnections" // tech)
|
||||||
(fromDb "youtube.com/@theodd1sout")
|
(fromDb "youtube.com/@tested" // tech) # Adam Savage
|
||||||
(fromDb "youtube.com/@TomScottGo")
|
(fromDb "youtube.com/@TomScottGo")
|
||||||
(fromDb "youtube.com/@TVW_Washington" // pol) # interviews with WA public officials
|
(fromDb "youtube.com/@TVW_Washington" // pol) # interviews with WA public officials
|
||||||
(fromDb "youtube.com/@veritasium")
|
|
||||||
(fromDb "youtube.com/@Vihart")
|
(fromDb "youtube.com/@Vihart")
|
||||||
(fromDb "youtube.com/@InnuendoStudios" // pol) # breaks down the nastier political strategies, from a "politics is power" angle
|
(fromDb "youtube.com/@InnuendoStudios" // pol) # breaks down the nastier political strategies, from a "politics is power" angle
|
||||||
|
|
||||||
# (fromDb "youtube.com/@CasuallyExplained" // pol)
|
|
||||||
# (fromDb "youtube.com/@ColdFusion")
|
# (fromDb "youtube.com/@ColdFusion")
|
||||||
# (fromDb "youtube.com/@rossmanngroup" // pol // tech) # Louis Rossmann
|
# (fromDb "youtube.com/@rossmanngroup" // pol // tech) # Louis Rossmann
|
||||||
# (fromDb "youtube.com/@TheB1M")
|
# (fromDb "youtube.com/@TheB1M")
|
||||||
# (fromDb "youtube.com/@tested" // tech) # Adam Savage (uploads too frequently)
|
|
||||||
# (fromDb "youtube.com/@Vox")
|
# (fromDb "youtube.com/@Vox")
|
||||||
# (fromDb "youtube.com/@Vsauce") # they're all like 1-minute long videos now? what happened @Vsauce?
|
# (fromDb "youtube.com/@Vsauce") # they're all like 1-minute long videos now? what happened @Vsauce?
|
||||||
];
|
];
|
||||||
|
@@ -24,20 +24,9 @@ let
|
|||||||
type = fsType;
|
type = fsType;
|
||||||
options = lib.concatStringsSep "," options;
|
options = lib.concatStringsSep "," options;
|
||||||
wantedBy = [ "default.target" ];
|
wantedBy = [ "default.target" ];
|
||||||
after = [
|
after = [ "network-online.target" ];
|
||||||
"emergency.service"
|
|
||||||
"network-online.target"
|
|
||||||
];
|
|
||||||
requires = [ "network-online.target" ];
|
requires = [ "network-online.target" ];
|
||||||
|
|
||||||
unitConfig.Conflicts = [
|
|
||||||
# emergency.service drops the user into a root shell;
|
|
||||||
# only accessible via physical TTY, but unmount sensitive data before that as a precaution.
|
|
||||||
"emergency.service"
|
|
||||||
];
|
|
||||||
|
|
||||||
# mountConfig.LazyUnmount = true; #< else it _ocassionally_ fails "target is busy"
|
|
||||||
|
|
||||||
mountConfig.ExecSearchPath = [ "/run/current-system/sw/bin" ];
|
mountConfig.ExecSearchPath = [ "/run/current-system/sw/bin" ];
|
||||||
mountConfig.User = "colin";
|
mountConfig.User = "colin";
|
||||||
mountConfig.AmbientCapabilities = "CAP_SETPCAP CAP_SYS_ADMIN";
|
mountConfig.AmbientCapabilities = "CAP_SETPCAP CAP_SYS_ADMIN";
|
||||||
@@ -78,8 +67,7 @@ in
|
|||||||
lib.mkMerge [
|
lib.mkMerge [
|
||||||
(ifSshAuthorized (remoteHome "crappy" {}))
|
(ifSshAuthorized (remoteHome "crappy" {}))
|
||||||
(ifSshAuthorized (remoteHome "desko" {}))
|
(ifSshAuthorized (remoteHome "desko" {}))
|
||||||
(ifSshAuthorized (remoteHome "flowy" {}))
|
(ifSshAuthorized (remoteHome "lappy" {}))
|
||||||
# (ifSshAuthorized (remoteHome "lappy" {}))
|
|
||||||
(ifSshAuthorized (remoteHome "moby" { host = "moby-hn"; }))
|
(ifSshAuthorized (remoteHome "moby" { host = "moby-hn"; }))
|
||||||
(ifSshAuthorized (remoteHome "servo" {}))
|
(ifSshAuthorized (remoteHome "servo" {}))
|
||||||
]
|
]
|
||||||
|
@@ -12,7 +12,9 @@ let
|
|||||||
"stderr_path=/var/log/curlftpfs/servo-hn.stderr"
|
"stderr_path=/var/log/curlftpfs/servo-hn.stderr"
|
||||||
];
|
];
|
||||||
|
|
||||||
remoteServo = subdir: {
|
remoteServo = subdir: let
|
||||||
|
systemdBindName = utils.escapeSystemdPath "/mnt/servo/${subdir}";
|
||||||
|
in {
|
||||||
# sane.fs."/mnt/servo/${subdir}".mount.bind = "/mnt/.servo_ftp/${subdir}";
|
# sane.fs."/mnt/servo/${subdir}".mount.bind = "/mnt/.servo_ftp/${subdir}";
|
||||||
systemd.mounts = [{
|
systemd.mounts = [{
|
||||||
where = "/mnt/servo/${subdir}";
|
where = "/mnt/servo/${subdir}";
|
||||||
|
@@ -14,9 +14,7 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
sane.user.persist.byStore.ephemeral = [
|
sane.user.persist.byStore.ephemeral = [
|
||||||
# this is persisted simply to save on RAM. mesa_shader_cache_db is < 10 MB per boot.
|
# this is persisted simply to save on RAM. mesa_shader_cache is < 10 MB per boot.
|
||||||
# TODO: see about removing this. the programs which benefit from shader caches should be configured to persist their _own_ dbs.
|
|
||||||
".cache/mesa_shader_cache_db"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
sane.user.persist.byStore.private = [
|
sane.user.persist.byStore.private = [
|
||||||
@@ -31,6 +29,28 @@
|
|||||||
|
|
||||||
"knowledge"
|
"knowledge"
|
||||||
"Videos/local"
|
"Videos/local"
|
||||||
|
|
||||||
|
# TODO: pre-compile mesa shaders, and then run in read-only mode?
|
||||||
|
# mesa shader cache can be configured with e.g.:
|
||||||
|
# - MESA_SHADER_CACHE_DISABLE=true
|
||||||
|
# - MESA_SHADER_CACHE_DIR=/path/to/cache_db
|
||||||
|
# - MESA_DISK_CACHE_SINGLE_FILE=1 (in which case default cache file is ~/.cache/mesa_shader_cache_sf)
|
||||||
|
# - MESA_DISK_CACHE_MULTI_FILE=1 (in which case default cache dir is ~/.cache/mesa_shader_cache)
|
||||||
|
# - MESA_DISK_CACHE_READ_ONLY_FOZ_DBS=foo,bar
|
||||||
|
# - to use read-only mesa caches, one from foo.db the other bar.db
|
||||||
|
# - MESA_DISK_CACHE_READ_ONLY_FOZ_DBS_DYNAMIC_LIST=/path/to/txt
|
||||||
|
# - where /path/to/txt contains a list of names which represent read-only caches
|
||||||
|
# - allows to change the cache providers w/o having to update variables
|
||||||
|
#
|
||||||
|
# see also: <https://gitlab.freedesktop.org/mesa/shader-db>
|
||||||
|
# - database of common shaders (gtk4, chromium, etc) & instructions to compile for any arch
|
||||||
|
# see also: <https://github.com/ValveSoftware/Fossilize>
|
||||||
|
# which may help in generating readonly cache files
|
||||||
|
#
|
||||||
|
# for now, mesa shader cache is persisted because some programs *greatly* benefit from it.
|
||||||
|
# esp gnome-contacts has a first-launch bug where it shows a misleading warning if shaders take too long to compile,
|
||||||
|
# so we persist to private instead of ephemeral.
|
||||||
|
".cache/mesa_shader_cache_db"
|
||||||
];
|
];
|
||||||
|
|
||||||
# convenience
|
# convenience
|
||||||
|
@@ -2,12 +2,6 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
# TODO: this should be populated per-host
|
# TODO: this should be populated per-host
|
||||||
|
|
||||||
sane.hosts.by-name."cadey" = {
|
|
||||||
ssh.authorized = lib.mkDefault false;
|
|
||||||
lan-ip = "10.78.79.70";
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.hosts.by-name."crappy" = {
|
sane.hosts.by-name."crappy" = {
|
||||||
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMIvSQAGKqmymXIL4La9B00LPxBIqWAr5AsJxk3UQeY5";
|
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMIvSQAGKqmymXIL4La9B00LPxBIqWAr5AsJxk3UQeY5";
|
||||||
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMN0cpRAloCBOE5/2wuzgik35iNDv5KLceWMCVaa7DIQ";
|
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMN0cpRAloCBOE5/2wuzgik35iNDv5KLceWMCVaa7DIQ";
|
||||||
@@ -24,22 +18,14 @@
|
|||||||
lan-ip = "10.78.79.52";
|
lan-ip = "10.78.79.52";
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.hosts.by-name."flowy" = {
|
sane.hosts.by-name."lappy" = {
|
||||||
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAa9U2+aUc5Kr6f2oeILAy2EC86W5OZSprmBb1F+8n7/";
|
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDpmFdNSVPRol5hkbbCivRhyeENzb9HVyf9KutGLP2Zu";
|
||||||
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMNuTITzc07mqYspWw6fqRw40ObxwnmWCwg188apHB/o";
|
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILSJnqmVl9/SYQ0btvGb0REwwWY8wkdkGXQZfn/1geEc";
|
||||||
wg-home.pubkey = "o6Vh+gHF87wAOOofgKKYIhV91kgDRnLvwnd5W2WHsDE=";
|
wg-home.pubkey = "FTUWGw2p4/cEcrrIE86PWVnqctbv8OYpw8Gt3+dC/lk=";
|
||||||
wg-home.ip = "10.0.10.56";
|
wg-home.ip = "10.0.10.20";
|
||||||
lan-ip = "10.78.79.56";
|
lan-ip = "10.78.79.53";
|
||||||
};
|
};
|
||||||
|
|
||||||
# sane.hosts.by-name."lappy" = {
|
|
||||||
# ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDpmFdNSVPRol5hkbbCivRhyeENzb9HVyf9KutGLP2Zu";
|
|
||||||
# ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILSJnqmVl9/SYQ0btvGb0REwwWY8wkdkGXQZfn/1geEc";
|
|
||||||
# wg-home.pubkey = "FTUWGw2p4/cEcrrIE86PWVnqctbv8OYpw8Gt3+dC/lk=";
|
|
||||||
# wg-home.ip = "10.0.10.20";
|
|
||||||
# lan-ip = "10.78.79.53";
|
|
||||||
# };
|
|
||||||
|
|
||||||
sane.hosts.by-name."moby" = {
|
sane.hosts.by-name."moby" = {
|
||||||
# ssh.authorized = lib.mkDefault false; # moby's too easy to hijack: don't let it ssh places
|
# ssh.authorized = lib.mkDefault false; # moby's too easy to hijack: don't let it ssh places
|
||||||
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICrR+gePnl0nV/vy7I5BzrGeyVL+9eOuXHU1yNE3uCwU";
|
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICrR+gePnl0nV/vy7I5BzrGeyVL+9eOuXHU1yNE3uCwU";
|
||||||
@@ -50,7 +36,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
sane.hosts.by-name."servo" = {
|
sane.hosts.by-name."servo" = {
|
||||||
# ssh.authorized = lib.mkDefault false; # servo presents too many services to the internet: easy atack vector
|
ssh.authorized = lib.mkDefault false; # servo presents too many services to the internet: easy atack vector
|
||||||
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPS1qFzKurAdB9blkWomq8gI1g0T3sTs9LsmFOj5VtqX";
|
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPS1qFzKurAdB9blkWomq8gI1g0T3sTs9LsmFOj5VtqX";
|
||||||
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOfdSmFkrVT6DhpgvFeQKm3Fh9VKZ9DbLYOPOJWYQ0E8";
|
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOfdSmFkrVT6DhpgvFeQKm3Fh9VKZ9DbLYOPOJWYQ0E8";
|
||||||
wg-home.pubkey = "roAw+IUFVtdpCcqa4khB385Qcv9l5JAB//730tyK4Wk=";
|
wg-home.pubkey = "roAw+IUFVtdpCcqa4khB385Qcv9l5JAB//730tyK4Wk=";
|
||||||
|
@@ -66,10 +66,6 @@
|
|||||||
sane.ids.plugdev.gid = 2421;
|
sane.ids.plugdev.gid = 2421;
|
||||||
sane.ids.ollama.uid = 2422;
|
sane.ids.ollama.uid = 2422;
|
||||||
sane.ids.ollama.gid = 2422;
|
sane.ids.ollama.gid = 2422;
|
||||||
sane.ids.bitmagnet.uid = 2423;
|
|
||||||
sane.ids.bitmagnet.gid = 2423;
|
|
||||||
sane.ids.anubis.uid = 2424;
|
|
||||||
sane.ids.anubis.gid = 2424;
|
|
||||||
sane.ids.shelvacu.uid = 5431;
|
sane.ids.shelvacu.uid = 5431;
|
||||||
|
|
||||||
sane.ids.colin.uid = 1000;
|
sane.ids.colin.uid = 1000;
|
||||||
@@ -96,7 +92,6 @@
|
|||||||
sane.ids.radicale.gid = 2011;
|
sane.ids.radicale.gid = 2011;
|
||||||
sane.ids.named.uid = 2012;
|
sane.ids.named.uid = 2012;
|
||||||
sane.ids.named.gid = 2012;
|
sane.ids.named.gid = 2012;
|
||||||
sane.ids.lpadmin.gid = 2013;
|
|
||||||
|
|
||||||
# found on graphical hosts
|
# found on graphical hosts
|
||||||
sane.ids.nm-iodine.uid = 2101; # desko/moby/lappy
|
sane.ids.nm-iodine.uid = 2101; # desko/moby/lappy
|
||||||
|
@@ -1,25 +1,13 @@
|
|||||||
# debugging:
|
# debugging:
|
||||||
# - /var/log/named/named.log
|
|
||||||
## config
|
|
||||||
# - `man named`
|
# - `man named`
|
||||||
# - `man named.conf`
|
# - `man named.conf`
|
||||||
# - show defaults with: `named -C`
|
|
||||||
# - defaults live in <repo:isc-projects/bind:bin/named/config.c>
|
|
||||||
# - per-option docs live in <repo:isc-projects/bind:bind9/doc/arm/reference.rst>
|
|
||||||
#
|
|
||||||
## statistics
|
|
||||||
# - `netstat --statistics --udp`
|
|
||||||
# - `rdnc stats`? dumps to `named.stats` in named's PWD?
|
|
||||||
#
|
|
||||||
## interactive debugging
|
|
||||||
# - `systemctl stop bind`
|
# - `systemctl stop bind`
|
||||||
# - `sudo /nix/store/0zpdy93sd3fgbxgvf8dsxhn8fbbya8d2-bind-9.18.28/sbin/named -g -u named -4 -c /nix/store/f1mp0myzmfms71h9vinwxpn2i9362a9a-named.conf`
|
# - `sudo /nix/store/0zpdy93sd3fgbxgvf8dsxhn8fbbya8d2-bind-9.18.28/sbin/named -g -u named -4 -c /nix/store/f1mp0myzmfms71h9vinwxpn2i9362a9a-named.conf`
|
||||||
# - `-g` = don't fork
|
# - `-g` = don't fork
|
||||||
# - `-u named` = start as superuser (to claim port 53), then drop to user `named`
|
# - `-u named` = start as superuser (to claim port 53), then drop to user `named`
|
||||||
#
|
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
let
|
let
|
||||||
hostCfg = config.sane.hosts.by-name."${config.networking.hostName}" or null;
|
hostCfg = config.sane.hosts.by-name."${config.networking.hostName}";
|
||||||
bindCfg = config.services.bind;
|
bindCfg = config.services.bind;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@@ -50,7 +38,7 @@ in
|
|||||||
];
|
];
|
||||||
services.bind.listenOn = [
|
services.bind.listenOn = [
|
||||||
"127.0.0.1"
|
"127.0.0.1"
|
||||||
] ++ lib.optionals (hostCfg != null && hostCfg.wg-home.ip != null) [
|
] ++ lib.optionals (hostCfg.wg-home.ip != null) [
|
||||||
# allow wireguard clients to use us as a recursive resolver (only needed for servo)
|
# allow wireguard clients to use us as a recursive resolver (only needed for servo)
|
||||||
hostCfg.wg-home.ip
|
hostCfg.wg-home.ip
|
||||||
];
|
];
|
||||||
@@ -65,13 +53,6 @@ in
|
|||||||
# listen-on port 953 { any; };
|
# listen-on port 953 { any; };
|
||||||
# '';
|
# '';
|
||||||
|
|
||||||
# services.bind.extraArgs = [
|
|
||||||
# # -d = debug logging level: higher = more verbose
|
|
||||||
# "-d" "2"
|
|
||||||
# # -L = where to log. default is `named.run` in PWD -- unless running interactively in which case it logs to stdout
|
|
||||||
# "-L" "/var/log/named/named.log"
|
|
||||||
# ];
|
|
||||||
|
|
||||||
networking.resolvconf.useLocalResolver = false; #< we manage resolvconf explicitly, above
|
networking.resolvconf.useLocalResolver = false; #< we manage resolvconf explicitly, above
|
||||||
|
|
||||||
# TODO: how to exempt `pool.ntp.org` from DNSSEC checks, as i did when using unbound?
|
# TODO: how to exempt `pool.ntp.org` from DNSSEC checks, as i did when using unbound?
|
||||||
@@ -86,12 +67,6 @@ in
|
|||||||
// and as of 2025-01-30 BIND9 gives no way to disable DNSSEC per-forwarder/zone,
|
// and as of 2025-01-30 BIND9 gives no way to disable DNSSEC per-forwarder/zone,
|
||||||
// so just disable it globally
|
// so just disable it globally
|
||||||
dnssec-validation no;
|
dnssec-validation no;
|
||||||
// XXX(2025-06-30): i need reverse DNS of private IP space such as 10.0.0.0/8.
|
|
||||||
// configuring those zones (done in a secrets/ file), unfortunately requires disabling
|
|
||||||
// ALL local entries for reserved zones (IN-ADDR.ARPA, IP6.ARPA, EMPTY.AS112.ARPA, HOME.ARPA, RESOLVER.ARPA).
|
|
||||||
// TODO: figure a better solution, as this likely causes reverse-DNS queries of LAN hosts to be sent to the WAN!
|
|
||||||
// - see <https://www.as112.net/>
|
|
||||||
empty-zones-enable no;
|
|
||||||
'';
|
'';
|
||||||
# re-implement the nixos default bind config, but without `options { forwarders { }; };`,
|
# re-implement the nixos default bind config, but without `options { forwarders { }; };`,
|
||||||
# as having an empty `forwarders` at the top-level prevents me from forwarding the `.` zone in a separate statement
|
# as having an empty `forwarders` at the top-level prevents me from forwarding the `.` zone in a separate statement
|
||||||
@@ -118,25 +93,6 @@ in
|
|||||||
${bindCfg.extraOptions}
|
${bindCfg.extraOptions}
|
||||||
};
|
};
|
||||||
|
|
||||||
// XXX(2025-06-18): some tools i use for work assume 'localhost' can be resolved by the system nameserver,
|
|
||||||
// and not just by /etc/hosts
|
|
||||||
zone "localhost" {
|
|
||||||
type master;
|
|
||||||
file "${pkgs.writeText "localhost" ''
|
|
||||||
$TTL 300
|
|
||||||
@ IN SOA localhost. root.localhost. (
|
|
||||||
202506181 ; Serial
|
|
||||||
28800 ; Refresh
|
|
||||||
7200 ; Retry
|
|
||||||
604800 ; Expire
|
|
||||||
86400) ; Minimum TTL
|
|
||||||
NS localhost.
|
|
||||||
|
|
||||||
localhost. A 127.0.0.1
|
|
||||||
AAAA ::1
|
|
||||||
''}";
|
|
||||||
};
|
|
||||||
|
|
||||||
${bindCfg.extraConfig}
|
${bindCfg.extraConfig}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
@@ -148,15 +104,5 @@ in
|
|||||||
cat "/run/named/dhcp-configs/$c" >> /run/named/dhcp-configs.conf
|
cat "/run/named/dhcp-configs/$c" >> /run/named/dhcp-configs.conf
|
||||||
done
|
done
|
||||||
'';
|
'';
|
||||||
systemd.services.bind.serviceConfig.ReadWritePaths = [
|
|
||||||
"/var/log/named"
|
|
||||||
];
|
|
||||||
|
|
||||||
sane.persist.sys.byPath."/var/log/named" = {
|
|
||||||
store = "ephemeral";
|
|
||||||
method = "symlink";
|
|
||||||
acl.mode = "0750";
|
|
||||||
acl.user = "named";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,7 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
{
|
{
|
||||||
networking.networkmanager.enable = true;
|
networking.networkmanager.enable = true;
|
||||||
# systemd-networkd-wait-online.service reliably fails on lappy. docs don't match behavior. shit software.
|
systemd.network.wait-online.enable = false; # systemd-networkd-wait-online.service reliably fails on lappy. docs don't match behavior. shit software.
|
||||||
# XXX(2025-07-18): `systemd-networkd-wait-online.service` also fails on desko (timeout).
|
|
||||||
systemd.network.wait-online.enable = false;
|
|
||||||
|
|
||||||
# plugins mostly add support for establishing different VPN connections.
|
# plugins mostly add support for establishing different VPN connections.
|
||||||
# the default plugin set includes mostly proprietary VPNs:
|
# the default plugin set includes mostly proprietary VPNs:
|
||||||
# - fortisslvpn (Fortinet)
|
# - fortisslvpn (Fortinet)
|
||||||
@@ -206,7 +203,6 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
networking.networkmanager.settings = {
|
networking.networkmanager.settings = {
|
||||||
# docs: `man 5 NetworkManager.conf`
|
|
||||||
# keyfile.path = where networkmanager should look for connection credentials
|
# keyfile.path = where networkmanager should look for connection credentials
|
||||||
keyfile.path = "/var/lib/NetworkManager/system-connections";
|
keyfile.path = "/var/lib/NetworkManager/system-connections";
|
||||||
|
|
||||||
@@ -218,30 +214,20 @@
|
|||||||
|
|
||||||
# main.dhcp = "internal"; #< default
|
# main.dhcp = "internal"; #< default
|
||||||
# main.dns controls what to do when NM gets a DNS server via DHCP
|
# main.dns controls what to do when NM gets a DNS server via DHCP
|
||||||
# - "default": NM manages /etc/resolv.conf itself.
|
# - "none" (populate /run/NetworkManager/resolv.conf with DHCP settings)
|
||||||
# - "none": NM doesn't manage /etc/resolv.conf, but does populate /run/NetworkManager/resolv.conf with DHCP settings
|
# - "internal" (?)
|
||||||
# - "systemd-resolved": tell systemd-resolved about it, and point /run/NetworkManager/resolv.conf -> systemd
|
# - "systemd-resolved" (tell systemd-resolved about it, and point /run/NetworkManager/resolv.conf -> systemd)
|
||||||
# - without this, systemd-resolved won't be able to resolve anything (because it has no upstream servers)
|
# without this, systemd-resolved won't be able to resolve anything (because it has no upstream servers)
|
||||||
# - (empty): perform a best-guess for how to manage /etc/resolv.conf
|
|
||||||
# -> if /etc/resolv.conf is a symlink to systemd-resolved, then behaves as "systemd-resolved".
|
|
||||||
# -> else, behaves as "default".
|
|
||||||
# note that NM's resolv.conf isn't (necessarily) /etc/resolv.conf -- that is managed by nixos (via symlinking)
|
# note that NM's resolv.conf isn't (necessarily) /etc/resolv.conf -- that is managed by nixos (via symlinking)
|
||||||
main.dns = let
|
main.dns = if config.services.resolved.enable then
|
||||||
dns = if config.services.resolved.enable then
|
"systemd-resolved"
|
||||||
"systemd-resolved"
|
else if
|
||||||
else if
|
(config.sane.services.hickory-dns.enable && config.sane.services.hickory-dns.asSystemResolver)
|
||||||
(config.sane.services.hickory-dns.enable && config.sane.services.hickory-dns.asSystemResolver)
|
|| (config.services.unbound.enable && config.services.unbound.resolveLocalQueries) then
|
||||||
|| (config.services.unbound.enable && config.services.unbound.resolveLocalQueries)
|
"none"
|
||||||
|| config.services.bind.enable # bind config isn't easily inspectable; assume that it's acting as local resolver
|
else
|
||||||
then
|
"internal"
|
||||||
"none"
|
;
|
||||||
else
|
|
||||||
# omitting the option instructs NM to do a "best guess".
|
|
||||||
# this is nearly equivalent to "default", however NM will do checks like "is /etc/resolv.conf a symlink to systemd-resolved", etc,
|
|
||||||
# to actually try to understand the environment.
|
|
||||||
null
|
|
||||||
;
|
|
||||||
in lib.mkIf (dns != null) dns;
|
|
||||||
main.systemd-resolved = false;
|
main.systemd-resolved = false;
|
||||||
};
|
};
|
||||||
environment.etc."NetworkManager/system-connections".source = "/var/lib/NetworkManager/system-connections";
|
environment.etc."NetworkManager/system-connections".source = "/var/lib/NetworkManager/system-connections";
|
||||||
|
@@ -7,8 +7,7 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
networking.firewall.extraCommands = with pkgs; ''
|
networking.firewall.extraCommands = with pkgs; ''
|
||||||
# after an outgoing SSDP query to the multicast address (dest port=1900, src port=any),
|
# after an outgoing SSDP query to the multicast address, open FW for incoming responses.
|
||||||
# open FW for incoming responses (i.e. accept any packet, so long as it's sent to the port we sent from).
|
|
||||||
# necessary for anything DLNA, especially go2tv
|
# necessary for anything DLNA, especially go2tv
|
||||||
# source: <https://serverfault.com/a/911286>
|
# source: <https://serverfault.com/a/911286>
|
||||||
# context: <https://github.com/alexballas/go2tv/issues/72>
|
# context: <https://github.com/alexballas/go2tv/issues/72>
|
||||||
@@ -17,7 +16,6 @@
|
|||||||
${ipset}/bin/ipset create -! upnp hash:ip,port timeout 10
|
${ipset}/bin/ipset create -! upnp hash:ip,port timeout 10
|
||||||
${iptables}/bin/iptables -A OUTPUT -d 239.255.255.250/32 -p udp -m udp --dport 1900 -j SET --add-set upnp src,src --exist
|
${iptables}/bin/iptables -A OUTPUT -d 239.255.255.250/32 -p udp -m udp --dport 1900 -j SET --add-set upnp src,src --exist
|
||||||
${iptables}/bin/iptables -A INPUT -p udp -m set --match-set upnp dst,dst -j ACCEPT
|
${iptables}/bin/iptables -A INPUT -p udp -m set --match-set upnp dst,dst -j ACCEPT
|
||||||
|
|
||||||
# IPv6 ruleset. ff02::/16 means *any* link-local multicast group (so this is probably more broad than it needs to be)
|
# IPv6 ruleset. ff02::/16 means *any* link-local multicast group (so this is probably more broad than it needs to be)
|
||||||
${ipset}/bin/ipset create -! upnp6 hash:ip,port timeout 10 family inet6
|
${ipset}/bin/ipset create -! upnp6 hash:ip,port timeout 10 family inet6
|
||||||
${iptables}/bin/ip6tables -A OUTPUT -d ff02::/16 -p udp -m udp --dport 1900 -j SET --add-set upnp6 src,src --exist
|
${iptables}/bin/ip6tables -A OUTPUT -d ff02::/16 -p udp -m udp --dport 1900 -j SET --add-set upnp6 src,src --exist
|
||||||
|
@@ -55,17 +55,7 @@
|
|||||||
# this is actually a no-op, and the real action happens in assigning `nix.settings.nix-path`.
|
# this is actually a no-op, and the real action happens in assigning `nix.settings.nix-path`.
|
||||||
nix.nixPath = (lib.optionals (config.sane.maxBuildCost >= 2) [
|
nix.nixPath = (lib.optionals (config.sane.maxBuildCost >= 2) [
|
||||||
"nixpkgs=${pkgs.path}"
|
"nixpkgs=${pkgs.path}"
|
||||||
]) ++ (let
|
]) ++ [
|
||||||
# XXX(2024-09-02): nix 2.24.4 errors when nixpkgs-overlays includes a symlink component:
|
|
||||||
# "error: path '/home/colin/dev' is a symlink"
|
|
||||||
# apparently nix has to explicitly handle symlinks in every place it might encounter them,
|
|
||||||
# so the fixes inside nix for this are manual and fragile. dereference it ourselves:
|
|
||||||
dev = if (config.sane.fs."/home/colin/dev" or {}) != {} then
|
|
||||||
config.sane.fs."/home/colin/dev".symlink.target
|
|
||||||
else
|
|
||||||
"/home/colin/dev"
|
|
||||||
;
|
|
||||||
in [
|
|
||||||
# note the import starts at repo root: this allows `./overlay/default.nix` to access the stuff at the root
|
# note the import starts at repo root: this allows `./overlay/default.nix` to access the stuff at the root
|
||||||
# "nixpkgs-overlays=${../../..}/hosts/common/nix-path/overlay"
|
# "nixpkgs-overlays=${../../..}/hosts/common/nix-path/overlay"
|
||||||
# as long as my system itself doesn't rely on NIXPKGS at runtime, we can point the overlays to git
|
# as long as my system itself doesn't rely on NIXPKGS at runtime, we can point the overlays to git
|
||||||
@@ -75,8 +65,12 @@
|
|||||||
# when it goes wrong. should i port my `nix-shell` scripts to something more tailored to my uses
|
# when it goes wrong. should i port my `nix-shell` scripts to something more tailored to my uses
|
||||||
# and then delete `nixpkgs-overlays`?
|
# and then delete `nixpkgs-overlays`?
|
||||||
# "nixpkgs-overlays=/home/colin/dev/nixos/integrations/nixpkgs/nixpkgs-overlays.nix"
|
# "nixpkgs-overlays=/home/colin/dev/nixos/integrations/nixpkgs/nixpkgs-overlays.nix"
|
||||||
"nixpkgs-overlays=${dev}/nixos/integrations/nixpkgs/nixpkgs-overlays.nix"
|
# XXX(2024-09-02): nix 2.24.4 errors when nixpkgs-overlays includes a symlink component:
|
||||||
]);
|
# "error: path '/home/colin/dev' is a symlink"
|
||||||
|
# apparently nix has to explicitly handle symlinks in every place it might encounter them,
|
||||||
|
# so the fixes inside nix for this are manual and fragile. dereference it ourselves:
|
||||||
|
"nixpkgs-overlays=${config.sane.fs."/home/colin/dev".symlink.target}/nixos/integrations/nixpkgs/nixpkgs-overlays.nix"
|
||||||
|
];
|
||||||
|
|
||||||
# ensure new deployments have a source of this repo with which they can bootstrap.
|
# ensure new deployments have a source of this repo with which they can bootstrap.
|
||||||
# this however changes on every commit and can be slow to copy for e.g. `moby`.
|
# this however changes on every commit and can be slow to copy for e.g. `moby`.
|
||||||
|
@@ -6,15 +6,11 @@ let
|
|||||||
# nixpkgs' pam hardcodes unix_chkpwd path to the /run/wrappers one,
|
# nixpkgs' pam hardcodes unix_chkpwd path to the /run/wrappers one,
|
||||||
# but i don't want the wrapper, so undo that.
|
# but i don't want the wrapper, so undo that.
|
||||||
# ideally i would patch this via an overlay, but pam is in the bootstrap so that forces a full rebuild.
|
# ideally i would patch this via an overlay, but pam is in the bootstrap so that forces a full rebuild.
|
||||||
# see: <repo:nixos/nixpkgs:pkgs/by-name/li/linux-pam/package.nix>
|
|
||||||
postPatch = (upstream.postPatch or "") + ''
|
postPatch = (upstream.postPatch or "") + ''
|
||||||
substituteInPlace modules/module-meson.build --replace-fail \
|
substituteInPlace modules/pam_unix/Makefile.am --replace-fail \
|
||||||
"/run/wrappers/bin/unix_chkpwd" "$out/bin/unix_chkpwd"
|
"/run/wrappers/bin/unix_chkpwd" "$out/bin/unix_chkpwd"
|
||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
# `mkDefault` is `mkOverride 1000`.
|
|
||||||
# `mkOverrideDefault` will override `mkDefault` values, but not ordinary values.
|
|
||||||
mkOverrideDefault = lib.mkOverride 900;
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# remove a few items from /run/wrappers we don't need.
|
# remove a few items from /run/wrappers we don't need.
|
||||||
@@ -139,20 +135,11 @@ in
|
|||||||
environment.variables.NIXPKGS_CONFIG = lib.mkForce "";
|
environment.variables.NIXPKGS_CONFIG = lib.mkForce "";
|
||||||
# XDG_CONFIG_DIRS defaults to "/etc/xdg", which doesn't exist.
|
# XDG_CONFIG_DIRS defaults to "/etc/xdg", which doesn't exist.
|
||||||
# in practice, pam appends the values i want to XDG_CONFIG_DIRS, though this approach causes an extra leading `:`
|
# in practice, pam appends the values i want to XDG_CONFIG_DIRS, though this approach causes an extra leading `:`
|
||||||
# XXX(2025-06-06): some nixpkgs' systemd services actually depend on the default XDG_CONFIG_DIRS=/etc/xdg!
|
environment.sessionVariables.XDG_CONFIG_DIRS = lib.mkForce [];
|
||||||
# specifically: `services.bitmagnet`
|
|
||||||
# environment.sessionVariables.XDG_CONFIG_DIRS = lib.mkForce [];
|
|
||||||
# XCURSOR_PATH: defaults to `[ "$HOME/.icons" "$HOME/.local/share/icons" ]`, neither of which i use, just adding noise.
|
# XCURSOR_PATH: defaults to `[ "$HOME/.icons" "$HOME/.local/share/icons" ]`, neither of which i use, just adding noise.
|
||||||
# see: <repo:nixos/nixpkgs:nixos/modules/config/xdg/icons.nix>
|
# see: <repo:nixos/nixpkgs:nixos/modules/config/xdg/icons.nix>
|
||||||
environment.sessionVariables.XCURSOR_PATH = lib.mkForce [];
|
environment.sessionVariables.XCURSOR_PATH = lib.mkForce [];
|
||||||
|
|
||||||
environment.shellAliases = {
|
|
||||||
# unset default aliases; see <repo:nixos/nixpkgs:nixos/modules/config/shells-environment.nix>
|
|
||||||
ls = mkOverrideDefault null;
|
|
||||||
ll = mkOverrideDefault null;
|
|
||||||
l = mkOverrideDefault null;
|
|
||||||
};
|
|
||||||
|
|
||||||
# disable nixos' portal module, otherwise /share/applications gets linked into the system and complicates things (sandboxing).
|
# disable nixos' portal module, otherwise /share/applications gets linked into the system and complicates things (sandboxing).
|
||||||
# instead, i manage portals myself via the sane.programs API (e.g. sane.programs.xdg-desktop-portal).
|
# instead, i manage portals myself via the sane.programs API (e.g. sane.programs.xdg-desktop-portal).
|
||||||
xdg.portal.enable = false;
|
xdg.portal.enable = false;
|
||||||
|
@@ -1,11 +1,8 @@
|
|||||||
# Terminal UI mail client
|
# Terminal UI mail client
|
||||||
{ pkgs, ... }:
|
{ ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
sane.programs.aerc = {
|
sane.programs.aerc = {
|
||||||
packageUnwrapped = pkgs.aerc.override {
|
|
||||||
withNotmuch = false; #< not used; regularly fails to build
|
|
||||||
};
|
|
||||||
sandbox.wrapperType = "inplace"; #< /share/aerc/aerc.conf mentions (in comments) other (non-sandboxed) /share files by absolute path
|
sandbox.wrapperType = "inplace"; #< /share/aerc/aerc.conf mentions (in comments) other (non-sandboxed) /share files by absolute path
|
||||||
sandbox.net = "clearnet";
|
sandbox.net = "clearnet";
|
||||||
secrets.".config/aerc/accounts.conf" = ../../../secrets/common/aerc_accounts.conf.bin;
|
secrets.".config/aerc/accounts.conf" = ../../../secrets/common/aerc_accounts.conf.bin;
|
||||||
|
@@ -1,63 +0,0 @@
|
|||||||
# alpaca: ollama llm client
|
|
||||||
# - super simple, easy UI
|
|
||||||
#
|
|
||||||
# shortcomings (as of 6.1.7, 2025-07-23):
|
|
||||||
# - doesn't seem to do any prompt tuning;
|
|
||||||
# inherits all the pathologies of the underlying model (e.g. makes up citations)
|
|
||||||
#
|
|
||||||
# it creates a config dir, `~/.config/com.jeffser.Alpaca`, but apparently empty
|
|
||||||
#
|
|
||||||
# TODO: configure ollama connection details statically
|
|
||||||
# - until then, on first run:
|
|
||||||
# - select the non-"managed" ollama option.
|
|
||||||
# - connect to http://10.0.10.22:11434
|
|
||||||
# TODO: update the nix package 6.1.7 -> 7.5.2
|
|
||||||
# - i.e. review <https://github.com/NixOS/nixpkgs/pull/420698>
|
|
||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
sane.programs.alpaca = {
|
|
||||||
packageUnwrapped = (pkgs.alpaca.override {
|
|
||||||
# ollama is only added to `PATH`; since i'm using it via http, remove it here.
|
|
||||||
# fixes cross compilation & simplifies closure.
|
|
||||||
ollama = null;
|
|
||||||
python3Packages = pkgs.python3Packages // {
|
|
||||||
# XXX(2025-07-23): does not cross compile (markitdown -> pydub -> ... -> opencv)
|
|
||||||
markitdown = null;
|
|
||||||
};
|
|
||||||
}).overrideAttrs (upstream: {
|
|
||||||
postPatch = (upstream.postPatch or "") + ''
|
|
||||||
# for nulled dependencies (above), patch so the application only errors
|
|
||||||
# at runtime, on first attempted use.
|
|
||||||
substituteInPlace src/widgets/attachments.py \
|
|
||||||
--replace-fail 'from markitdown' '# from markitdown'
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
buildCost = 2; #< liable to break cross during updates; not important enough to block deploy over
|
|
||||||
|
|
||||||
sandbox.net = "all"; # maybe only needs wireguard, actually
|
|
||||||
sandbox.whitelistWayland = true;
|
|
||||||
sandbox.mesaCacheDir = ".cache/com.jeffser.Alpaca/mesa";
|
|
||||||
|
|
||||||
sandbox.whitelistDbus.user.own = [ "com.jeffser.Alpaca" ];
|
|
||||||
sandbox.whitelistPortal = [
|
|
||||||
"OpenURI"
|
|
||||||
];
|
|
||||||
sandbox.whitelistSendNotifications = true;
|
|
||||||
|
|
||||||
persist.byStore.ephemeral = [
|
|
||||||
".cache/com.jeffser.Alpaca" #< ?
|
|
||||||
];
|
|
||||||
|
|
||||||
persist.byStore.private = [
|
|
||||||
# alpaca.db: sqlite3 database with the following tables:
|
|
||||||
# - attachment
|
|
||||||
# - chat
|
|
||||||
# - instances
|
|
||||||
# - message
|
|
||||||
# - model_preferences
|
|
||||||
# - preferences
|
|
||||||
# - tool_parameters
|
|
||||||
".local/share/com.jeffser.Alpaca"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,30 +1,15 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
let
|
let
|
||||||
cfg = config.sane.programs.alsa-ucm-conf;
|
cfg = config.sane.programs.alsa-ucm-conf;
|
||||||
deprioritize = pkg: pkg.overrideAttrs (base: {
|
in
|
||||||
|
{
|
||||||
|
sane.programs.alsa-ucm-conf = {
|
||||||
|
packageUnwrapped = pkgs.alsa-ucm-conf.overrideAttrs (base: {
|
||||||
meta = (base.meta or {}) // {
|
meta = (base.meta or {}) // {
|
||||||
# let the other alsa ucm packages override configs from this one
|
# let the other alsa ucm packages override configs from this one
|
||||||
priority = ((base.meta or {}).priority or 10) + 20;
|
priority = ((base.meta or {}).priority or 10) + 20;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
alsa-ucm-latest = pkgs.alsa-ucm-conf.overrideAttrs (upstream: rec {
|
|
||||||
# XXX(2025-07-18): see <https://github.com/NixOS/nixpkgs/pull/414818>
|
|
||||||
version = "1.2.14";
|
|
||||||
src = lib.warnIf (lib.versionAtLeast upstream.version "1.2.14") "upstream alsa-ucm-conf is up to date with my own: remove override?" pkgs.fetchurl {
|
|
||||||
url = "mirror://alsa/lib/alsa-ucm-conf-${version}.tar.bz2";
|
|
||||||
hash = "sha256-MumAn1ktkrl4qhAy41KTwzuNDx7Edfk3Aiw+6aMGnCE=";
|
|
||||||
};
|
|
||||||
installPhase = lib.replaceStrings
|
|
||||||
[ ''for file in "''${files[@]}"'' ]
|
|
||||||
[ ''for file in ucm2/common/ctl/led.conf'' ]
|
|
||||||
upstream.installPhase
|
|
||||||
;
|
|
||||||
});
|
|
||||||
in
|
|
||||||
{
|
|
||||||
sane.programs.alsa-ucm-conf = {
|
|
||||||
packageUnwrapped = deprioritize pkgs.alsa-ucm-conf;
|
|
||||||
# packageUnwrapped = deprioritize alsa-ucm-latest;
|
|
||||||
sandbox.enable = false; #< only provides $out/share/alsa
|
sandbox.enable = false; #< only provides $out/share/alsa
|
||||||
|
|
||||||
# alsa-lib package only looks in its $out/share/alsa to find runtime config data, by default.
|
# alsa-lib package only looks in its $out/share/alsa to find runtime config data, by default.
|
||||||
|
@@ -19,15 +19,16 @@
|
|||||||
packageUnwrapped = with pkgs; animatch.override {
|
packageUnwrapped = with pkgs; animatch.override {
|
||||||
# allegro has no native wayland support, and so by default crashes when run without Xwayland.
|
# allegro has no native wayland support, and so by default crashes when run without Xwayland.
|
||||||
# enable the allegro SDL backend, and achieve Wayland support via SDL's Wayland support.
|
# enable the allegro SDL backend, and achieve Wayland support via SDL's Wayland support.
|
||||||
allegro5 = allegro5.override { useSDL = true; };
|
# TODO: see about upstreaming this to nixpkgs?
|
||||||
|
allegro5 = allegro5.overrideAttrs (upstream: {
|
||||||
|
buildInputs = upstream.buildInputs ++ [
|
||||||
|
SDL2
|
||||||
|
];
|
||||||
|
cmakeFlags = upstream.cmakeFlags ++ [
|
||||||
|
"-DALLEGRO_SDL=on"
|
||||||
|
];
|
||||||
|
});
|
||||||
};
|
};
|
||||||
# nativeBuildInputs = (upstream.nativeBuildInputs or []) ++ [
|
|
||||||
# makeWrapper
|
|
||||||
# ];
|
|
||||||
# postFixup = (upstream.postFixup or "") + ''
|
|
||||||
# wrapProgram $out/bin/animatch \
|
|
||||||
# --set SDL_VIDEODRIVER wayland
|
|
||||||
# '';
|
|
||||||
|
|
||||||
buildCost = 1;
|
buildCost = 1;
|
||||||
|
|
||||||
|
@@ -52,7 +52,6 @@ in
|
|||||||
"errno"
|
"errno"
|
||||||
"ethtool"
|
"ethtool"
|
||||||
"evtest"
|
"evtest"
|
||||||
"expect"
|
|
||||||
"fatresize"
|
"fatresize"
|
||||||
"fd"
|
"fd"
|
||||||
"fftest" # for debugging moby haptics/vibrator, mostly
|
"fftest" # for debugging moby haptics/vibrator, mostly
|
||||||
@@ -67,7 +66,6 @@ in
|
|||||||
"hdparm"
|
"hdparm"
|
||||||
"hping"
|
"hping"
|
||||||
"htop"
|
"htop"
|
||||||
"htpasswd"
|
|
||||||
"iftop"
|
"iftop"
|
||||||
"inetutils" # for telnet
|
"inetutils" # for telnet
|
||||||
"iotop"
|
"iotop"
|
||||||
@@ -87,7 +85,6 @@ in
|
|||||||
"mmcli"
|
"mmcli"
|
||||||
"nano"
|
"nano"
|
||||||
# "ncdu" # ncurses disk usage. doesn't cross compile (zig)
|
# "ncdu" # ncurses disk usage. doesn't cross compile (zig)
|
||||||
"nfs-utils" # required, for mounting nfs filesystems
|
|
||||||
"neovim"
|
"neovim"
|
||||||
"netcat"
|
"netcat"
|
||||||
"nethogs"
|
"nethogs"
|
||||||
@@ -98,7 +95,7 @@ in
|
|||||||
"nmon"
|
"nmon"
|
||||||
"nvimpager"
|
"nvimpager"
|
||||||
"nvme-cli" # nvme
|
"nvme-cli" # nvme
|
||||||
"openssl"
|
# "openssl"
|
||||||
"parted"
|
"parted"
|
||||||
"pciutils"
|
"pciutils"
|
||||||
"picocom" # serial TTY
|
"picocom" # serial TTY
|
||||||
@@ -109,11 +106,8 @@ in
|
|||||||
"rsync"
|
"rsync"
|
||||||
# "s6-rc" # service manager
|
# "s6-rc" # service manager
|
||||||
# "screen"
|
# "screen"
|
||||||
"see-cat" # pretty-print equivalent to 'cat'
|
|
||||||
"ssh"
|
|
||||||
"sshpass"
|
|
||||||
"smartmontools" # smartctl
|
"smartmontools" # smartctl
|
||||||
"socat"
|
# "socat"
|
||||||
"strace"
|
"strace"
|
||||||
"subversion"
|
"subversion"
|
||||||
"tcpdump"
|
"tcpdump"
|
||||||
@@ -121,7 +115,6 @@ in
|
|||||||
"unixtools.ps"
|
"unixtools.ps"
|
||||||
"unixtools.sysctl"
|
"unixtools.sysctl"
|
||||||
"unixtools.xxd"
|
"unixtools.xxd"
|
||||||
"uptime"
|
|
||||||
"usbutils" # lsusb
|
"usbutils" # lsusb
|
||||||
"util-linux" # lsblk, lscpu, etc
|
"util-linux" # lsblk, lscpu, etc
|
||||||
"valgrind"
|
"valgrind"
|
||||||
@@ -142,11 +135,8 @@ in
|
|||||||
# - debugging?
|
# - debugging?
|
||||||
consoleUtils = declPackageSet [
|
consoleUtils = declPackageSet [
|
||||||
"alsa-utils" # for aplay, speaker-test
|
"alsa-utils" # for aplay, speaker-test
|
||||||
"bc" # CLI calculator
|
|
||||||
"cdecl" # like <https://cdecl.org>. `cdecl explain 'struct foo *const inst'`
|
|
||||||
# "cdrtools"
|
# "cdrtools"
|
||||||
# "clinfo"
|
# "clinfo"
|
||||||
"colordiff"
|
|
||||||
# "dmidecode"
|
# "dmidecode"
|
||||||
"dtrx" # `unar` alternative, "Do The Right eXtraction"
|
"dtrx" # `unar` alternative, "Do The Right eXtraction"
|
||||||
# "efivar"
|
# "efivar"
|
||||||
@@ -161,14 +151,12 @@ in
|
|||||||
# "gopass-jsonapi"
|
# "gopass-jsonapi"
|
||||||
# "helix" # text editor
|
# "helix" # text editor
|
||||||
"htop" # needed as a user package, for ~/.config/htop
|
"htop" # needed as a user package, for ~/.config/htop
|
||||||
"lddtree"
|
|
||||||
# "libsecret" # for managing user keyrings (secret-tool)
|
# "libsecret" # for managing user keyrings (secret-tool)
|
||||||
# "lm_sensors" # for sensors-detect
|
# "lm_sensors" # for sensors-detect
|
||||||
# "lshw"
|
# "lshw"
|
||||||
# "memtester"
|
# "memtester"
|
||||||
"mercurial" # hg
|
"mercurial" # hg
|
||||||
"mimeo" # like xdg-open
|
"mimeo" # like xdg-open
|
||||||
"mozlz4a" # for extracting .mozlz4 files (firefox)
|
|
||||||
"neovim" # needed as a user package, for swap persistence
|
"neovim" # needed as a user package, for swap persistence
|
||||||
"nix" # needed as user package, for ~/.cache/nix persistence
|
"nix" # needed as user package, for ~/.cache/nix persistence
|
||||||
# "nettools"
|
# "nettools"
|
||||||
@@ -177,13 +165,10 @@ in
|
|||||||
# "node2nix"
|
# "node2nix"
|
||||||
# "oathToolkit" # for oathtool
|
# "oathToolkit" # for oathtool
|
||||||
"objdump"
|
"objdump"
|
||||||
"oils-for-unix"
|
|
||||||
"patchelf"
|
|
||||||
# "ponymix"
|
# "ponymix"
|
||||||
"pulsemixer"
|
"pulsemixer"
|
||||||
"python3-repl"
|
"python3-repl"
|
||||||
# "python3.pkgs.eyeD3" # music tagging
|
# "python3.pkgs.eyeD3" # music tagging
|
||||||
"readline" # for the config
|
|
||||||
"ripgrep" # needed as a user package so that its user-level config file can be installed
|
"ripgrep" # needed as a user package so that its user-level config file can be installed
|
||||||
# "rsyslog" # KEEP THIS HERE if you want persistent logging (TODO: port to systemd, store in /var/log/...)
|
# "rsyslog" # KEEP THIS HERE if you want persistent logging (TODO: port to systemd, store in /var/log/...)
|
||||||
"sane-deadlines"
|
"sane-deadlines"
|
||||||
@@ -191,17 +176,16 @@ in
|
|||||||
"sane-scripts.cli"
|
"sane-scripts.cli"
|
||||||
"sane-secrets-unlock"
|
"sane-secrets-unlock"
|
||||||
"sane-sysload"
|
"sane-sysload"
|
||||||
"sc-im" # CLI spreadsheet editor
|
"sc-im"
|
||||||
"snapper"
|
"snapper"
|
||||||
"sops" # for manually viewing secrets; outside `sane-secrets` (TODO: improve sane-secrets!)
|
"sops" # for manually viewing secrets; outside `sane-secrets` (TODO: improve sane-secrets!)
|
||||||
"speedtest-cli"
|
"speedtest-cli"
|
||||||
"ssh" # specified as a user program, to enable ssh-agent service
|
# "ssh-to-age"
|
||||||
"ssh-to-age" # used when provisioning a new nixos host
|
|
||||||
"strings"
|
"strings"
|
||||||
"sudo"
|
"sudo"
|
||||||
# "tageditor" # music tagging
|
# "tageditor" # music tagging
|
||||||
# "unar"
|
# "unar"
|
||||||
"unzip"
|
# "unzip"
|
||||||
"wireguard-tools" # for `wg`
|
"wireguard-tools" # for `wg`
|
||||||
"xdg-utils" # for xdg-open
|
"xdg-utils" # for xdg-open
|
||||||
# "yarn"
|
# "yarn"
|
||||||
@@ -212,14 +196,13 @@ in
|
|||||||
"dasht" # docset documentation viewer
|
"dasht" # docset documentation viewer
|
||||||
# "gh" # MS GitHub cli
|
# "gh" # MS GitHub cli
|
||||||
"haredoc"
|
"haredoc"
|
||||||
"nix-check-deps" # run `nix-check-deps packageName -f .` before submitting stuff upstream
|
|
||||||
"nix-index"
|
"nix-index"
|
||||||
"nixfmt-rfc-style" # run `nixfmt path/to/package.nix` before submitting stuff upstream
|
"nixfmt-rfc-style" # run `nixpkgs path/to/package.nix` before submitting stuff upstream
|
||||||
"nixpkgs-hammering"
|
"nixpkgs-hammering"
|
||||||
"nixpkgs-review"
|
"nixpkgs-review"
|
||||||
"qmk-udev-rules"
|
"qmk-udev-rules"
|
||||||
"sane-scripts.dev"
|
"sane-scripts.dev"
|
||||||
"sequoia" # gpg tool
|
"sequoia"
|
||||||
# "via"
|
# "via"
|
||||||
"wally-cli"
|
"wally-cli"
|
||||||
# "zsa-udev-rules"
|
# "zsa-udev-rules"
|
||||||
@@ -238,12 +221,9 @@ in
|
|||||||
|
|
||||||
pcTuiApps = declPackageSet [
|
pcTuiApps = declPackageSet [
|
||||||
"aerc" # email client
|
"aerc" # email client
|
||||||
# "cassini" # Elegoo printer control. need here especially, for opening firewalls.
|
|
||||||
"mslicer" # TODO: upstream, and then move this to the phone-case-cq repo
|
|
||||||
# "msmtp" # sendmail
|
# "msmtp" # sendmail
|
||||||
# "offlineimap" # email mailbox sync
|
# "offlineimap" # email mailbox sync
|
||||||
# "sfeed" # RSS fetcher
|
# "sfeed" # RSS fetcher
|
||||||
# "uvtools"
|
|
||||||
"visidata" # TUI spreadsheet viewer/editor
|
"visidata" # TUI spreadsheet viewer/editor
|
||||||
"w3m" # web browser
|
"w3m" # web browser
|
||||||
];
|
];
|
||||||
@@ -253,6 +233,7 @@ in
|
|||||||
"clang"
|
"clang"
|
||||||
"lua"
|
"lua"
|
||||||
"nodejs"
|
"nodejs"
|
||||||
|
"patchelf"
|
||||||
"rustc"
|
"rustc"
|
||||||
# "tree-sitter"
|
# "tree-sitter"
|
||||||
];
|
];
|
||||||
@@ -269,10 +250,10 @@ in
|
|||||||
"celeste64"
|
"celeste64"
|
||||||
# "cutemaze" # meh: trivial maze game; qt6 and keyboard-only
|
# "cutemaze" # meh: trivial maze game; qt6 and keyboard-only
|
||||||
# "cuyo" # trivial puyo-puyo clone
|
# "cuyo" # trivial puyo-puyo clone
|
||||||
# "endless-sky" # space merchantilism/exploration
|
"endless-sky" # space merchantilism/exploration
|
||||||
# "factorio"
|
# "factorio"
|
||||||
# "frozen-bubble" # WAN + LAN + 1P/2P bubble bobble
|
# "frozen-bubble" # WAN + LAN + 1P/2P bubble bobble
|
||||||
# "hase" # WAN worms game
|
"hase" # WAN worms game
|
||||||
# "hedgewars" # WAN + LAN worms game (5~10 people online at any moment; <https://hedgewars.org>)
|
# "hedgewars" # WAN + LAN worms game (5~10 people online at any moment; <https://hedgewars.org>)
|
||||||
# "libremines" # meh: trivial minesweeper; qt6
|
# "libremines" # meh: trivial minesweeper; qt6
|
||||||
# "mario0" # SMB + portal
|
# "mario0" # SMB + portal
|
||||||
@@ -282,17 +263,16 @@ in
|
|||||||
# "osu-lazer"
|
# "osu-lazer"
|
||||||
# "pinball" # 3d pinball; kb/mouse. old sourceforge project
|
# "pinball" # 3d pinball; kb/mouse. old sourceforge project
|
||||||
# "powermanga" # STYLISH space invaders derivative (keyboard-only)
|
# "powermanga" # STYLISH space invaders derivative (keyboard-only)
|
||||||
# "shattered-pixel-dungeon" # doesn't cross compile
|
"shattered-pixel-dungeon" # doesn't cross compile
|
||||||
# "sm64ex-coop"
|
# "sm64ex-coop"
|
||||||
"sm64coopdx"
|
"sm64coopdx"
|
||||||
"space-cadet-pinball" # LMB/RMB controls (bindable though. volume buttons?)
|
"space-cadet-pinball" # LMB/RMB controls (bindable though. volume buttons?)
|
||||||
"steam"
|
"steam"
|
||||||
"superTux" # keyboard-only controls
|
"superTux" # keyboard-only controls
|
||||||
"superTuxKart" # poor FPS on pinephone
|
"superTuxKart" # poor FPS on pinephone
|
||||||
# "tumiki-fighters" # keyboard-only
|
"tumiki-fighters" # keyboard-only
|
||||||
"vvvvvv" # keyboard-only controls
|
"vvvvvv" # keyboard-only controls
|
||||||
# "wine"
|
# "wine"
|
||||||
"zelda64recomp"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
guiApps = declPackageSet [
|
guiApps = declPackageSet [
|
||||||
@@ -304,10 +284,7 @@ in
|
|||||||
guiBaseApps = declPackageSet [
|
guiBaseApps = declPackageSet [
|
||||||
# "abaddon" # discord client
|
# "abaddon" # discord client
|
||||||
"alacritty" # terminal emulator
|
"alacritty" # terminal emulator
|
||||||
"alpaca" # ollama/LLM client
|
|
||||||
"blanket" # ambient noise generator
|
|
||||||
"calls" # gnome calls (dialer/handler)
|
"calls" # gnome calls (dialer/handler)
|
||||||
"confy" # conference planning app
|
|
||||||
"dbus"
|
"dbus"
|
||||||
# "dconf" # or use `gsettings`, with its keyfile backend
|
# "dconf" # or use `gsettings`, with its keyfile backend
|
||||||
# "delfin" # Jellyfin client
|
# "delfin" # Jellyfin client
|
||||||
@@ -315,11 +292,11 @@ in
|
|||||||
"dino" # XMPP client
|
"dino" # XMPP client
|
||||||
"dissent" # Discord client (formerly known as: gtkcord4)
|
"dissent" # Discord client (formerly known as: gtkcord4)
|
||||||
# "emote"
|
# "emote"
|
||||||
# "envelope" # GTK4 email client (alpha)
|
"envelope" # GTK4 email client (alpha)
|
||||||
# "evince" # PDF viewer
|
# "evince" # PDF viewer
|
||||||
# "flare-signal" # gtk4 signal client
|
# "flare-signal" # gtk4 signal client
|
||||||
"fractal" # matrix client
|
"fractal" # matrix client
|
||||||
# "g4music" # local music player
|
"g4music" # local music player
|
||||||
# "gnome.cheese"
|
# "gnome.cheese"
|
||||||
# "gnome-feeds" # RSS reader (with claimed mobile support)
|
# "gnome-feeds" # RSS reader (with claimed mobile support)
|
||||||
# "gnome.file-roller"
|
# "gnome.file-roller"
|
||||||
@@ -334,7 +311,6 @@ in
|
|||||||
"gnome-frog" # OCR/QR decoder
|
"gnome-frog" # OCR/QR decoder
|
||||||
"gnome-maps"
|
"gnome-maps"
|
||||||
"gnome-screenshot" # libcamera-based screenshotter, for debugging; should be compatible with gc2145 camera on Pinephone
|
"gnome-screenshot" # libcamera-based screenshotter, for debugging; should be compatible with gc2145 camera on Pinephone
|
||||||
"gnome-sound-recorder" # a simple microphone recorder/tester
|
|
||||||
"gnome-weather"
|
"gnome-weather"
|
||||||
"gpodder"
|
"gpodder"
|
||||||
"gsettings"
|
"gsettings"
|
||||||
@@ -350,9 +326,8 @@ in
|
|||||||
"mepo" # maps viewer
|
"mepo" # maps viewer
|
||||||
# "mesa-demos" # for eglinfo, glxinfo & other testing tools
|
# "mesa-demos" # for eglinfo, glxinfo & other testing tools
|
||||||
"mpv"
|
"mpv"
|
||||||
"networkmanagerapplet"
|
# "networkmanagerapplet" # for nm-connection-editor GUI. XXX(2024-09-03): broken, probably by NetworkManager sandboxing
|
||||||
# "ntfy-sh" # notification service
|
# "ntfy-sh" # notification service
|
||||||
"newelle" # ollama/LLM client
|
|
||||||
"newsflash" # RSS viewer
|
"newsflash" # RSS viewer
|
||||||
"papers" # PDF viewer
|
"papers" # PDF viewer
|
||||||
"pavucontrol"
|
"pavucontrol"
|
||||||
@@ -368,11 +343,10 @@ in
|
|||||||
# "tdesktop" # broken on phosh
|
# "tdesktop" # broken on phosh
|
||||||
# "tokodon"
|
# "tokodon"
|
||||||
"tuba" # mastodon/pleroma client (stores pw in keyring)
|
"tuba" # mastodon/pleroma client (stores pw in keyring)
|
||||||
# "v4l-utils" # for `media-ctl`; to debug cameras: <https://wiki.postmarketos.org/wiki/PINE64_PinePhone_(pine64-pinephone)#Cameras>
|
"v4l-utils" # for `media-ctl`; to debug cameras: <https://wiki.postmarketos.org/wiki/PINE64_PinePhone_(pine64-pinephone)#Cameras>
|
||||||
"video-trimmer"
|
"video-trimmer"
|
||||||
"vulkan-tools" # vulkaninfo
|
"vulkan-tools" # vulkaninfo
|
||||||
# "whalebird" # pleroma client (Electron). input is broken on phosh.
|
# "whalebird" # pleroma client (Electron). input is broken on phosh.
|
||||||
"wiremix" # wireplumber TUI
|
|
||||||
"xdg-terminal-exec"
|
"xdg-terminal-exec"
|
||||||
"youtube-tui"
|
"youtube-tui"
|
||||||
# "zathura" # PDF/CBZ/ePUB viewer
|
# "zathura" # PDF/CBZ/ePUB viewer
|
||||||
@@ -392,7 +366,7 @@ in
|
|||||||
"megapixels" # camera app (does not support PPP as of 2024-11-29)
|
"megapixels" # camera app (does not support PPP as of 2024-11-29)
|
||||||
"megapixels-next" # camera app (which supports PPP, as of 2024-11-29)
|
"megapixels-next" # camera app (which supports PPP, as of 2024-11-29)
|
||||||
"notejot" # note taking, e.g. shopping list
|
"notejot" # note taking, e.g. shopping list
|
||||||
# "planify" # todo-tracker/planner (XXX(2025-05-16): does not build; gxml tests fail against glib 2.84.1; planify itself fails still, if gxml.doCheck forced false)
|
"planify" # todo-tracker/planner
|
||||||
"portfolio-filemanager"
|
"portfolio-filemanager"
|
||||||
# "tangram" # web browser
|
# "tangram" # web browser
|
||||||
"wike" # Wikipedia Reader
|
"wike" # Wikipedia Reader
|
||||||
@@ -405,10 +379,11 @@ in
|
|||||||
"pcTuiApps"
|
"pcTuiApps"
|
||||||
####
|
####
|
||||||
"audacity"
|
"audacity"
|
||||||
|
# "blanket" # ambient noise generator
|
||||||
"brave" # for the integrated wallet -- as a backup
|
"brave" # for the integrated wallet -- as a backup
|
||||||
# "cantata" # music player (mpd frontend)
|
# "cantata" # music player (mpd frontend)
|
||||||
# "chromium" # chromium takes hours to build. brave is chromium-based, distributed in binary form, so prefer it.
|
# "chromium" # chromium takes hours to build. brave is chromium-based, distributed in binary form, so prefer it.
|
||||||
"cups"
|
# "cups"
|
||||||
"discord" # x86-only
|
"discord" # x86-only
|
||||||
# "electrum"
|
# "electrum"
|
||||||
"element-desktop"
|
"element-desktop"
|
||||||
@@ -431,7 +406,7 @@ in
|
|||||||
# "kid3" # audio tagging
|
# "kid3" # audio tagging
|
||||||
"krita"
|
"krita"
|
||||||
"libreoffice" # TODO: replace with an office suite that uses saner packaging?
|
"libreoffice" # TODO: replace with an office suite that uses saner packaging?
|
||||||
"losslesscut-bin" # x86-only (TODO: replace with from-source build: <https://github.com/NixOS/nixpkgs/pull/385535>)
|
"losslesscut-bin" # x86-only
|
||||||
# "makemkv" # x86-only
|
# "makemkv" # x86-only
|
||||||
# "monero-gui" # x86-only
|
# "monero-gui" # x86-only
|
||||||
"mumble"
|
"mumble"
|
||||||
@@ -477,13 +452,20 @@ in
|
|||||||
|
|
||||||
bash-language-server.sandbox.whitelistPwd = true;
|
bash-language-server.sandbox.whitelistPwd = true;
|
||||||
|
|
||||||
bc.sandbox.autodetectCliPaths = "existingFile";
|
blanket.buildCost = 1;
|
||||||
|
blanket.sandbox.whitelistAudio = true;
|
||||||
|
# blanket.sandbox.whitelistDbus.user = true; #< TODO: reduce # TODO: untested
|
||||||
|
blanket.sandbox.whitelistWayland = true;
|
||||||
|
|
||||||
bridge-utils.sandbox.net = "all";
|
bridge-utils.sandbox.net = "all";
|
||||||
|
|
||||||
"cacert.unbundled".sandbox.enable = false; #< data only
|
"cacert.unbundled".sandbox.enable = false; #< data only
|
||||||
|
|
||||||
cdecl = {};
|
cargo.persist.byStore.plaintext = [ ".cargo" ];
|
||||||
|
# probably this sandboxing is too restrictive; i'm sandboxing it for rust-analyzer / neovim LSP
|
||||||
|
cargo.sandbox.whitelistPwd = true;
|
||||||
|
cargo.sandbox.net = "all";
|
||||||
|
cargo.sandbox.extraHomePaths = [ "dev" "ref" ];
|
||||||
|
|
||||||
clang = {};
|
clang = {};
|
||||||
|
|
||||||
@@ -493,8 +475,6 @@ in
|
|||||||
"/var/lib/clightning/bitcoin/lightning-rpc"
|
"/var/lib/clightning/bitcoin/lightning-rpc"
|
||||||
];
|
];
|
||||||
|
|
||||||
colordiff.sandbox.autodetectCliPaths = "existingFile"; # for `aplay ./file.wav`
|
|
||||||
|
|
||||||
# cryptsetup: typical use is `cryptsetup open /dev/loopxyz mappedName`, and creates `/dev/mapper/mappedName`
|
# cryptsetup: typical use is `cryptsetup open /dev/loopxyz mappedName`, and creates `/dev/mapper/mappedName`
|
||||||
cryptsetup.sandbox.extraPaths = [
|
cryptsetup.sandbox.extraPaths = [
|
||||||
"/dev/mapper"
|
"/dev/mapper"
|
||||||
@@ -522,8 +502,6 @@ in
|
|||||||
# auth token, preferences
|
# auth token, preferences
|
||||||
delfin.persist.byStore.private = [ ".config/delfin" ];
|
delfin.persist.byStore.private = [ ".config/delfin" ];
|
||||||
|
|
||||||
difftastic.sandbox.autodetectCliPaths = "existing";
|
|
||||||
|
|
||||||
dig.sandbox.net = "all";
|
dig.sandbox.net = "all";
|
||||||
|
|
||||||
dmidecode.sandbox.extraPaths = [ "/sys/firmware/dmi" ];
|
dmidecode.sandbox.extraPaths = [ "/sys/firmware/dmi" ];
|
||||||
@@ -869,15 +847,18 @@ in
|
|||||||
|
|
||||||
marksman.sandbox.whitelistPwd = true;
|
marksman.sandbox.whitelistPwd = true;
|
||||||
|
|
||||||
|
mercurial.sandbox.net = "clearnet";
|
||||||
|
mercurial.sandbox.whitelistPwd = true;
|
||||||
|
|
||||||
mesa-demos.sandbox.whitelistDri = true;
|
mesa-demos.sandbox.whitelistDri = true;
|
||||||
mesa-demos.sandbox.whitelistWayland = true;
|
mesa-demos.sandbox.whitelistWayland = true;
|
||||||
mesa-demos.sandbox.whitelistX = true;
|
mesa-demos.sandbox.whitelistX = true;
|
||||||
|
|
||||||
meson = {};
|
meson = {};
|
||||||
|
|
||||||
# millipixels.packageUnwrapped = pkgs.millipixels.override {
|
millipixels.packageUnwrapped = pkgs.millipixels.override {
|
||||||
# v4l-utils = config.sane.programs.v4l-utils.packageUnwrapped; # necessary for cross compilation
|
v4l-utils = config.sane.programs.v4l-utils.packageUnwrapped; # necessary for cross compilation
|
||||||
# };
|
};
|
||||||
millipixels.sandbox.method = null; #< TODO: sandbox
|
millipixels.sandbox.method = null; #< TODO: sandbox
|
||||||
|
|
||||||
# actual monero blockchain (not wallet/etc; safe to delete, just slow to regenerate)
|
# actual monero blockchain (not wallet/etc; safe to delete, just slow to regenerate)
|
||||||
@@ -889,10 +870,6 @@ in
|
|||||||
"records/finance/cryptocurrencies/monero"
|
"records/finance/cryptocurrencies/monero"
|
||||||
];
|
];
|
||||||
|
|
||||||
mozlz4a.sandbox.autodetectCliPaths = "existingOrParent";
|
|
||||||
|
|
||||||
mslicer.sandbox.method = null; #< TODO: sandbox
|
|
||||||
|
|
||||||
nano.sandbox.autodetectCliPaths = "existingFileOrParent";
|
nano.sandbox.autodetectCliPaths = "existingFileOrParent";
|
||||||
|
|
||||||
netcat.sandbox.net = "all";
|
netcat.sandbox.net = "all";
|
||||||
@@ -908,19 +885,11 @@ in
|
|||||||
networkmanagerapplet.sandbox.whitelistWayland = true;
|
networkmanagerapplet.sandbox.whitelistWayland = true;
|
||||||
networkmanagerapplet.sandbox.whitelistDbus.system = true;
|
networkmanagerapplet.sandbox.whitelistDbus.system = true;
|
||||||
|
|
||||||
nfs-utils.sandbox.method = null; #< TODO: sandbox
|
|
||||||
|
|
||||||
nil.sandbox.whitelistPwd = true;
|
nil.sandbox.whitelistPwd = true;
|
||||||
nil.sandbox.keepPids = true;
|
nil.sandbox.keepPids = true;
|
||||||
|
|
||||||
nixd.sandbox.whitelistPwd = true;
|
nixd.sandbox.whitelistPwd = true;
|
||||||
|
|
||||||
nix-check-deps.sandbox.whitelistPwd = true;
|
|
||||||
nix-check-deps.sandbox.net = "all";
|
|
||||||
nix-check-deps.sandbox.extraPaths = [
|
|
||||||
"/nix/var"
|
|
||||||
];
|
|
||||||
|
|
||||||
nix-tree.sandbox.extraPaths = [
|
nix-tree.sandbox.extraPaths = [
|
||||||
"/nix/var"
|
"/nix/var"
|
||||||
];
|
];
|
||||||
@@ -967,12 +936,8 @@ in
|
|||||||
# settings (electron app)
|
# settings (electron app)
|
||||||
obsidian.persist.byStore.plaintext = [ ".config/obsidian" ];
|
obsidian.persist.byStore.plaintext = [ ".config/obsidian" ];
|
||||||
|
|
||||||
oils-for-unix.sandbox.enable = false; #< it's a shell; doesn't make sense to sandbox
|
|
||||||
|
|
||||||
openscad-lsp.sandbox.whitelistPwd = true;
|
openscad-lsp.sandbox.whitelistPwd = true;
|
||||||
|
|
||||||
openssl.sandbox.net = "clearnet";
|
|
||||||
|
|
||||||
passt.sandbox.enable = false; #< sandbox helper (netns specifically)
|
passt.sandbox.enable = false; #< sandbox helper (netns specifically)
|
||||||
|
|
||||||
parted.sandbox.extraPaths = [
|
parted.sandbox.extraPaths = [
|
||||||
@@ -1041,7 +1006,6 @@ in
|
|||||||
unidecode
|
unidecode
|
||||||
]);
|
]);
|
||||||
python3-repl.sandbox.net = "clearnet";
|
python3-repl.sandbox.net = "clearnet";
|
||||||
python3-repl.sandbox.autodetectCliPaths = "existing"; #< for invoking scripts like `python3 ./my-script.py`
|
|
||||||
python3-repl.sandbox.extraHomePaths = [
|
python3-repl.sandbox.extraHomePaths = [
|
||||||
"/" #< this is 'safe' because with don't expose .persist/private, so no .ssh/id_ed25519
|
"/" #< this is 'safe' because with don't expose .persist/private, so no .ssh/id_ed25519
|
||||||
".persist/plaintext"
|
".persist/plaintext"
|
||||||
@@ -1053,7 +1017,6 @@ in
|
|||||||
rsync.sandbox.net = "clearnet";
|
rsync.sandbox.net = "clearnet";
|
||||||
rsync.sandbox.autodetectCliPaths = "existingOrParent";
|
rsync.sandbox.autodetectCliPaths = "existingOrParent";
|
||||||
rsync.sandbox.tryKeepUsers = true; # if running as root, keep the user namespace so that `-a` can set the correct owners, etc
|
rsync.sandbox.tryKeepUsers = true; # if running as root, keep the user namespace so that `-a` can set the correct owners, etc
|
||||||
rsync.sandbox.whitelistSsh = true;
|
|
||||||
|
|
||||||
rust-analyzer.buildCost = 2;
|
rust-analyzer.buildCost = 2;
|
||||||
rust-analyzer.sandbox.whitelistPwd = true;
|
rust-analyzer.sandbox.whitelistPwd = true;
|
||||||
@@ -1088,10 +1051,10 @@ in
|
|||||||
|
|
||||||
screen.sandbox.enable = false; #< tty; needs to run anything
|
screen.sandbox.enable = false; #< tty; needs to run anything
|
||||||
|
|
||||||
# sequoia.packageUnwrapped = pkgs.sequoia.overrideAttrs (_: {
|
sequoia.packageUnwrapped = pkgs.sequoia.overrideAttrs (_: {
|
||||||
# # XXX(2024-07-30): sq_autocrypt_import test failure: "Warning: 9B7DD433F254904A is expired."
|
# XXX(2024-07-30): sq_autocrypt_import test failure: "Warning: 9B7DD433F254904A is expired."
|
||||||
# doCheck = false;
|
doCheck = false;
|
||||||
# });
|
});
|
||||||
sequoia.buildCost = 1;
|
sequoia.buildCost = 1;
|
||||||
sequoia.sandbox.whitelistPwd = true;
|
sequoia.sandbox.whitelistPwd = true;
|
||||||
sequoia.sandbox.autodetectCliPaths = "existingFileOrParent"; # supports `-o <file-to-create>`
|
sequoia.sandbox.autodetectCliPaths = "existingFileOrParent"; # supports `-o <file-to-create>`
|
||||||
@@ -1119,6 +1082,14 @@ in
|
|||||||
# TODO: enable dma heaps for more efficient buffer sharing: <https://gitlab.com/postmarketOS/pmaports/-/issues/2789>
|
# TODO: enable dma heaps for more efficient buffer sharing: <https://gitlab.com/postmarketOS/pmaports/-/issues/2789>
|
||||||
snapshot.sandbox.method = null; #< TODO: sandbox
|
snapshot.sandbox.method = null; #< TODO: sandbox
|
||||||
|
|
||||||
|
sops.sandbox.extraHomePaths = [
|
||||||
|
".config/sops"
|
||||||
|
"nixos"
|
||||||
|
# TODO: sops should only need access to knowledge/secrets,
|
||||||
|
# except that i currently put its .sops.yaml config in the root of ~/knowledge
|
||||||
|
"knowledge"
|
||||||
|
];
|
||||||
|
|
||||||
sox.sandbox.autodetectCliPaths = "existingFileOrParent";
|
sox.sandbox.autodetectCliPaths = "existingFileOrParent";
|
||||||
sox.sandbox.whitelistAudio = true;
|
sox.sandbox.whitelistAudio = true;
|
||||||
|
|
||||||
@@ -1133,8 +1104,6 @@ in
|
|||||||
|
|
||||||
sqlite.sandbox.method = null; #< TODO: sandbox
|
sqlite.sandbox.method = null; #< TODO: sandbox
|
||||||
|
|
||||||
ssh-to-age.sandbox.autodetectCliPaths = "existingFile";
|
|
||||||
|
|
||||||
# N.B. if you call sshfs-fuse from the CLI -- without `mount.fuse` -- disable sandboxing
|
# N.B. if you call sshfs-fuse from the CLI -- without `mount.fuse` -- disable sandboxing
|
||||||
sshfs-fuse.sandbox.net = "all";
|
sshfs-fuse.sandbox.net = "all";
|
||||||
sshfs-fuse.sandbox.autodetectCliPaths = "parent";
|
sshfs-fuse.sandbox.autodetectCliPaths = "parent";
|
||||||
@@ -1147,8 +1116,6 @@ in
|
|||||||
];
|
];
|
||||||
sshfs-fuse.sandbox.keepPids = true; #< XXX: bwrap didn't need this, but bunpen does. why?
|
sshfs-fuse.sandbox.keepPids = true; #< XXX: bwrap didn't need this, but bunpen does. why?
|
||||||
|
|
||||||
sshpass.sandbox.autodetectCliPaths = "existingFile"; #< for `sshpass -f <path/to/password/file>`
|
|
||||||
|
|
||||||
strace.sandbox.enable = false; #< needs to `exec` its args, and therefore support *anything*
|
strace.sandbox.enable = false; #< needs to `exec` its args, and therefore support *anything*
|
||||||
|
|
||||||
subversion.sandbox.net = "clearnet";
|
subversion.sandbox.net = "clearnet";
|
||||||
@@ -1171,8 +1138,6 @@ in
|
|||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
swaybg.sandbox.method = null; #< TODO: sandbox
|
|
||||||
|
|
||||||
swappy.sandbox.autodetectCliPaths = "existingFileOrParent";
|
swappy.sandbox.autodetectCliPaths = "existingFileOrParent";
|
||||||
swappy.sandbox.whitelistWayland = true;
|
swappy.sandbox.whitelistWayland = true;
|
||||||
|
|
||||||
@@ -1182,6 +1147,11 @@ in
|
|||||||
systemctl.sandbox.capabilities = [ "cap_dac_override" "cap_sys_admin" ];
|
systemctl.sandbox.capabilities = [ "cap_dac_override" "cap_sys_admin" ];
|
||||||
systemctl.sandbox.keepPidsAndProc = true;
|
systemctl.sandbox.keepPidsAndProc = true;
|
||||||
|
|
||||||
|
tcpdump.sandbox.net = "all";
|
||||||
|
tcpdump.sandbox.autodetectCliPaths = "existingFileOrParent";
|
||||||
|
tcpdump.sandbox.capabilities = [ "net_admin" "net_raw" ];
|
||||||
|
tcpdump.sandbox.tryKeepUsers = true;
|
||||||
|
|
||||||
tdesktop.persist.byStore.private = [ ".local/share/TelegramDesktop" ];
|
tdesktop.persist.byStore.private = [ ".local/share/TelegramDesktop" ];
|
||||||
|
|
||||||
tokodon.buildCost = 1;
|
tokodon.buildCost = 1;
|
||||||
@@ -1194,10 +1164,6 @@ in
|
|||||||
|
|
||||||
typescript-language-server.buildCost = 2;
|
typescript-language-server.buildCost = 2;
|
||||||
typescript-language-server.sandbox.whitelistPwd = true;
|
typescript-language-server.sandbox.whitelistPwd = true;
|
||||||
typescript-language-server.persist.byStore.ephemeral = [
|
|
||||||
".cache/typescript"
|
|
||||||
".npm" # .npm/{_cacache,_logs}
|
|
||||||
];
|
|
||||||
|
|
||||||
tumiki-fighters.buildCost = 1;
|
tumiki-fighters.buildCost = 1;
|
||||||
tumiki-fighters.sandbox.whitelistAudio = true;
|
tumiki-fighters.sandbox.whitelistAudio = true;
|
||||||
@@ -1223,8 +1189,6 @@ in
|
|||||||
"/sys/bus/usb"
|
"/sys/bus/usb"
|
||||||
];
|
];
|
||||||
|
|
||||||
uvtools.sandbox.method = null; #< TODO: sandbox
|
|
||||||
|
|
||||||
vala-language-server.sandbox.whitelistPwd = true;
|
vala-language-server.sandbox.whitelistPwd = true;
|
||||||
vala-language-server.suggestedPrograms = [
|
vala-language-server.suggestedPrograms = [
|
||||||
# might someday support cmake, too: <https://github.com/vala-lang/vala-language-server/issues/73>
|
# might someday support cmake, too: <https://github.com/vala-lang/vala-language-server/issues/73>
|
||||||
@@ -1277,8 +1241,6 @@ in
|
|||||||
wirelesstools.sandbox.capabilities = [ "net_admin" ];
|
wirelesstools.sandbox.capabilities = [ "net_admin" ];
|
||||||
wirelesstools.sandbox.tryKeepUsers = true;
|
wirelesstools.sandbox.tryKeepUsers = true;
|
||||||
|
|
||||||
wiremix.sandbox.whitelistAudio = true;
|
|
||||||
|
|
||||||
wl-clipboard.sandbox.whitelistWayland = true;
|
wl-clipboard.sandbox.whitelistWayland = true;
|
||||||
wl-clipboard.sandbox.keepPids = true; #< this is needed, but not sure why?
|
wl-clipboard.sandbox.keepPids = true; #< this is needed, but not sure why?
|
||||||
|
|
||||||
@@ -1298,11 +1260,7 @@ in
|
|||||||
|
|
||||||
sane.persist.sys.byStore.plaintext = lib.mkIf config.sane.programs.guiApps.enabled [
|
sane.persist.sys.byStore.plaintext = lib.mkIf config.sane.programs.guiApps.enabled [
|
||||||
# "/var/lib/alsa" # preserve output levels, default devices
|
# "/var/lib/alsa" # preserve output levels, default devices
|
||||||
{
|
"/var/lib/systemd/backlight" # backlight brightness
|
||||||
# backlight brightness; MUST be `bind`, else systemd loses its shit with "Too many levels of symbolic links".
|
|
||||||
path = "/var/lib/systemd/backlight";
|
|
||||||
method = "bind";
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
hardware.graphics = lib.mkIf config.sane.programs.guiApps.enabled ({
|
hardware.graphics = lib.mkIf config.sane.programs.guiApps.enabled ({
|
||||||
|
@@ -3,32 +3,22 @@
|
|||||||
# - default recording input will be silent, on lappy.
|
# - default recording input will be silent, on lappy.
|
||||||
# - Audio Setup -> Rescan Audio Devices ...
|
# - Audio Setup -> Rescan Audio Devices ...
|
||||||
# - Audio Setup -> Recording device -> sysdefault
|
# - Audio Setup -> Recording device -> sysdefault
|
||||||
{ lib, pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
let
|
|
||||||
# wxGTK32 uses webkitgtk-4.0.
|
|
||||||
# audacity doesn't actually need webkit though, so diable to reduce closure
|
|
||||||
wxGTK32 = pkgs.wxGTK32.override {
|
|
||||||
withWebKit = false;
|
|
||||||
};
|
|
||||||
# basePkg = pkgs.audacity.overrideAttrs (base: {
|
|
||||||
# # upstream audacity.desktop specifies GDK_BACKEND=x11, with which it doesn't actually launch :|
|
|
||||||
# postInstall = (base.postInstall or "") + ''
|
|
||||||
# substituteInPlace $out/share/applications/${appId}.desktop \
|
|
||||||
# --replace-fail 'GDK_BACKEND=x11 ' ""
|
|
||||||
# '';
|
|
||||||
|
|
||||||
# # XXX(2025-03-03): upstream nixpkgs incorrectly defaults `GDK_BACKEND=x11`,
|
|
||||||
# # even though audacity runs fine on wayland
|
|
||||||
# postFixup = lib.replaceStrings [ "--set-default GDK_BACKEND x11" ] [ "" ] base.postFixup;
|
|
||||||
# });
|
|
||||||
basePkg = pkgs.tenacity; #< XXX(2025-07-27): upstream audacity fails build; use tenacity until fixed
|
|
||||||
appId = basePkg.pname;
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
sane.programs.audacity = {
|
sane.programs.audacity = {
|
||||||
packageUnwrapped = basePkg.override {
|
packageUnwrapped = (pkgs.audacity.override {
|
||||||
inherit wxGTK32;
|
# wxGTK32 uses webkitgtk-4.0.
|
||||||
};
|
# audacity doesn't actually need webkit though, so diable to reduce closure
|
||||||
|
wxGTK32 = pkgs.wxGTK32.override {
|
||||||
|
withWebKit = false;
|
||||||
|
};
|
||||||
|
}).overrideAttrs (base: {
|
||||||
|
# upstream audacity.desktop specifies GDK_BACKEND=x11, with which it doesn't actually launch :|
|
||||||
|
postInstall = (base.postInstall or "") + ''
|
||||||
|
substituteInPlace $out/share/applications/audacity.desktop \
|
||||||
|
--replace-fail 'GDK_BACKEND=x11 ' ""
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
|
||||||
buildCost = 1;
|
buildCost = 1;
|
||||||
|
|
||||||
@@ -40,21 +30,20 @@ in
|
|||||||
"tmp"
|
"tmp"
|
||||||
"Music"
|
"Music"
|
||||||
# audacity needs the entire config dir mounted if running in a sandbox
|
# audacity needs the entire config dir mounted if running in a sandbox
|
||||||
".config/${appId}"
|
".config/audacity"
|
||||||
];
|
];
|
||||||
sandbox.extraPaths = [
|
sandbox.extraPaths = [
|
||||||
"/dev/snd" # for recording audio inputs to work
|
"/dev/snd" # for recording audio inputs to work
|
||||||
];
|
];
|
||||||
|
|
||||||
# disable first-run splash screen
|
# disable first-run splash screen
|
||||||
fs.".config/${appId}/${appId}.cfg".file.text = ''
|
fs.".config/audacity/audacity.cfg".file.text = ''
|
||||||
PrefsVersion=1.1.1r1
|
PrefsVersion=1.1.1r1
|
||||||
[GUI]
|
[GUI]
|
||||||
ShowSplashScreen=0
|
ShowSplashScreen=0
|
||||||
[Version]
|
[Version]
|
||||||
Major=${lib.versions.major basePkg.version}
|
Major=3
|
||||||
Minor=${lib.versions.minor basePkg.version}
|
Minor=4
|
||||||
Micro=${lib.versions.patch basePkg.version}
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -3,5 +3,7 @@
|
|||||||
{
|
{
|
||||||
sane.programs.ausyscall = {
|
sane.programs.ausyscall = {
|
||||||
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.audit "ausyscall";
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.audit "ausyscall";
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,7 +22,7 @@ in
|
|||||||
# do this here, because the nixos service isn't so easily patched.
|
# do this here, because the nixos service isn't so easily patched.
|
||||||
postInstall = (upstream.postInstall or "") + ''
|
postInstall = (upstream.postInstall or "") + ''
|
||||||
wrapProgram "$out/sbin/avahi-daemon" \
|
wrapProgram "$out/sbin/avahi-daemon" \
|
||||||
--add-flag --no-drop-root
|
--add-flags --no-drop-root
|
||||||
'';
|
'';
|
||||||
nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
||||||
pkgs.makeBinaryWrapper
|
pkgs.makeBinaryWrapper
|
||||||
|
@@ -88,6 +88,18 @@ in
|
|||||||
{
|
{
|
||||||
sane.programs.bemenu = {
|
sane.programs.bemenu = {
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
env.BEMENU_OPTS = bemenuOpts;
|
|
||||||
|
packageUnwrapped = pkgs.bemenu.overrideAttrs (upstream: {
|
||||||
|
nativeBuildInputs = (upstream.nativeBuildInputs or []) ++ [
|
||||||
|
pkgs.makeBinaryWrapper
|
||||||
|
];
|
||||||
|
# can alternatively be specified as CLI flags
|
||||||
|
postInstall = (upstream.postInstall or "") + ''
|
||||||
|
wrapProgram $out/bin/bemenu \
|
||||||
|
--set BEMENU_OPTS "${bemenuOpts}"
|
||||||
|
wrapProgram $out/bin/bemenu-run \
|
||||||
|
--set BEMENU_OPTS "${bemenuOpts}"
|
||||||
|
'';
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,13 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
{
|
|
||||||
sane.programs.blanket = {
|
|
||||||
# com.rafaelmardojai.Blanket
|
|
||||||
buildCost = 1;
|
|
||||||
sandbox.whitelistAudio = true;
|
|
||||||
sandbox.whitelistDbus.user.own = [
|
|
||||||
"com.rafaelmardojai.Blanket"
|
|
||||||
"org.mpris.MediaPlayer2.Blanket"
|
|
||||||
];
|
|
||||||
sandbox.whitelistWayland = true;
|
|
||||||
};
|
|
||||||
}
|
|
@@ -50,10 +50,9 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# plug into the nixpkgs bonsaid service.
|
# plug into the (proposed) nixpkgs bonsaid service.
|
||||||
# it's a user service, and since i don't use the service manager it doesn't actually activate:
|
# it's a user service, and since i don't use the service manager it doesn't actually activate:
|
||||||
# i just steal the config file generation from it :)
|
# i just steal the config file generation from it :)
|
||||||
services.bonsaid.package = config.sane.programs.bonsai.package;
|
|
||||||
services.bonsaid.settings = lib.mkIf cfg.enabled (lib.mkMerge [
|
services.bonsaid.settings = lib.mkIf cfg.enabled (lib.mkMerge [
|
||||||
cfg.config.transitions
|
cfg.config.transitions
|
||||||
[{
|
[{
|
||||||
|
@@ -13,28 +13,13 @@ in
|
|||||||
"/sys/block"
|
"/sys/block"
|
||||||
"/sys/dev/block"
|
"/sys/dev/block"
|
||||||
"/sys/devices"
|
"/sys/devices"
|
||||||
#vvv required for `sudo btrfs scrub start`
|
|
||||||
"/sys/fs"
|
|
||||||
#vvv required for `sudo btrfs scrub status` to show stats
|
|
||||||
"/var/lib/btrfs"
|
|
||||||
];
|
];
|
||||||
sandbox.tryKeepUsers = true;
|
sandbox.tryKeepUsers = true;
|
||||||
sandbox.keepPids = true; # required for `sudo btrfs scrub start`
|
sandbox.capabilities = [ "sys_admin" ]; # for `btrfs scrub`
|
||||||
sandbox.capabilities = [
|
|
||||||
"dac_read_search" # for `btrfs replace`
|
|
||||||
"sys_admin" # for `btrfs scrub`
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# TODO: service sandboxing
|
# TODO: service sandboxing
|
||||||
services.btrfs.autoScrub.enable = lib.mkIf cfg.enabled true;
|
services.btrfs.autoScrub.enable = lib.mkIf cfg.enabled true;
|
||||||
services.btrfs.autoScrub.interval = "weekly";
|
services.btrfs.autoScrub.interval = "weekly";
|
||||||
|
|
||||||
# nixos/modules/tasks/filesystems/btrfs.nix fires this assertion, but its implementation totally handles the case of 0 btrfs filesystems.
|
|
||||||
sane.silencedAssertions = lib.mkIf cfg.enabled [''
|
|
||||||
If 'services.btrfs.autoScrub' is enabled, you need to have at least one
|
|
||||||
btrfs file system mounted via 'fileSystems' or specify a list manually
|
|
||||||
in 'services.btrfs.autoScrub.fileSystems'.
|
|
||||||
''];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,7 +7,7 @@ in
|
|||||||
packageUnwrapped = pkgs.bunpen.overrideAttrs (base: {
|
packageUnwrapped = pkgs.bunpen.overrideAttrs (base: {
|
||||||
# create a directory which holds just the `bunpen` so that we
|
# create a directory which holds just the `bunpen` so that we
|
||||||
# can add bunpen as a dependency to binaries via `PATH=/run/current-system/libexec/bunpen` without forcing rebuild every time bunpen changes
|
# can add bunpen as a dependency to binaries via `PATH=/run/current-system/libexec/bunpen` without forcing rebuild every time bunpen changes
|
||||||
postInstall = (base.postInstall or "") + ''
|
postInstall = ''
|
||||||
mkdir -p $out/libexec/bunpen
|
mkdir -p $out/libexec/bunpen
|
||||||
ln -s $out/bin/bunpen $out/libexec/bunpen/bunpen
|
ln -s $out/bin/bunpen $out/libexec/bunpen/bunpen
|
||||||
'';
|
'';
|
||||||
|
@@ -1,16 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
{
|
|
||||||
sane.programs.cargo = {
|
|
||||||
#v XXX(2025-02-23): normal `cargo` fails to build for cross (temporarily?). use prebuilt instead.
|
|
||||||
# NOT easy to debug/fix. git bisect pins this between ceba2c6c3b (good) and 62a28e5a3d (bad)
|
|
||||||
# packageUnwrapped = pkgs.rust.packages.prebuilt.cargo;
|
|
||||||
|
|
||||||
buildCost = 1; # 2.5 GiB closure
|
|
||||||
|
|
||||||
persist.byStore.plaintext = [ ".cargo" ];
|
|
||||||
# probably this sandboxing is too restrictive; i'm sandboxing it for rust-analyzer / neovim LSP
|
|
||||||
sandbox.whitelistPwd = true;
|
|
||||||
sandbox.net = "all";
|
|
||||||
sandbox.extraHomePaths = [ "dev" "ref" ];
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,28 +0,0 @@
|
|||||||
{ config, lib, pkgs, ...}:
|
|
||||||
let
|
|
||||||
cfg = config.sane.programs.cassini;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
sane.programs.cassini = {
|
|
||||||
sandbox.method = null; #< TODO: sandbox
|
|
||||||
};
|
|
||||||
|
|
||||||
# inspired by SSDP firewall code.
|
|
||||||
# Elegoo printers use their own SSDP-like discovery method, but on port 3000 instead of 1900 and 255.255.255.255 instead of 239.255.255.250:
|
|
||||||
# 1. i send a broadcast packet to 255.255.255.255 port 3000;
|
|
||||||
# 2. printers respond with a packet that originates from their port 3000, addressed to whichever port i sent from.
|
|
||||||
#
|
|
||||||
# TODO: can i generalize the SSDP rule from <hosts/common/net/upnp.nix> to be generic over port?
|
|
||||||
networking.firewall.extraCommands = with pkgs; lib.mkIf cfg.enabled ''
|
|
||||||
# originally for SSDP: <https://serverfault.com/a/911286>
|
|
||||||
# ipset -! means "don't fail if set already exists"
|
|
||||||
${ipset}/bin/ipset create -! upnp hash:ip,port timeout 10
|
|
||||||
${iptables}/bin/iptables -A OUTPUT -d 255.255.255.255/32 -p udp -m udp --dport 3000 -j SET --add-set upnp src,src --exist
|
|
||||||
${iptables}/bin/iptables -A INPUT -p udp -m set --match-set upnp dst,dst -j ACCEPT
|
|
||||||
|
|
||||||
# IPv6 ruleset. ff02::/16 means *any* link-local multicast group (so this is probably more broad than it needs to be)
|
|
||||||
${ipset}/bin/ipset create -! upnp6 hash:ip,port timeout 10 family inet6
|
|
||||||
${iptables}/bin/ip6tables -A OUTPUT -d ff02::/16 -p udp -m udp --dport 3000 -j SET --add-set upnp6 src,src --exist
|
|
||||||
${iptables}/bin/ip6tables -A INPUT -p udp -m set --match-set upnp6 dst,dst -j ACCEPT
|
|
||||||
'';
|
|
||||||
}
|
|
@@ -1,19 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
{
|
|
||||||
sane.programs.confy = {
|
|
||||||
sandbox.net = "all";
|
|
||||||
sandbox.whitelistDri = true;
|
|
||||||
sandbox.whitelistWayland = true;
|
|
||||||
sandbox.mesaCacheDir = ".cache/net.kirgroup.confy/mesa";
|
|
||||||
sandbox.whitelistDbus.user.own = [ "net.kirgroup.confy" ];
|
|
||||||
sandbox.whitelistPortal = [
|
|
||||||
"NetworkMonitor"
|
|
||||||
"OpenURI"
|
|
||||||
];
|
|
||||||
|
|
||||||
persist.byStore.private = [
|
|
||||||
".cache/net.kirgroup.confy"
|
|
||||||
# ".local/share/net.kirgroup.confy" #< empty
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
conky.config = {
|
conky.config = {
|
||||||
out_to_wayland = true,
|
out_to_wayland = true,
|
||||||
out_to_x = false,
|
|
||||||
update_interval = 10,
|
update_interval = 10,
|
||||||
|
|
||||||
alignment = 'middle_middle',
|
alignment = 'middle_middle',
|
||||||
|
@@ -11,12 +11,11 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.programs.cups = {
|
sane.programs.cups = {
|
||||||
sandbox.method = null; #< TODO: sandbox
|
|
||||||
suggestedPrograms = [
|
suggestedPrograms = [
|
||||||
"system-config-printer"
|
"system-config-printer"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
sane.programs.system-config-printer.sandbox.method = null; #< TODO: sandbox
|
sane.programs.system-config-printer = {};
|
||||||
|
|
||||||
services.printing = lib.mkIf cfg.enabled {
|
services.printing = lib.mkIf cfg.enabled {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@@ -5,7 +5,6 @@
|
|||||||
./abaddon.nix
|
./abaddon.nix
|
||||||
./aerc.nix
|
./aerc.nix
|
||||||
./alacritty.nix
|
./alacritty.nix
|
||||||
./alpaca.nix
|
|
||||||
./alsa-ucm-conf
|
./alsa-ucm-conf
|
||||||
./animatch.nix
|
./animatch.nix
|
||||||
./assorted.nix
|
./assorted.nix
|
||||||
@@ -14,7 +13,6 @@
|
|||||||
./avahi.nix
|
./avahi.nix
|
||||||
./bemenu.nix
|
./bemenu.nix
|
||||||
./bitcoin-cli.nix
|
./bitcoin-cli.nix
|
||||||
./blanket.nix
|
|
||||||
./blueberry.nix
|
./blueberry.nix
|
||||||
./blueman.nix
|
./blueman.nix
|
||||||
./bonsai.nix
|
./bonsai.nix
|
||||||
@@ -28,12 +26,9 @@
|
|||||||
./cantata.nix
|
./cantata.nix
|
||||||
./capsh.nix
|
./capsh.nix
|
||||||
./captree.nix
|
./captree.nix
|
||||||
./cargo.nix
|
|
||||||
./cassini.nix
|
|
||||||
./catt.nix
|
./catt.nix
|
||||||
./celeste64.nix
|
./celeste64.nix
|
||||||
./chatty.nix
|
./chatty.nix
|
||||||
./confy.nix
|
|
||||||
./conky
|
./conky
|
||||||
./cozy.nix
|
./cozy.nix
|
||||||
./cups.nix
|
./cups.nix
|
||||||
@@ -59,7 +54,6 @@
|
|||||||
./evince.nix
|
./evince.nix
|
||||||
./evolution-data-server.nix
|
./evolution-data-server.nix
|
||||||
./exiftool.nix
|
./exiftool.nix
|
||||||
./expect.nix
|
|
||||||
./fcitx5.nix
|
./fcitx5.nix
|
||||||
./feedbackd.nix
|
./feedbackd.nix
|
||||||
./fftest.nix
|
./fftest.nix
|
||||||
@@ -86,11 +80,10 @@
|
|||||||
./gnome-frog.nix
|
./gnome-frog.nix
|
||||||
./gnome-keyring
|
./gnome-keyring
|
||||||
./gnome-maps.nix
|
./gnome-maps.nix
|
||||||
./gnome-sound-recorder.nix
|
|
||||||
./gnome-weather.nix
|
./gnome-weather.nix
|
||||||
./go2tv.nix
|
./go2tv.nix
|
||||||
./gocryptfs.nix
|
./gocryptfs.nix
|
||||||
./gpodder
|
./gpodder.nix
|
||||||
./gpsd.nix
|
./gpsd.nix
|
||||||
./gps-share.nix
|
./gps-share.nix
|
||||||
./grimshot.nix
|
./grimshot.nix
|
||||||
@@ -103,7 +96,6 @@
|
|||||||
./haredoc.nix
|
./haredoc.nix
|
||||||
./helix.nix
|
./helix.nix
|
||||||
./htop
|
./htop
|
||||||
./htpasswd.nix
|
|
||||||
./iio-sensor-proxy.nix
|
./iio-sensor-proxy.nix
|
||||||
./imagemagick.nix
|
./imagemagick.nix
|
||||||
./inkscape.nix
|
./inkscape.nix
|
||||||
@@ -114,7 +106,6 @@
|
|||||||
./komikku.nix
|
./komikku.nix
|
||||||
./koreader
|
./koreader
|
||||||
./krita.nix
|
./krita.nix
|
||||||
./lddtree.nix
|
|
||||||
./less.nix
|
./less.nix
|
||||||
./lftp.nix
|
./lftp.nix
|
||||||
./lgtrombetta-compass.nix
|
./lgtrombetta-compass.nix
|
||||||
@@ -127,7 +118,6 @@
|
|||||||
./megapixels.nix
|
./megapixels.nix
|
||||||
./megapixels-next.nix
|
./megapixels-next.nix
|
||||||
./mepo.nix
|
./mepo.nix
|
||||||
./mercurial
|
|
||||||
./mimeo
|
./mimeo
|
||||||
./mimetype.nix
|
./mimetype.nix
|
||||||
./mmcli.nix
|
./mmcli.nix
|
||||||
@@ -138,7 +128,6 @@
|
|||||||
./nautilus.nix
|
./nautilus.nix
|
||||||
./neovim
|
./neovim
|
||||||
./networkmanager_dmenu
|
./networkmanager_dmenu
|
||||||
./newelle.nix
|
|
||||||
./newsflash.nix
|
./newsflash.nix
|
||||||
./nheko.nix
|
./nheko.nix
|
||||||
./nicotine-plus.nix
|
./nicotine-plus.nix
|
||||||
@@ -165,7 +154,6 @@
|
|||||||
./playerctl.nix
|
./playerctl.nix
|
||||||
./qmk-udev-rules.nix
|
./qmk-udev-rules.nix
|
||||||
./radicale.nix
|
./radicale.nix
|
||||||
./readline.nix
|
|
||||||
./rhythmbox.nix
|
./rhythmbox.nix
|
||||||
./ripgrep.nix
|
./ripgrep.nix
|
||||||
./rofi
|
./rofi
|
||||||
@@ -185,22 +173,17 @@
|
|||||||
./sblast
|
./sblast
|
||||||
./schlock.nix
|
./schlock.nix
|
||||||
./seatd.nix
|
./seatd.nix
|
||||||
./see-cat.nix
|
|
||||||
./sfeed.nix
|
./sfeed.nix
|
||||||
./shadow.nix
|
./shadow.nix
|
||||||
./signal-desktop.nix
|
./signal-desktop.nix
|
||||||
./slack.nix
|
|
||||||
./sm64coopdx.nix
|
./sm64coopdx.nix
|
||||||
./sm64ex-coop.nix
|
./sm64ex-coop.nix
|
||||||
./smartmontools.nix
|
./smartmontools.nix
|
||||||
./socat.nix
|
|
||||||
./sops.nix
|
|
||||||
./soundconverter.nix
|
./soundconverter.nix
|
||||||
./splatmoji.nix
|
./splatmoji.nix
|
||||||
./spot.nix
|
./spot.nix
|
||||||
./spotify.nix
|
./spotify.nix
|
||||||
./steam.nix
|
./steam.nix
|
||||||
./ssh.nix
|
|
||||||
./stepmania.nix
|
./stepmania.nix
|
||||||
./strings.nix
|
./strings.nix
|
||||||
./sublime-music.nix
|
./sublime-music.nix
|
||||||
@@ -213,11 +196,9 @@
|
|||||||
./switchboard.nix
|
./switchboard.nix
|
||||||
./syshud.nix
|
./syshud.nix
|
||||||
./tangram.nix
|
./tangram.nix
|
||||||
./tcpdump.nix
|
|
||||||
./tor-browser.nix
|
./tor-browser.nix
|
||||||
./tuba.nix
|
./tuba.nix
|
||||||
./unl0kr
|
./unl0kr
|
||||||
./uptime.nix
|
|
||||||
./v4l-utils.nix
|
./v4l-utils.nix
|
||||||
./via.nix
|
./via.nix
|
||||||
./video-trimmer.nix
|
./video-trimmer.nix
|
||||||
@@ -246,8 +227,6 @@
|
|||||||
./zathura.nix
|
./zathura.nix
|
||||||
./zeal.nix
|
./zeal.nix
|
||||||
./zecwallet-lite.nix
|
./zecwallet-lite.nix
|
||||||
./zelda64recomp.nix
|
|
||||||
./zoom-us.nix
|
|
||||||
./zulip.nix
|
./zulip.nix
|
||||||
./zsa-udev-rules.nix
|
./zsa-udev-rules.nix
|
||||||
./zfs-tools.nix
|
./zfs-tools.nix
|
||||||
|
@@ -1,6 +1,15 @@
|
|||||||
{ ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.dialect = {
|
sane.programs.dialect = {
|
||||||
|
packageUnwrapped = pkgs.dialect.overrideAttrs (upstream: {
|
||||||
|
# TODO: send upstream
|
||||||
|
# TODO: figure out how to get audio working
|
||||||
|
# TODO: move to runtimeDependencies?
|
||||||
|
buildInputs = upstream.buildInputs ++ [
|
||||||
|
pkgs.glib-networking # for TLS
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
buildCost = 1;
|
buildCost = 1;
|
||||||
|
|
||||||
sandbox.wrapperType = "inplace"; # share/search_providers/ calls back into the binary, weird wrap semantics
|
sandbox.wrapperType = "inplace"; # share/search_providers/ calls back into the binary, weird wrap semantics
|
||||||
|
@@ -50,14 +50,13 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# packageUnwrapped = pkgs.dino.override {
|
packageUnwrapped = pkgs.dino.override {
|
||||||
# # XXX(2024/04/24): build without echo cancelation (i.e. force WITH_VOICE_PROCESSOR to be undefined).
|
# XXX(2024/04/24): build without echo cancelation (i.e. force WITH_VOICE_PROCESSOR to be undefined).
|
||||||
# # this means that if the other end of the call is on speaker phone, i'm liable to hear my own voice
|
# this means that if the other end of the call is on speaker phone, i'm liable to hear my own voice
|
||||||
# # leave their speaker, enter their mic, and then return to me.
|
# leave their speaker, enter their mic, and then return to me.
|
||||||
# # the benefit is a >50% reduction in CPU use. insignificant on any modern PC; make-or-break on a low-power Pinephone.
|
# the benefit is a >50% reduction in CPU use. insignificant on any modern PC; make-or-break on a low-power Pinephone.
|
||||||
# # XXX(2025/05/16): this appears to no longer be optional
|
webrtc-audio-processing = null;
|
||||||
# # webrtc-audio-processing_1 = null;
|
};
|
||||||
# };
|
|
||||||
|
|
||||||
# suggestedPrograms = [
|
# suggestedPrograms = [
|
||||||
# "gnome-keyring"
|
# "gnome-keyring"
|
||||||
|
@@ -1,25 +1,14 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.dtrx = {
|
sane.programs.dtrx = {
|
||||||
packageUnwrapped = (pkgs.dtrx.override {
|
packageUnwrapped = pkgs.dtrx.override {
|
||||||
# `binutils` is the nix wrapper, which reads nix-related env vars
|
# `binutils` is the nix wrapper, which reads nix-related env vars
|
||||||
# before passing on to e.g. `ld`.
|
# before passing on to e.g. `ld`.
|
||||||
# dtrx probably only needs `ar` at runtime, not even `ld`.
|
# dtrx probably only needs `ar` at runtime, not even `ld`.
|
||||||
# this is a "correctness" (and closure) fix, not a build or even runtime fix (probably)
|
|
||||||
binutils = pkgs.binutils-unwrapped;
|
binutils = pkgs.binutils-unwrapped;
|
||||||
# build without rpm support, since `rpm` package doesn't cross-compile.
|
# build without rpm support, since `rpm` package doesn't cross-compile.
|
||||||
# rpm = null;
|
rpm = null;
|
||||||
}).overrideAttrs (upstream: {
|
};
|
||||||
# patches = (upstream.patches or []) ++ [
|
|
||||||
# (pkgs.fetchpatch2 {
|
|
||||||
# # https://github.com/dtrx-py/dtrx/pull/62
|
|
||||||
# # this is needed for as long as i'm interacting with .tar.lz archives which are actually LZMA and not lzip.
|
|
||||||
# name = "fix .tar.lz mapping";
|
|
||||||
# url = "https://github.com/dtrx-py/dtrx/commit/ff379f1444b142bb461f26780e32f82e60856be2.patch";
|
|
||||||
# hash = "sha256-WNz5i/iJqyxmZh/1mw6M8hWeiQdRvyhCta7gN/va6lQ=";
|
|
||||||
# })
|
|
||||||
# ];
|
|
||||||
});
|
|
||||||
sandbox.whitelistPwd = true;
|
sandbox.whitelistPwd = true;
|
||||||
sandbox.autodetectCliPaths = "existing"; #< for the archive
|
sandbox.autodetectCliPaths = "existing"; #< for the archive
|
||||||
};
|
};
|
||||||
|
@@ -5,28 +5,23 @@
|
|||||||
# - touch-based scroll works well (for moby)
|
# - touch-based scroll works well (for moby)
|
||||||
# - URL bar constantly resets cursor to the start of the line as i type
|
# - URL bar constantly resets cursor to the start of the line as i type
|
||||||
# - maybe due to the URLbar suggestions getting in the way
|
# - maybe due to the URLbar suggestions getting in the way
|
||||||
#
|
{ pkgs, ... }:
|
||||||
# TODO: consider wrapping with `WEBKIT_USE_SINGLE_WEB_PROCESS=1` for better perf
|
|
||||||
# - this runs all tabs in 1 process. which is fine, if i'm not a heavy multi-tabber
|
|
||||||
{ lib, ... }:
|
|
||||||
{
|
{
|
||||||
sane.programs.epiphany = {
|
sane.programs.epiphany = {
|
||||||
sandbox.wrapperType = "inplace"; # /share/epiphany/default-bookmarks.rdf refers back to /share; dbus files to /libexec
|
sandbox.wrapperType = "inplace"; # /share/epiphany/default-bookmarks.rdf refers back to /share; dbus files to /libexec
|
||||||
sandbox.net = "clearnet";
|
sandbox.net = "clearnet";
|
||||||
sandbox.whitelistAudio = true;
|
sandbox.whitelistAudio = true;
|
||||||
sandbox.whitelistDbus.user = true; #< TODO: reduce. requires to support nested dbus proxy though.
|
sandbox.whitelistDbus.user.own = [ "org.gnome.Epiphany" ];
|
||||||
# sandbox.whitelistDbus.user.own = [ "org.gnome.Epiphany" ];
|
sandbox.whitelistPortal = [
|
||||||
# sandbox.whitelistPortal = [
|
# these are all speculative
|
||||||
# # these are all speculative
|
"Camera"
|
||||||
# "Camera"
|
"FileChooser"
|
||||||
# "FileChooser"
|
"Location"
|
||||||
# "Location"
|
"OpenURI"
|
||||||
# "OpenURI"
|
"Print"
|
||||||
# "Print"
|
"ProxyResolver" #< required else it doesn't load websites
|
||||||
# "ProxyResolver" #< required else it doesn't load websites
|
"ScreenCast"
|
||||||
# "ScreenCast"
|
];
|
||||||
# ];
|
|
||||||
|
|
||||||
# default sandboxing breaks rendering in weird ways. sites are super zoomed in / not scaled.
|
# default sandboxing breaks rendering in weird ways. sites are super zoomed in / not scaled.
|
||||||
# enabling DRI/DRM (as below) seems to fix that.
|
# enabling DRI/DRM (as below) seems to fix that.
|
||||||
sandbox.whitelistDri = true;
|
sandbox.whitelistDri = true;
|
||||||
@@ -35,16 +30,30 @@
|
|||||||
".config/epiphany" #< else it gets angry at launch
|
".config/epiphany" #< else it gets angry at launch
|
||||||
"tmp"
|
"tmp"
|
||||||
];
|
];
|
||||||
sandbox.extraPaths = [
|
|
||||||
# epiphany sandboxes *itself* with bwrap, and dbus-proxy which, confusingly, causes it to *require* these paths.
|
|
||||||
# TODO: these could maybe be mounted empty.
|
|
||||||
"/sys/block"
|
|
||||||
"/sys/bus"
|
|
||||||
"/sys/class"
|
|
||||||
];
|
|
||||||
|
|
||||||
buildCost = 2;
|
buildCost = 2;
|
||||||
|
|
||||||
|
# XXX(2023/07/08): running on moby without `WEBKIT_DISABLE_SANDBOX...` fails, with:
|
||||||
|
# - `bwrap: Can't make symlink at /var/run: File exists`
|
||||||
|
# this could be due to:
|
||||||
|
# - epiphany is somewhere following a symlink into /var/run instead of /run
|
||||||
|
# - (nothing in `env` or in this repo touches /var/run)
|
||||||
|
# - no xdg-desktop-portal is installed (unlikely)
|
||||||
|
#
|
||||||
|
# a few other users have hit this, in different contexts:
|
||||||
|
# - <https://gitlab.gnome.org/GNOME/gnome-builder/-/issues/1164>
|
||||||
|
# - <https://github.com/flatpak/flatpak/issues/3477>
|
||||||
|
# - <https://github.com/NixOS/nixpkgs/issues/197085>
|
||||||
|
#
|
||||||
|
# TODO: consider `WEBKIT_USE_SINGLE_WEB_PROCESS=1` for better perf
|
||||||
|
# - this runs all tabs in 1 process. which is fine, if i'm not a heavy multi-tabber
|
||||||
|
packageUnwrapped = pkgs.epiphany.overrideAttrs (upstream: {
|
||||||
|
preFixup = ''
|
||||||
|
gappsWrapperArgs+=(
|
||||||
|
--set WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS "1"
|
||||||
|
);
|
||||||
|
'' + (upstream.preFixup or "");
|
||||||
|
});
|
||||||
persist.byStore.private = [
|
persist.byStore.private = [
|
||||||
".cache/epiphany"
|
".cache/epiphany"
|
||||||
".local/share/epiphany"
|
".local/share/epiphany"
|
||||||
@@ -60,39 +69,12 @@
|
|||||||
"x-scheme-handler/about" = desktop;
|
"x-scheme-handler/about" = desktop;
|
||||||
"x-scheme-handler/unknown" = desktop;
|
"x-scheme-handler/unknown" = desktop;
|
||||||
};
|
};
|
||||||
gsettings."org/gnome/epiphany" = with lib.gvariant; {
|
gsettings."org/gnome/epiphany" = {
|
||||||
ask-for-default = false;
|
ask-for-default = false;
|
||||||
# homepage-url = "about:newtab";
|
|
||||||
search-engine-providers = [
|
|
||||||
# [
|
|
||||||
# (mkDictionaryEntry "url" (mkVariant "https://www.bing.com/search?q=%s"))
|
|
||||||
# (mkDictionaryEntry "bang" (mkVariant "!b"))
|
|
||||||
# (mkDictionaryEntry "name" (mkVariant "Bing"))
|
|
||||||
# ]
|
|
||||||
[
|
|
||||||
(mkDictionaryEntry "url" (mkVariant "https://duckduckgo.com/?q=%s&t=epiphany&kd=-1"))
|
|
||||||
(mkDictionaryEntry "bang" (mkVariant "!ddg"))
|
|
||||||
(mkDictionaryEntry "name" (mkVariant "DuckDuckGo"))
|
|
||||||
]
|
|
||||||
[
|
|
||||||
# serializes to: {'url': <'https://www.google.com/search?q=%s'>, 'bang': <'!g'>, 'name': <'Google'>},
|
|
||||||
(mkDictionaryEntry "url" (mkVariant "https://www.google.com/search?q=%s"))
|
|
||||||
(mkDictionaryEntry "bang" (mkVariant "!g"))
|
|
||||||
(mkDictionaryEntry "name" (mkVariant "Google"))
|
|
||||||
]
|
|
||||||
[
|
|
||||||
(mkDictionaryEntry "url" (mkVariant "https://kagi.com/search?q=%s"))
|
|
||||||
(mkDictionaryEntry "bang" (mkVariant "!k"))
|
|
||||||
(mkDictionaryEntry "name" (mkVariant "Kagi"))
|
|
||||||
]
|
|
||||||
];
|
|
||||||
default-search-engine = "Kagi";
|
|
||||||
};
|
};
|
||||||
gsettings."org/gnome/epiphany/web" = {
|
gsettings."org/gnome/epiphany/web" = {
|
||||||
# default-zoom-level = 1.0;
|
|
||||||
enable-adblock = true;
|
enable-adblock = true;
|
||||||
# enable-itp = false; # ??
|
# enable-itp = false; # ??
|
||||||
# enable-popups = true;
|
|
||||||
enable-website-data-storage = true;
|
enable-website-data-storage = true;
|
||||||
remember-passwords = false;
|
remember-passwords = false;
|
||||||
};
|
};
|
||||||
|
@@ -1,7 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
sane.programs.expect = {
|
|
||||||
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.expect "expect";
|
|
||||||
sandbox.enable = false; #< it's typically used to launch programs
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,26 +1,12 @@
|
|||||||
# fftest can test the haptics/vibrator on a phone:
|
# fftest can test the haptics/vibrator on a phone:
|
||||||
# - `fftest /dev/input/by-path/platform-vibrator-event`
|
# - `fftest /dev/input/by-path/platform-vibrator-event`
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
let
|
|
||||||
fftestOnly = pkgs.linkBinIntoOwnPackage pkgs.linuxConsoleTools "fftest";
|
|
||||||
#
|
|
||||||
# XXX(2025-03-24): upstream `linuxConsoleTools` depends on SDL, which doesn't cross compile.
|
|
||||||
# but `fftest` component doesn't use SDL, so if we build only that then it can cross compile:
|
|
||||||
# fftestOnly = pkgs.linuxConsoleTools.overrideAttrs (upstream: {
|
|
||||||
# buildInputs = [ ]; #< disable SDL
|
|
||||||
# buildFlags = (upstream.buildFlags or []) ++ [
|
|
||||||
# "-C" "utils" "fftest"
|
|
||||||
# ];
|
|
||||||
|
|
||||||
# installPhase = ''
|
|
||||||
# install -Dm755 utils/fftest $out/bin/fftest
|
|
||||||
# install -Dm644 docs/fftest.1 $out/share/man/man1/fftest.1
|
|
||||||
# '';
|
|
||||||
# });
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
sane.programs.fftest = {
|
sane.programs.fftest = {
|
||||||
packageUnwrapped = fftestOnly;
|
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.linuxConsoleTools [
|
||||||
|
"bin/fftest"
|
||||||
|
"share/man/man1/fftest.1.gz"
|
||||||
|
];
|
||||||
sandbox.autodetectCliPaths = "existing";
|
sandbox.autodetectCliPaths = "existing";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -21,7 +21,7 @@ in
|
|||||||
enable = lib.mkDefault true;
|
enable = lib.mkDefault true;
|
||||||
};
|
};
|
||||||
bypass-paywalls-clean = {
|
bypass-paywalls-clean = {
|
||||||
enable = lib.mkDefault false;
|
enable = lib.mkDefault true;
|
||||||
};
|
};
|
||||||
# ctrl-shift-c-should-copy = {
|
# ctrl-shift-c-should-copy = {
|
||||||
# package = pkgs.firefox-extensions.ctrl-shift-c-should-copy;
|
# package = pkgs.firefox-extensions.ctrl-shift-c-should-copy;
|
||||||
@@ -44,9 +44,6 @@ in
|
|||||||
i-still-dont-care-about-cookies = {
|
i-still-dont-care-about-cookies = {
|
||||||
enable = lib.mkDefault false; #< obsoleted by uBlock Origin annoyances/cookies lists
|
enable = lib.mkDefault false; #< obsoleted by uBlock Origin annoyances/cookies lists
|
||||||
};
|
};
|
||||||
kagi-search = {
|
|
||||||
enable = lib.mkDefault true;
|
|
||||||
};
|
|
||||||
# open-in-mpv = {
|
# open-in-mpv = {
|
||||||
# # test: `open-in-mpv 'mpv:///open?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ'`
|
# # test: `open-in-mpv 'mpv:///open?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ'`
|
||||||
# package = pkgs.firefox-extensions.open-in-mpv;
|
# package = pkgs.firefox-extensions.open-in-mpv;
|
||||||
|
@@ -10,39 +10,32 @@
|
|||||||
<dl><p>
|
<dl><p>
|
||||||
<!-- XXX: if you want multiple aliases, declare the link twice WITH A DIFFERENT HREF= else firefox dedupes them (case-insensitively) -->
|
<!-- XXX: if you want multiple aliases, declare the link twice WITH A DIFFERENT HREF= else firefox dedupes them (case-insensitively) -->
|
||||||
<dt><a href="https://aur.archlinux.org/packages?O=0&K=%s" shortcuturl="aur">Search AUR
|
<dt><a href="https://aur.archlinux.org/packages?O=0&K=%s" shortcuturl="aur">Search AUR
|
||||||
<dt><a href="https://doc.rust-lang.org/stable/std/index.html?search=Box" shortcuturl="rust">Search Rust stdlib
|
|
||||||
<dt><a href="https://docs.rs/releases/search?query=%s" shortcuturl="docsrs">Search docs.rs
|
<dt><a href="https://docs.rs/releases/search?query=%s" shortcuturl="docsrs">Search docs.rs
|
||||||
<dt><a href="https://duckduckgo.com/?t=h_&q=%s" shortcuturl="ddg">Search DuckDuckGo
|
<dt><a href="https://duckduckgo.com/?t=h_&q=%s" shortcuturl="ddg">Search DuckDuckGo
|
||||||
<dt><a href="https://en.wikipedia.org/wiki/Special:Search?search=%s" shortcuturl="w">Search Wikipedia
|
<dt><a href="https://en.wikipedia.org/wiki/Special:Search?search=%s" shortcuturl="w">Search Wikipedia
|
||||||
<dt><a href="https://github.com/nixos/nixpkgs/pulls?q=%s" shortcuturl="pr">Search nixpkgs PRs
|
<dt><a href="https://github.com/nixos/nixpkgs/pulls?q=%s" shortcuturl="pr">Search nixpkgs PRs
|
||||||
<dt><a href="https://github.com/search?type=repositories&q=%s" shortcuturl="gh">Search GitHub
|
<dt><a href="https://github.com/search?type=repositories&q=%s" shortcuturl="gh">Search GitHub
|
||||||
<dt><a href="https://kagi.com/maps/infobox?q=%s" shortcuturl="maps">Search Kagi Maps
|
|
||||||
<dt><a href="https://kagi.com/search?q=%s" shortcuturl="kagi">Search with Kagi
|
|
||||||
<dt><a href="https://lib.rs/search?q=%s" shortcuturl="librs">Search lib.rs (Rust)
|
<dt><a href="https://lib.rs/search?q=%s" shortcuturl="librs">Search lib.rs (Rust)
|
||||||
<dt><a href="https://myanimelist.net/search/all?cat=all&q=%s" shortcuturl="mal">Search MyAnimeList
|
<dt><a href="https://myanimelist.net/search/all?cat=all&q=%s" shortcuturl="mal">Search MyAnimeList
|
||||||
<dt><a href="https://pypi.org/search/?q=%s" shortcuturl="pypi">Search PyPi PYthon Packaging Index
|
|
||||||
<dt><a href="https://repology.org/projects/?maintainer=&category=&inrepo=¬inrepo=&repos=&families=&repos_newest=&families_newest=&search=%s" shortcuturl="repo">Search Repology - packages
|
<dt><a href="https://repology.org/projects/?maintainer=&category=&inrepo=¬inrepo=&repos=&families=&repos_newest=&families_newest=&search=%s" shortcuturl="repo">Search Repology - packages
|
||||||
<dt><a href="https://search.nixos.org/options?channel=unstable&query=%s" shortcuturl="opt">Search NixOS Options
|
<dt><a href="https://search.nixos.org/options?channel=unstable&query=%s" shortcuturl="opt">Search NixOS Options
|
||||||
<dt><a href="https://search.nixos.org/packages?channel=unstable&query=%s" shortcuturl="pkg">Search NixOS Packages
|
<dt><a href="https://search.nixos.org/packages?channel=unstable&query=%s" shortcuturl="pkg">Search NixOS Packages
|
||||||
<dt><a href="https://soundcloud.com/search?q=%s" shortcuturl="sc">Search Soundcloud
|
|
||||||
<!-- TODO: have kiwix load the first result if my search is an exact match -->
|
<!-- TODO: have kiwix load the first result if my search is an exact match -->
|
||||||
<dt><a href="https://w.uninsane.org/viewer#search?books.name=wikipedia_en_all_maxi&pattern=%s" shortcuturl="wk">Search Wikipedia mirror
|
<dt><a href="https://w.uninsane.org/viewer#search?books.name=wikipedia_en_all_maxi&pattern=%s" shortcuturl="wk">Search Wikipedia mirror
|
||||||
<dt><a href="https://wiki.archlinux.org/index.php?title=Special%3ASearch&search=%s" shortcuturl="arch">Search ArchWiki
|
<dt><a href="https://wiki.archlinux.org/index.php?title=Special%3ASearch&search=%s" shortcuturl="arch">Search ArchWiki
|
||||||
<dt><a href="https://wiki.nixos.org/w/index.php?search=kvm" shortcuturl="nixos">Search NixOS Wiki
|
<dt><a href="https://wiki.nixos.org/index.php?go=Go&search=%s" shortcuturl="nixos">Search NixOS Wiki
|
||||||
<dt><a href="https://www.aliexpress.us/w/wholesale-%s.html" shortcuturl="ali">Search Aliexpress
|
<dt><a href="https://www.aliexpress.us/w/wholesale-%s.html" shortcuturl="ali">Search Aliexpress
|
||||||
<dt><a href="https://www.aliexpress.us/w/wholesale-%s.html?" shortcuturl="aliexpress">Search Aliexpress
|
<dt><a href="https://www.aliexpress.us/w/wholesale-%s.html?" shortcuturl="aliexpress">Search Aliexpress
|
||||||
<dt><a href="https://www.amazon.com/s/?k=%s" shortcuturl="am">Search Amazon
|
<dt><a href="https://www.amazon.com/s/?k=%s" shortcuturl="am">Search Amazon
|
||||||
<dt><a href="https://www.amazon.com/s/?k=%s&" shortcuturl="amazon">Search Amazon
|
<dt><a href="https://www.amazon.com/s/?k=%s&" shortcuturl="amazon">Search Amazon
|
||||||
<dt><a href="https://www.ebay.com/sch/i.html?_sacat=0&_nkw=%s" shortcuturl="ebay">Search eBay
|
<dt><a href="https://www.ebay.com/sch/i.html?_sacat=0&_nkw=%s" shortcuturl="ebay">Search eBay
|
||||||
<dt><a href="https://www.etsy.com/search?q=%s" shortcuturl="etsy">Search Etsy
|
|
||||||
<dt><a href="https://www.etymonline.com/search?q=%s" shortcuturl="etym">Search Etymonline
|
<dt><a href="https://www.etymonline.com/search?q=%s" shortcuturl="etym">Search Etymonline
|
||||||
<dt><a href="https://www.google.com/maps/search/%s" shortcuturl="gmaps">Search Google Maps
|
<dt><a href="https://www.google.com/maps/search/%s" shortcuturl="maps">Search Google Maps
|
||||||
<dt><a href="https://www.google.com/search?q=%s" shortcuturl="g">Search Google
|
<dt><a href="https://www.google.com/search?q=%s" shortcuturl="g">Search Google
|
||||||
<dt><a href="https://www.google.com/search?q=%s&" shortcuturl="google">Search Google
|
<dt><a href="https://www.google.com/search?q=%s&" shortcuturl="google">Search Google
|
||||||
<dt><a href="https://www.google.com/search?tbm=shop&q=%s" shortcuturl="shopping">Search Google Shopping
|
<dt><a href="https://www.google.com/search?tbm=shop&q=%s" shortcuturl="shopping">Search Google Shopping
|
||||||
<dt><a href="https://www.google.com/search?tbm=vid&q=%s" shortcuturl="v">Search Google Videos
|
<dt><a href="https://www.google.com/search?tbm=vid&q=%s" shortcuturl="v">Search Google Videos
|
||||||
<dt><a href="https://www.google.com/search?tbm=vid&q=%s&" shortcuturl="videos">Search Google Videos
|
<dt><a href="https://www.google.com/search?tbm=vid&q=%s&" shortcuturl="videos">Search Google Videos
|
||||||
<dt><a href="https://www.google.com/search?udm=2&q=%s" shortcuturl="i">Search Google Images
|
|
||||||
<dt><a href="https://www.imdb.com/find/?q=%s" shortcuturl="imdb">Search Internet Movie DataBase
|
<dt><a href="https://www.imdb.com/find/?q=%s" shortcuturl="imdb">Search Internet Movie DataBase
|
||||||
<dt><a href="https://www.reddit.com/search/?q=%s" shortcuturl="reddit">Search Reddit
|
<dt><a href="https://www.reddit.com/search/?q=%s" shortcuturl="reddit">Search Reddit
|
||||||
<dt><a href="https://www.rottentomatoes.com/search?search=%s" shortcuturl="rt">Search Rotten Tomatoes
|
<dt><a href="https://www.rottentomatoes.com/search?search=%s" shortcuturl="rt">Search Rotten Tomatoes
|
||||||
|
@@ -43,10 +43,6 @@ in
|
|||||||
"knowledge/secrets/accounts"
|
"knowledge/secrets/accounts"
|
||||||
];
|
];
|
||||||
|
|
||||||
# firefox learns about this package by looking in ~/.mozilla/native-messaging-hosts
|
|
||||||
fs.".mozilla/native-messaging-hosts/com.github.browserpass.native.json".symlink.target
|
|
||||||
= "${browserpass}//lib/mozilla/native-messaging-hosts/com.github.browserpass.native.json";
|
|
||||||
|
|
||||||
# TODO: env.PASSWORD_STORE_DIR only needs to be present within the browser session.
|
# TODO: env.PASSWORD_STORE_DIR only needs to be present within the browser session.
|
||||||
# alternative to PASSWORD_STORE_DIR:
|
# alternative to PASSWORD_STORE_DIR:
|
||||||
# fs.".password-store".symlink.target = "knowledge/secrets/accounts";
|
# fs.".password-store".symlink.target = "knowledge/secrets/accounts";
|
||||||
|
@@ -1,3 +1,6 @@
|
|||||||
|
# common settings to toggle (at runtime, in about:config):
|
||||||
|
# > security.ssl.require_safe_negotiation
|
||||||
|
|
||||||
{ config, lib, pkgs, ...}:
|
{ config, lib, pkgs, ...}:
|
||||||
let
|
let
|
||||||
cfg = config.sane.programs.firefox.config;
|
cfg = config.sane.programs.firefox.config;
|
||||||
@@ -16,9 +19,7 @@ let
|
|||||||
cfg.addons
|
cfg.addons
|
||||||
);
|
);
|
||||||
addonSuggestedPrograms = lib.map (n: config.sane.programs."${n}") addonSuggestedProgramNames;
|
addonSuggestedPrograms = lib.map (n: config.sane.programs."${n}") addonSuggestedProgramNames;
|
||||||
addonHomePaths = lib.concatMap
|
addonHomePaths = lib.concatMap (p: p.sandbox.extraHomePaths) (addonSuggestedPrograms ++ nativeMessagingPrograms);
|
||||||
(p: p.sandbox.extraHomePaths ++ builtins.attrNames p.fs)
|
|
||||||
(addonSuggestedPrograms ++ nativeMessagingPrograms);
|
|
||||||
|
|
||||||
packageUnwrapped = let
|
packageUnwrapped = let
|
||||||
unwrapped = pkgs.firefox-unwrapped // {
|
unwrapped = pkgs.firefox-unwrapped // {
|
||||||
@@ -31,8 +32,7 @@ let
|
|||||||
# inherit the default librewolf.cfg
|
# inherit the default librewolf.cfg
|
||||||
# it can be further customized via ~/.librewolf/librewolf.overrides.cfg
|
# it can be further customized via ~/.librewolf/librewolf.overrides.cfg
|
||||||
libName = "firefox";
|
libName = "firefox";
|
||||||
# XXX(2025-08-26): nativeMessagingHosts wrapping is broken! put things in ~/.mozilla/native-messaging-hosts/ instead.
|
inherit nativeMessagingHosts;
|
||||||
# inherit nativeMessagingHosts;
|
|
||||||
|
|
||||||
nixExtensions = lib.concatMap (ext: lib.optional ext.enable ext.package) (builtins.attrValues cfg.addons);
|
nixExtensions = lib.concatMap (ext: lib.optional ext.enable ext.package) (builtins.attrValues cfg.addons);
|
||||||
|
|
||||||
@@ -48,10 +48,6 @@ let
|
|||||||
]; # ++ pkgs.librewolf-pmos-mobile.extraPrefsFiles
|
]; # ++ pkgs.librewolf-pmos-mobile.extraPrefsFiles
|
||||||
|
|
||||||
extraPolicies = {
|
extraPolicies = {
|
||||||
# firefox policy schema is documented in <repo:mozilla-firefox/firefox:browser/components/enterprisepolicies/schemas/policies-schema.json>
|
|
||||||
# and <https://mozilla.github.io/policy-templates>
|
|
||||||
# however the bulk of them seem to not actually have any effect T_T
|
|
||||||
#
|
|
||||||
# XXX(2024-12-02): using `nixExtensions` causes `about:debugging` to be blocked.
|
# XXX(2024-12-02): using `nixExtensions` causes `about:debugging` to be blocked.
|
||||||
# i guess this is because the page can install extensions, or something.
|
# i guess this is because the page can install extensions, or something.
|
||||||
# fuck that, enable it by brute force
|
# fuck that, enable it by brute force
|
||||||
@@ -60,18 +56,6 @@ let
|
|||||||
installation_mode = "allowed";
|
installation_mode = "allowed";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
PasswordManagerEnabled = false; #< TODO(2025-05-31): does this actually have an effect?
|
|
||||||
# see also ~/.mozilla/firefox/default/search.json.mozlz4
|
|
||||||
# (use mozlz4a package to view)
|
|
||||||
# XXX(2025-05-31): the below SearchEngines policy has no observable effect.
|
|
||||||
# SearchEngines = {
|
|
||||||
# Add = [];
|
|
||||||
# # Default = "search@kagi.comdefault";
|
|
||||||
# Default = "ddg"; #< builtin
|
|
||||||
# DefaultPrivate = "ddg"; #< builtin
|
|
||||||
# PreventInstalls = false;
|
|
||||||
# Remove = [];
|
|
||||||
# };
|
|
||||||
};
|
};
|
||||||
}).overrideAttrs (base: {
|
}).overrideAttrs (base: {
|
||||||
nativeBuildInputs = (base.nativeBuildInputs or []) ++ [
|
nativeBuildInputs = (base.nativeBuildInputs or []) ++ [
|
||||||
@@ -230,10 +214,7 @@ in
|
|||||||
sandbox.net = "all";
|
sandbox.net = "all";
|
||||||
sandbox.whitelistAudio = true;
|
sandbox.whitelistAudio = true;
|
||||||
sandbox.whitelistAvDev = true; #< it doesn't seem to use pipewire, but direct /dev/videoN (as of 2024/09/12)
|
sandbox.whitelistAvDev = true; #< it doesn't seem to use pipewire, but direct /dev/videoN (as of 2024/09/12)
|
||||||
sandbox.whitelistDbus.user.own = [
|
sandbox.whitelistDbus.user.own = [ "org.mozilla.firefox.*" ];
|
||||||
"org.mozilla.firefox.*"
|
|
||||||
"org.mpris.MediaPlayer2.firefox.*"
|
|
||||||
];
|
|
||||||
sandbox.whitelistPortal = [
|
sandbox.whitelistPortal = [
|
||||||
"Camera" # not sure if used
|
"Camera" # not sure if used
|
||||||
# "Email" # not sure if used
|
# "Email" # not sure if used
|
||||||
@@ -243,7 +224,6 @@ in
|
|||||||
"Print" # not sure if used
|
"Print" # not sure if used
|
||||||
"ScreenCast" # not sure if used
|
"ScreenCast" # not sure if used
|
||||||
];
|
];
|
||||||
sandbox.whitelistSecurityKeys = true;
|
|
||||||
sandbox.whitelistSendNotifications = true;
|
sandbox.whitelistSendNotifications = true;
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
sandbox.extraHomePaths = [
|
sandbox.extraHomePaths = [
|
||||||
@@ -274,127 +254,38 @@ in
|
|||||||
|
|
||||||
env.BROWSER = "firefox"; # used by misc tools like xdg-email, as fallback
|
env.BROWSER = "firefox"; # used by misc tools like xdg-email, as fallback
|
||||||
|
|
||||||
fs.".mozilla/firefox/bookmarks.html".symlink.target = ./bookmarks.html;
|
fs = {
|
||||||
# instruct Firefox to put the profile in a predictable directory (so we can do things like persist just it).
|
".mozilla/firefox/bookmarks.html".symlink.target = ./bookmarks.html;
|
||||||
# XXX: the directory *must* exist, even if empty; Firefox will not create the directory itself.
|
|
||||||
fs.".mozilla/firefox/profiles.ini".symlink.text = ''
|
|
||||||
[Profile0]
|
|
||||||
Name=default
|
|
||||||
IsRelative=1
|
|
||||||
Path=default
|
|
||||||
Default=1
|
|
||||||
|
|
||||||
[General]
|
# instruct Firefox to put the profile in a predictable directory (so we can do things like persist just it).
|
||||||
StartWithLastProfile=1
|
# XXX: the directory *must* exist, even if empty; Firefox will not create the directory itself.
|
||||||
'';
|
".mozilla/firefox/profiles.ini".symlink.text = ''
|
||||||
|
[Profile0]
|
||||||
|
Name=default
|
||||||
|
IsRelative=1
|
||||||
|
Path=default
|
||||||
|
Default=1
|
||||||
|
|
||||||
fs.".mozilla/firefox/user.js".symlink.target = ./user.js;
|
[General]
|
||||||
fs.".mozilla/firefox/default/search.json.mozlz4".symlink.target = let
|
StartWithLastProfile=1
|
||||||
drv = pkgs.stdenvNoCC.mkDerivation {
|
'';
|
||||||
# Mozilla uses a custom compression scheme for `search.json` because they're ASSHOLES.
|
|
||||||
# seriously, why do you need to compress this 2 KiB file? and then why do you need to INVENT YOUR OWN COMPRESSION FORMAT FOR THAT?
|
".mozilla/firefox/user.js".symlink.target = ./user.js;
|
||||||
# GET YOUR HEAD OUT OF YOUR ASS.
|
};
|
||||||
#
|
|
||||||
# search.json fields:
|
|
||||||
# - `metaData.defaultEngineIdHash`: this is a digest of the defaultEngineId _value_, plus some legalese text;
|
|
||||||
# compute this either by manually updating the search engine in firefox and seeing what it generates,
|
|
||||||
# or, see the code for it in <repo:nix-community/home-manager>
|
|
||||||
name = "search.json.mozlz4";
|
|
||||||
src = ./.;
|
|
||||||
nativeBuildInputs = with pkgs; [ mozlz4a ];
|
|
||||||
buildPhase = ''
|
|
||||||
mozlz4a ./search.json search.json.mozlz4
|
|
||||||
'';
|
|
||||||
installPhase = ''
|
|
||||||
install -D search.json.mozlz4 "$out"/search.json.mozlz4
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in "${drv}/search.json.mozlz4";
|
|
||||||
|
|
||||||
# flush the cache to disk to avoid it taking up too much tmp.
|
# flush the cache to disk to avoid it taking up too much tmp.
|
||||||
persist.byPath = let
|
persist.byPath.".cache/mozilla".store =
|
||||||
maybePersist = if (cfg.persistData != null) then
|
if (cfg.persistData != null) then
|
||||||
cfg.persistData
|
cfg.persistData
|
||||||
else
|
else
|
||||||
"ephemeral"
|
"ephemeral"
|
||||||
;
|
;
|
||||||
in {
|
|
||||||
".cache/mozilla".store = maybePersist;
|
persist.byPath.".mozilla/firefox/default".store =
|
||||||
# storage consumes 80+ MB
|
if (cfg.persistData != null) then
|
||||||
# the other profile dirs take significantly less; < 20MB total
|
cfg.persistData
|
||||||
".mozilla/firefox/default/storage".store = maybePersist;
|
else
|
||||||
# profile files (.mozilla/firefox/default/...):
|
"ephemeral"
|
||||||
# - addons.json
|
;
|
||||||
# - regenerated on launch
|
|
||||||
# - addonStartup.json.lz4
|
|
||||||
# - regenerated on next-next launch
|
|
||||||
# - bookmarkbackups/
|
|
||||||
# - bounce-tracking-protection.sqlite
|
|
||||||
# - recreated on launch
|
|
||||||
# - cert9.db
|
|
||||||
# - regenerated on launch
|
|
||||||
# - compatibility.ini
|
|
||||||
# - regenerated on launch
|
|
||||||
# - containers.json
|
|
||||||
# - regenerated on launch
|
|
||||||
# - content-prefs.sqlite
|
|
||||||
# - recreated on launch
|
|
||||||
# - cookies.sqlite{,-wal}
|
|
||||||
# - recreated on launch
|
|
||||||
# - crashes/
|
|
||||||
# - datareporting/
|
|
||||||
# - domain_to_categories.sqlite{,-journal}
|
|
||||||
# - recreated on launch
|
|
||||||
# - enumerate_devices.txt
|
|
||||||
# - recreated on launch
|
|
||||||
# - extension-preferences.json
|
|
||||||
# - NOT recreated, but inconsequential to delete
|
|
||||||
# - extension-settings.json
|
|
||||||
# - regenerated on launch
|
|
||||||
# - extension-store/
|
|
||||||
# - extension-store-menus/
|
|
||||||
# - extensions/
|
|
||||||
# - extensions.json
|
|
||||||
# - regenerated on launch
|
|
||||||
# - failover.jsc
|
|
||||||
# - regenerated on launch
|
|
||||||
# - favicons.sqlite{,-wal}
|
|
||||||
# - regenerated on launch
|
|
||||||
# - formhistory.sqlite
|
|
||||||
# - recreated on launch
|
|
||||||
# - handlers.json
|
|
||||||
# - NOT recreated, but inconsequential to delete
|
|
||||||
# - key4.db
|
|
||||||
# - recreated on launch
|
|
||||||
# - lock -> ...
|
|
||||||
# - minidumps/
|
|
||||||
# - permissions.sqlite
|
|
||||||
# - recreated on launch
|
|
||||||
# - pkcs11.txt
|
|
||||||
# - regenerated on launch
|
|
||||||
# - places.sqlite{,-wal}
|
|
||||||
# - recreated on launch
|
|
||||||
# - prefs.js
|
|
||||||
# - recreated on launch
|
|
||||||
# - protections.sqlite
|
|
||||||
# - recreated on launch
|
|
||||||
# - search.json.mozlz4
|
|
||||||
# - recreated on launch; loses any customized search engines
|
|
||||||
# - security_state/
|
|
||||||
# - serviceworker.txt
|
|
||||||
# - NOT recreated, but inconsequential to delete
|
|
||||||
# - sessionCheckpoints.json
|
|
||||||
# - recreated on launch
|
|
||||||
# - shield-preference-experiments.json
|
|
||||||
# - NOT recreated, but inconsequential to delete
|
|
||||||
# - storage/
|
|
||||||
# - storage-sync-v2.sqlite
|
|
||||||
# - recreated on launch
|
|
||||||
# - storage.sqlite
|
|
||||||
# - times.json
|
|
||||||
# - recreated on launch
|
|
||||||
# - xulstore.json
|
|
||||||
# - recreated on launch
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 12,
|
|
||||||
"engines": [
|
|
||||||
{
|
|
||||||
"id": "search@kagi.comdefault",
|
|
||||||
"_name": "Kagi",
|
|
||||||
"_loadPath": "[addon]search@kagi.com",
|
|
||||||
"_urls": [
|
|
||||||
{
|
|
||||||
"params": [],
|
|
||||||
"rels": [],
|
|
||||||
"template": "https://kagi.com/search?q={searchTerms}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"params": [],
|
|
||||||
"rels": [],
|
|
||||||
"template": "https://kagi.com/api/autosuggest?q={searchTerms}",
|
|
||||||
"type": "application/x-suggestions+json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_orderHint": null,
|
|
||||||
"_telemetryId": null,
|
|
||||||
"_filePath": null,
|
|
||||||
"_definedAliases": [
|
|
||||||
"@kagi"
|
|
||||||
],
|
|
||||||
"_extensionID": "search@kagi.com"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metaData": {
|
|
||||||
"defaultEngineId": "search@kagi.comdefault",
|
|
||||||
"defaultEngineIdHash": "hrzTeftqb+2F9OI3GYJwG6XAMryJr8Eut/3f90YKv3k="
|
|
||||||
}
|
|
||||||
}
|
|
@@ -15,32 +15,19 @@
|
|||||||
// - number
|
// - number
|
||||||
// anything else (e.g. arrays, objects) MUST be represented as strings (use backticks for multiline/raw strings)
|
// anything else (e.g. arrays, objects) MUST be represented as strings (use backticks for multiline/raw strings)
|
||||||
|
|
||||||
// COMMON SETTINGS TO TOGGLE (at runtime, in about:config)
|
|
||||||
// defaultPref("security.ssl.require_safe_negotiation", false);
|
|
||||||
|
|
||||||
///// RESET UNWANTED ARKENFOX CHANGES
|
///// RESET UNWANTED ARKENFOX CHANGES
|
||||||
// browser.sessionstore.privacy_level: 0, 1, 2
|
// browser.sessionstore.privacy_level: 0, 1, 2
|
||||||
// 0: persist partially-filled forms to disk, across browser restarts
|
// 0: persist partially-filled forms to disk, across browser restarts
|
||||||
defaultPref("browser.sessionstore.privacy_level", 0);
|
defaultPref("browser.sessionstore.privacy_level", 0);
|
||||||
//
|
// enable 0-round-trip TLS resumption, at the expense that MITM can replay the client's first packet.
|
||||||
// `enable_0rtt_data=true`: enable 0-round-trip TLS resumption, at the expense that MITM can replay the client's first packet.
|
defaultPref("security.tls.enable_0rtt_data", true);
|
||||||
// defaultPref("security.tls.enable_0rtt_data", true);
|
|
||||||
//
|
|
||||||
// `require_safe_negotiation=false`: allow TLS 1.2 connections even to servers potentially vulnerable to CVE-2009-3555.
|
|
||||||
// this allows a MITM attacker to prefix arbitrary data to my request.
|
|
||||||
// as of 2025-07-20: 99.9% of sites support safe negotiation. 0.1% do not;
|
|
||||||
// google-chrome, epiphany, and stock firefox (not arkenfox) do not enforce safe negotiation.
|
|
||||||
// - <https://lwn.net/Articles/362234/>
|
|
||||||
// defaultPref("security.ssl.require_safe_negotiation", false);
|
|
||||||
//
|
|
||||||
// OCSP queries SSL cert revocation status on every connect; that means letting a 3rd party know every site you visit.
|
// OCSP queries SSL cert revocation status on every connect; that means letting a 3rd party know every site you visit.
|
||||||
// disable that, how in hell is that good for privacy.
|
// disable that, how in hell is that good for privacy.
|
||||||
// N.B.: i'm pretty sure this keeps CRlite enabled, which is the better implementation of cert revocation (i.e. performed locally).
|
// N.B.: i'm pretty sure this keeps CRlite enabled, which is the better implementation of cert revocation (i.e. performed locally).
|
||||||
// see: <https://blog.mozilla.org/security/2020/01/09/crlite-part-1-all-web-pki-revocations-compressed/>
|
// see: <https://blog.mozilla.org/security/2020/01/09/crlite-part-1-all-web-pki-revocations-compressed/>
|
||||||
defaultPref("security.OCSP.enabled", 0);
|
defaultPref("security.OCSP.enabled", 0);
|
||||||
//
|
// if we can't query the revocation status of a SSL cert because the issuer is offline,
|
||||||
// `security.OCSP.require=false`: if we can't query the revocation status of a SSL cert because
|
// treat it as unrevoked.
|
||||||
// the issuer is offline, treat it as unrevoked.
|
|
||||||
// see: <https://librewolf.net/docs/faq/#im-getting-sec_error_ocsp_server_error-what-can-i-do>
|
// see: <https://librewolf.net/docs/faq/#im-getting-sec_error_ocsp_server_error-what-can-i-do>
|
||||||
defaultPref("security.OCSP.require", false);
|
defaultPref("security.OCSP.require", false);
|
||||||
defaultPref("browser.display.use_system_colors", true);
|
defaultPref("browser.display.use_system_colors", true);
|
||||||
@@ -120,8 +107,6 @@ defaultPref("network.protocol-handler.external.xdg-open", true); // for firefox-
|
|||||||
defaultPref("network.protocol-handler.external.mpv", true); // for open-in-mpv extension
|
defaultPref("network.protocol-handler.external.mpv", true); // for open-in-mpv extension
|
||||||
defaultPref("network.protocol-handler.external.element", true); // for Element matrix client
|
defaultPref("network.protocol-handler.external.element", true); // for Element matrix client
|
||||||
defaultPref("network.protocol-handler.external.matrix", true); // for Nheko matrix client
|
defaultPref("network.protocol-handler.external.matrix", true); // for Nheko matrix client
|
||||||
defaultPref("network.protocol-handler.external.slack", true); // for official Slack desktop app
|
|
||||||
defaultPref("network.protocol-handler.external.zoommtg", true); // for official zoom desktop app
|
|
||||||
|
|
||||||
// statically configure bookmarks.
|
// statically configure bookmarks.
|
||||||
// notably, these bookmarks have "shortcut url" fields:
|
// notably, these bookmarks have "shortcut url" fields:
|
||||||
@@ -140,23 +125,6 @@ defaultPref("trailhead.firstrun.didSeeAboutWelcome", true);
|
|||||||
defaultPref("browser.aboutConfig.showWarning", false);
|
defaultPref("browser.aboutConfig.showWarning", false);
|
||||||
defaultPref("browser.shell.checkDefaultBrowser", false);
|
defaultPref("browser.shell.checkDefaultBrowser", false);
|
||||||
|
|
||||||
// disable extension updates
|
|
||||||
defaultPref("extensions.update.autoUpdateDefault", false);
|
|
||||||
defaultPref("extensions.update.enabled", false);
|
|
||||||
defaultPref("extensions.systemAddon.update.enabled", false);
|
|
||||||
// wipe the URIs used to check for updates, as a precaution.
|
|
||||||
defaultPref("extensions.update.url", "");
|
|
||||||
defaultPref("extensions.update.background.url", "");
|
|
||||||
defaultPref("extensions.systemAddon.update.url", "");
|
|
||||||
|
|
||||||
// also disable app-level auto-updates
|
|
||||||
defaultPref("app.update.auto", false);
|
|
||||||
|
|
||||||
// disable "safe browsing", in which my browser asks Google whether a site is malicious or not, for every site i visit (?)
|
|
||||||
defaultPref("browser.safebrowsing.blockedURIs.enabled", false);
|
|
||||||
defaultPref("browser.safebrowsing.downloads.enabled", false);
|
|
||||||
defaultPref("browser.safebrowsing.malware.enabled", false);
|
|
||||||
defaultPref("browser.safebrowsing.phishing.enabled", false);
|
|
||||||
|
|
||||||
// browser.engagement.sidebar-button.has-used
|
// browser.engagement.sidebar-button.has-used
|
||||||
// browser.migration.version = 150
|
// browser.migration.version = 150
|
||||||
|
@@ -11,9 +11,7 @@
|
|||||||
# - linking flare to iOS signal "works", but neither side can exchange messages nor contacts
|
# - linking flare to iOS signal "works", but neither side can exchange messages nor contacts
|
||||||
# in iOS i see "A message from Colin could not be delivered"
|
# in iOS i see "A message from Colin could not be delivered"
|
||||||
# - registering as primary device does not work ("you are not authorized", or some such)
|
# - registering as primary device does not work ("you are not authorized", or some such)
|
||||||
### compatibility (2025-07-05):
|
#
|
||||||
# - registering as primary device works, via JMP.chat tel.
|
|
||||||
# - no apparent way to create chats, though allegedly i can still be invited to existing chats.
|
|
||||||
### debugging:
|
### debugging:
|
||||||
# - `RUST_LOG=flare=trace flare`
|
# - `RUST_LOG=flare=trace flare`
|
||||||
#
|
#
|
||||||
@@ -68,15 +66,8 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.flare-signal = {
|
sane.programs.flare-signal = {
|
||||||
# packageUnwrapped = pkgs.flare-signal-nixified;
|
packageUnwrapped = pkgs.flare-signal-nixified;
|
||||||
packageUnwrapped = pkgs.flare-signal.overrideAttrs (upstream: {
|
# packageUnwrapped = pkgs.flare-signal;
|
||||||
postPatch = (upstream.postPatch or "") + ''
|
|
||||||
# enable the "Primary Device" button (beta).
|
|
||||||
# or setenv FLARE_ENABLE_PRIMARY_DEVICE=1
|
|
||||||
substituteInPlace data/resources/ui/setup_window.blp \
|
|
||||||
--replace 'sensitive: false;' ""
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
persist.byStore.private = [
|
persist.byStore.private = [
|
||||||
# everything: conf, state, files, all opaque
|
# everything: conf, state, files, all opaque
|
||||||
".local/share/flare"
|
".local/share/flare"
|
||||||
|
@@ -9,11 +9,27 @@
|
|||||||
let
|
let
|
||||||
# see: <repo:nixos/nixpkgs:nixos/modules/config/fonts/fontconfig.nix>
|
# see: <repo:nixos/nixpkgs:nixos/modules/config/fonts/fontconfig.nix>
|
||||||
# and: <repo:nixos/nixpkgs:pkgs/development/libraries/fontconfig/make-fonts-cache.nix>
|
# and: <repo:nixos/nixpkgs:pkgs/development/libraries/fontconfig/make-fonts-cache.nix>
|
||||||
# nixpkgs creates a fontconfig cache, which covers 99% of apps.
|
# nixpkgs creates a fontconfig cache, but only when *not* cross compiling.
|
||||||
# if build-time caching fails for some reason, then fonts are cached at runtime, in ~/.cache/fontconfig,
|
# but the alternative is that fonts are cached purely at runtime, in ~/.cache/fontconfig,
|
||||||
# and that needs to either be added to the sandbox of *every* app,
|
# and that needs to either be added to the sandbox of *every* app,
|
||||||
# or font-heavy apps are several *seconds* slower to launch.
|
# or font-heavy apps are several *seconds* slower to launch.
|
||||||
|
#
|
||||||
|
# TODO: upstream this into `make-fonts-cache.nix`?
|
||||||
|
cache = (pkgs.makeFontsCache { fontDirectories = config.fonts.packages; }).overrideAttrs (upstream: {
|
||||||
|
buildCommand = lib.replaceStrings
|
||||||
|
[ "fc-cache" ]
|
||||||
|
[ "${pkgs.stdenv.hostPlatform.emulator pkgs.buildPackages} ${lib.getExe' pkgs.fontconfig.bin "fc-cache"}" ]
|
||||||
|
upstream.buildCommand
|
||||||
|
;
|
||||||
|
});
|
||||||
|
cacheConf = pkgs.writeTextDir "etc/fonts/conf.d/01-nixos-cache-cross.conf" ''
|
||||||
|
<?xml version='1.0'?>
|
||||||
|
<!DOCTYPE fontconfig SYSTEM 'urn:fontconfig:fonts.dtd'>
|
||||||
|
<fontconfig>
|
||||||
|
<!-- Pre-generated font caches -->
|
||||||
|
<cachedir>${cache}</cachedir>
|
||||||
|
</fontconfig>
|
||||||
|
'';
|
||||||
noUserCacheConf = pkgs.runCommandNoCC "etc-fonts-fonts.conf-no-user" {} ''
|
noUserCacheConf = pkgs.runCommandNoCC "etc-fonts-fonts.conf-no-user" {} ''
|
||||||
cp ${pkgs.fontconfig.out}/etc/fonts/fonts.conf .
|
cp ${pkgs.fontconfig.out}/etc/fonts/fonts.conf .
|
||||||
substituteInPlace fonts.conf \
|
substituteInPlace fonts.conf \
|
||||||
@@ -58,13 +74,16 @@ in
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
fontconfig.confPackages = lib.mkBefore [
|
fontconfig.confPackages = lib.mkBefore ([
|
||||||
# XXX(2024-12-18): electron apps (signal-desktop, discord) duplicate the entire font cache (1-2MB) to ~/.cache/fontconfig
|
# XXX(2024-12-18): electron apps (signal-desktop, discord) duplicate the entire font cache (1-2MB) to ~/.cache/fontconfig
|
||||||
# just to update a tiny section (4KB).
|
# just to update a tiny section (4KB).
|
||||||
# patch instead to not have a user font cache. they will work, but complain "Fontconfig error: No writable cache directories".
|
# patch instead to not have a user font cache. they will work, but complain "Fontconfig error: No writable cache directories".
|
||||||
# proper fix: see if electron apps need some specific font i'm missing, or are just being dumb?
|
# proper fix: see if electron apps need some specific font i'm missing, or are just being dumb?
|
||||||
noUserCacheConf
|
noUserCacheConf
|
||||||
];
|
] ++ lib.optionals (pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform) [
|
||||||
|
# nixpkgs builds a cache file, but only for non-cross. i want it always, so add my own cache -- but ONLY for cross.
|
||||||
|
cacheConf
|
||||||
|
]);
|
||||||
|
|
||||||
#vvv enables dejavu_fonts, freefont_ttf, gyre-fonts, liberation_ttf, unifont, noto-fonts-emoji
|
#vvv enables dejavu_fonts, freefont_ttf, gyre-fonts, liberation_ttf, unifont, noto-fonts-emoji
|
||||||
enableDefaultPackages = false;
|
enableDefaultPackages = false;
|
||||||
|
@@ -11,7 +11,6 @@
|
|||||||
# - now you can send messages, and read messages in unencrypted rooms, but not read messages from encrypted rooms.
|
# - now you can send messages, and read messages in unencrypted rooms, but not read messages from encrypted rooms.
|
||||||
# to fix encrypted message receipt:
|
# to fix encrypted message receipt:
|
||||||
# - start from above (fractal closed, no ~/.local/share/fractal/*)
|
# - start from above (fractal closed, no ~/.local/share/fractal/*)
|
||||||
# - use `sane-wipe fractal` and restart fractal & verify your session, OR:
|
|
||||||
# - in ~/.local/share/keyrings/Default_keyring.keyring:
|
# - in ~/.local/share/keyrings/Default_keyring.keyring:
|
||||||
# - find the entry that says "display-name=Fractal: Matrix credentials for <mxid>"
|
# - find the entry that says "display-name=Fractal: Matrix credentials for <mxid>"
|
||||||
# - remove that entry and all associated entries (i.e. ones with same number but different :attributeN)
|
# - remove that entry and all associated entries (i.e. ones with same number but different :attributeN)
|
||||||
|
@@ -18,10 +18,6 @@ in
|
|||||||
rm "$out/bin/git-jump"
|
rm "$out/bin/git-jump"
|
||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
suggestedPrograms = [
|
|
||||||
"difftastic"
|
|
||||||
"ssh"
|
|
||||||
];
|
|
||||||
sandbox.net = "clearnet";
|
sandbox.net = "clearnet";
|
||||||
sandbox.whitelistPwd = true;
|
sandbox.whitelistPwd = true;
|
||||||
sandbox.autodetectCliPaths = "parent"; # autodetection is necessary for git-upload-pack; "parent" so that `git mv` works
|
sandbox.autodetectCliPaths = "parent"; # autodetection is necessary for git-upload-pack; "parent" so that `git mv` works
|
||||||
@@ -31,8 +27,8 @@ in
|
|||||||
"knowledge"
|
"knowledge"
|
||||||
"nixos"
|
"nixos"
|
||||||
"ref"
|
"ref"
|
||||||
|
".ssh/id_ed25519" # for ssh-auth'd remotes
|
||||||
];
|
];
|
||||||
sandbox.whitelistSsh = true;
|
|
||||||
fs.".config/git/config".symlink.text = mkCfg {
|
fs.".config/git/config".symlink.text = mkCfg {
|
||||||
# top-level options documented:
|
# top-level options documented:
|
||||||
# - <https://git-scm.com/docs/git-config#_variables>
|
# - <https://git-scm.com/docs/git-config#_variables>
|
||||||
@@ -48,7 +44,6 @@ in
|
|||||||
alias.d = "difftool";
|
alias.d = "difftool";
|
||||||
alias.dif = "diff"; # common typo
|
alias.dif = "diff"; # common typo
|
||||||
alias.difsum = "diff --compact-summary"; #< show only the list of files which changed, not contents
|
alias.difsum = "diff --compact-summary"; #< show only the list of files which changed, not contents
|
||||||
alias.pul = "pull"; # common typo
|
|
||||||
alias.rb = "rebase";
|
alias.rb = "rebase";
|
||||||
alias.reset-head = "reset --hard HEAD";
|
alias.reset-head = "reset --hard HEAD";
|
||||||
alias.st = "status";
|
alias.st = "status";
|
||||||
@@ -59,7 +54,7 @@ in
|
|||||||
# - <https://difftastic.wilfred.me.uk/git.html>
|
# - <https://difftastic.wilfred.me.uk/git.html>
|
||||||
diff.tool = "difftastic";
|
diff.tool = "difftastic";
|
||||||
difftool.prompt = false;
|
difftool.prompt = false;
|
||||||
"difftool \"difftastic\"".cmd = ''difft "$LOCAL" "$REMOTE"'';
|
"difftool \"difftastic\"".cmd = ''${lib.getExe pkgs.difftastic} "$LOCAL" "$REMOTE"'';
|
||||||
# now run `git difftool` to use difftastic git
|
# now run `git difftool` to use difftastic git
|
||||||
|
|
||||||
# render dates as YYYY-MM-DD HH:MM:SS +TZ
|
# render dates as YYYY-MM-DD HH:MM:SS +TZ
|
||||||
|
@@ -1,19 +1,6 @@
|
|||||||
{ pkgs, ... }: {
|
{ pkgs, ... }: {
|
||||||
sane.programs.gnome-contacts = {
|
sane.programs.gnome-contacts = {
|
||||||
packageUnwrapped = (pkgs.gnome-contacts.override {
|
packageUnwrapped = pkgs.gnome-contacts.overrideAttrs (upstream: {
|
||||||
evolution-data-server-gtk4 = pkgs.evolution-data-server-gtk4.override {
|
|
||||||
# drop webkitgtk_6_0 dependency.
|
|
||||||
# it's normally cached, but if modifying low-level deps (e.g. pipewire) it's nice to not have to rebuild it,
|
|
||||||
# especially since `gnome-contacts` is part of `moby-min`.
|
|
||||||
withGtk4 = false;
|
|
||||||
};
|
|
||||||
folks = pkgs.folks.override {
|
|
||||||
evolution-data-server-gtk4 = pkgs.evolution-data-server-gtk4.override {
|
|
||||||
# drop webkitgtk_6_0 dependency.
|
|
||||||
withGtk4 = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}).overrideAttrs (upstream: {
|
|
||||||
# patches = (upstream.patches or []) ++ [
|
# patches = (upstream.patches or []) ++ [
|
||||||
# # optional danctnix patch to allow clicking on the telephone to open the calls app,
|
# # optional danctnix patch to allow clicking on the telephone to open the calls app,
|
||||||
# # however it's frequently in need of rebasing
|
# # however it's frequently in need of rebasing
|
||||||
|
@@ -19,26 +19,37 @@
|
|||||||
".local/share/keyrings"
|
".local/share/keyrings"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
fs.".local/share/keyrings/default" = {
|
||||||
|
file.text = "Default_keyring.keyring"; #< no trailing newline
|
||||||
|
# wantedBy = [ config.sane.fs."${config.sane.persist.stores.private.origin}".unit ];
|
||||||
|
# wantedBeforeBy = [ #< don't create this as part of `multi-user.target`
|
||||||
|
# "gnome-keyring.service" # TODO: sane.programs should declare this dependency for us
|
||||||
|
# ];
|
||||||
|
};
|
||||||
|
# N.B.: certain keyring names have special significance
|
||||||
|
# `login.keyring` is forcibly encrypted to the user's password, so that pam gnome-keyring can unlock it on login.
|
||||||
|
# - it does this re-encryption forcibly, any time it wants to write to the keyring.
|
||||||
|
fs.".local/share/keyrings/Default_keyring.keyring" = {
|
||||||
|
file.text = ''
|
||||||
|
[keyring]
|
||||||
|
display-name=Default keyring
|
||||||
|
lock-on-idle=false
|
||||||
|
lock-after=false
|
||||||
|
'';
|
||||||
|
# wantedBy = [ config.sane.fs."${config.sane.persist.stores.private.origin}".unit ];
|
||||||
|
# wantedBeforeBy = [ #< don't create this as part of `multi-user.target`
|
||||||
|
# "gnome-keyring.service"
|
||||||
|
# ];
|
||||||
|
};
|
||||||
|
|
||||||
services.gnome-keyring = {
|
services.gnome-keyring = {
|
||||||
description = "gnome-keyring-daemon: secret provider";
|
description = "gnome-keyring-daemon: secret provider";
|
||||||
partOf = [ "graphical-session" ];
|
partOf = [ "graphical-session" ];
|
||||||
command = let
|
command = let
|
||||||
default_keyring = pkgs.writeText "Default_keyring.keyring" ''
|
|
||||||
[keyring]
|
|
||||||
display-name=Default keyring
|
|
||||||
lock-on-idle=false
|
|
||||||
lock-after=false
|
|
||||||
'';
|
|
||||||
gkr-start = pkgs.writeShellScriptBin "gnome-keyring-daemon-start" ''
|
gkr-start = pkgs.writeShellScriptBin "gnome-keyring-daemon-start" ''
|
||||||
set -eu
|
set -eu
|
||||||
# XXX(2024-09-05): this service races with the creation of the keyrings directory, so wait for it to appear
|
# XXX(2024-09-05): this service races with the creation of the keyrings directory, so wait for it to appear
|
||||||
test -e ~/.local/share/keyrings
|
test -e ~/.local/share/keyrings
|
||||||
# N.B.: certain keyring names have special significance
|
|
||||||
# `login.keyring` is forcibly encrypted to the user's password, so that pam gnome-keyring can unlock it on login.
|
|
||||||
# - it does this re-encryption forcibly, any time it wants to write to the keyring.
|
|
||||||
echo -n "Default_keyring" > ~/.local/share/keyrings/default
|
|
||||||
cp ${default_keyring} --update=none ~/.local/share/keyrings/Default_keyring.keyring
|
|
||||||
|
|
||||||
mkdir -m 0700 -p $XDG_RUNTIME_DIR/keyring
|
mkdir -m 0700 -p $XDG_RUNTIME_DIR/keyring
|
||||||
exec gnome-keyring-daemon --start --foreground --components=secrets
|
exec gnome-keyring-daemon --start --foreground --components=secrets
|
||||||
'';
|
'';
|
||||||
|
@@ -1,13 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
{
|
|
||||||
sane.programs.gnome-sound-recorder = {
|
|
||||||
sandbox.wrapperType = "inplace"; #< the binary lives in `share/org.gnome.SoundRecorder`, for some reason.
|
|
||||||
sandbox.whitelistAudio = true;
|
|
||||||
sandbox.whitelistWayland = true;
|
|
||||||
sandbox.extraHomePaths = [
|
|
||||||
".local/share/org.gnome.SoundRecorder" #< this is where it saves recordings
|
|
||||||
# additionally, gnome-sound-recorder has the option to "export" audio out of this directory:
|
|
||||||
# opens a file chooser for where to save the file (maybe via the portal??)
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user