Compare commits

..

75 commits

Author SHA1 Message Date
74e2bde66f
secrets: Rekey for new odyssey ssh key 2026-01-02 14:49:34 -06:00
bdedf7a69e
config (zed): Switch Julia syntax formatting to cli 2026-01-02 11:56:29 -06:00
e823b4804c
shell: Remove JuliaFormatter project 2026-01-02 11:56:29 -06:00
55ea13d49b
pkgs (common): Add JuliaFormatter.jl cli 2026-01-02 11:56:28 -06:00
9628c7b433
pkgs (common): Add Runic.jl cli 2026-01-02 11:56:28 -06:00
05ad4dc62f
feat (linux-desktop): Convert Plasma settings into plasma-manager 2026-01-02 11:56:28 -06:00
8336b25291
fix (zed): Make LaTeX preview open in background
The order of the arguments matters to make Skip.app open in the
background for LaTeX documents, so fix the order.
2025-12-26 20:47:15 -06:00
7d8843c399
flatpak (fedora): Remove Anki 2025-12-21 16:21:10 -06:00
8c313aae37
dnf (fedora): Remove musescore 2025-12-21 16:20:58 -06:00
7e65bc03b3
brew (corianne): Remove Anki 2025-12-21 16:20:07 -06:00
117cf07697
brew (corianne): Remove Musescore 2025-12-21 16:19:52 -06:00
01cf173573
brew (corianne): Install Vienna 2025-12-21 16:19:35 -06:00
b6a67cfa98
shell: Add repo_init function 2025-12-21 16:18:00 -06:00
8e283c2288
config (zed): Enable Typst previews 2025-12-21 16:16:57 -06:00
69205e695f
shell: Add git clone shortcut function 2025-12-17 09:50:44 -06:00
20465843e4
config (git): Add ssh rewrites 2025-12-17 09:50:14 -06:00
c7f76d5c1c
config (zed): Add new git_hosting_providers key 2025-12-17 09:46:29 -06:00
d40b20d8cc
config (zed): Switch default model to Claude Sonnet 4.5 2025-12-17 09:44:14 -06:00
9fcc736104
config (zed): Switch to external Nix formatter 2025-12-17 09:40:41 -06:00
6fbf0f2b7d
fix (freshrss): OIDC config mounting
After much troubleshooting, I figured out that FreshRSS does not actually support OIDC with the use of the environment variables for configuration. Instead, the config files actually have to be set with the web wizard and persisted with a volume mount. Do that.
2025-12-09 08:47:04 -06:00
1fc358b482
fix (freshrss): Networking stack fixes 2025-12-08 20:40:27 -06:00
3f35901fd3
fix (freshrss): Uncomment required variables 2025-12-08 17:29:00 -06:00
1eebebdeb0
fix (freshrss): Bind port 2025-12-08 17:25:48 -06:00
335fed99f3
fix (freshrss): Set OIDC variables 2025-12-08 17:22:33 -06:00
7145bf01ed
service (freshrss): Add freshrss service 2025-12-08 16:44:12 -06:00
a0175f565b
secrets! (pihole): Remove pihole secrets 2025-12-08 08:11:43 -06:00
0571d801ed
services (bosephus): Remove pihole service 2025-12-04 09:07:16 -06:00
9108361964
pkgs (desktop): add nixos-rebuild package 2025-12-04 09:00:54 -06:00
ac837750c9
nix-builder (corianne): Add rosetta builder 2025-12-04 09:00:37 -06:00
24d7b7d533
programs (zed): Add build+preview on demand support for LaTeX 2025-12-04 08:59:53 -06:00
c49474d8ce
flake: Upgrade nixpkgs to nixos-25.11 family
This commit upgrades nixpkgs to nixos-25.11, and all other management
systems (home-manager, nix-darwin, etc.) to the equivalent tag, and also
upgrades any syntax within the modules to follow new syntax.

1. Upgrades nixpkgs to nixos-25.11
2. Upgrades nixpkgs-darwin to nixpkgs-25.11-darwin
3. Upgrades home-manger to release-25.11
4. Upgrades nix-darwin to 25.11
5. Implements conditional to use nixpkgs on Linux and nixpkgs-darwin on
   Darwin
6. Replace micromamba with mamba-cpp and set alias, see
   <https://github.com/NixOS/nixpkgs/issues/456288#issuecomment-3584844923>
7. Replace asitop with its new name: macpm
8. Remove ollama package and launchd service. ollama was removed from
   Linux in 275270cef7, but remained in Darwin. The build process
   technically did not fail, but it did extend build time and is unused,
   so it was removed.
9. Switch git program module to use new syntax
10. Switch to NixOS-provided Crowdsec module
11. Switch logind lidSwitch settings to use new syntax
12. Switch sabma module to use new syntax
2025-12-02 22:25:55 -06:00
086cae0a56
fix (borgmatic): Add psql command 2025-12-01 15:14:01 -06:00
1301fd94b3
fix (borgmatic): Add postgresql config 2025-12-01 15:09:48 -06:00
8b5fa1dfe9
service (authentik): Add Borgmatic config 2025-12-01 15:01:45 -06:00
a3a8ea9a34
services (linux): Remove nixos-update service 2025-12-01 14:03:20 -06:00
6a1cc7877c
users (mcentire): Add millironx to adm group 2025-12-01 13:52:06 -06:00
b2477b9f24
fix (authentik): Too many fixes to list
Bad on me, but I have spent way too long making edits that are all
required on mcentire to get Authentik semi-working. There are lots of
notes in here on reasoning of why stuff is the way it is. Backup still
needs to be configured, and potentially Crowdsec.
2025-12-01 12:03:20 -06:00
8d96ef7684
fix (podman-secrets): Use user systemd unit
User systemd units cannot wait for system units. Fix race condition bugs
in user Quadlet services by using a user service that the Quadlet
services can use as a `After=` or `Requires=` directive.
2025-12-01 12:01:45 -06:00
fa6b537a3c
docs: Add mcentire to README 2025-12-01 09:17:07 -06:00
e9b1841f7b
docs: Remove harmony reference 2025-12-01 09:07:15 -06:00
4e84e57e3b
docs: Convert README table to pipe format 2025-12-01 09:06:23 -06:00
70f98a6200
meta: Add README 2025-12-01 08:57:54 -06:00
ce174b61fd
meta: Add gitignore 2025-12-01 08:37:00 -06:00
8e5734469c
fix (podman-secrets): setuid path
NixOS does some weird stuff with setting security bits in wrappers,
rather than in packages themselves, and this was breaking podman. Add
the wrappers directory to the PATH of the secrets service.
2025-11-28 18:10:19 -06:00
49a2f7cd35
fix (podman-secrets): Create home directory for authentik user 2025-11-28 16:14:58 -06:00
1f322921bd
fix (podman-secrets): Use explicit pkg references in script 2025-11-28 16:02:49 -06:00
72e4f04b31
fix (podman-secrets): Use explicit Julia call 2025-11-28 15:51:53 -06:00
2b06848632
service (mcentire): Add authentik service 2025-11-28 15:41:59 -06:00
3fd32ffa45
feat: Add podman-secrets module 2025-11-28 10:41:45 -06:00
1730970935
homes (mcentire): Add home-manager config for mcentire 2025-11-28 10:41:45 -06:00
f2069cacb9
secrets: Add mcentire-millironx ssh key 2025-11-28 10:41:45 -06:00
b6b514278e
defaults (Dock/Taskbar): Make taskbar and dock have the same Apps
Except for Steam, because Steam is weird and will spawn extra windows
that don't play well with Taskbar.
2025-11-24 11:02:47 -06:00
4a9eed6ecb
brew (corianne): Remove LogiOptions app 2025-11-24 10:34:08 -06:00
8d188dea43
addons (firefox): Remove web archives addon 2025-11-19 09:28:05 -06:00
ac6c552339
pkgs (firefoxpwa): Remove Firefox PWAs 2025-11-19 09:28:04 -06:00
f9672236f5
addons (firefox): Remove Floccus addon 2025-11-19 09:28:04 -06:00
c8a1aa9692
addons (firefox): Install plasma-integration only on Linux 2025-11-19 09:28:04 -06:00
4a8ddb0784
pkg (desktop): Remove ghostty 2025-11-19 09:05:53 -06:00
ac57a31f06
lint (borgmatic): Move retention to global scope 2025-11-16 19:39:29 -06:00
9fc8c9a890
services (borgmatic): Add borgmatic service 2025-11-16 19:33:47 -06:00
65ee23cc36
activation (common): remove git hash recorder
I used to try to control Ansible's bootstrapping of home-manager by
recording the current git hash of the home-manager repo, but I haven't
allowed ansible to touch home-manager after initial setup for a while
now, so remove the hash code.
2025-11-16 18:27:25 -06:00
d080b9d480
lint (ansible): Fix template reference/location 2025-11-16 18:25:13 -06:00
160c8e8273
lint (ansible): Fix line length 2025-11-16 18:24:52 -06:00
e094a8ac6a
config (harmony): Remove Harmony/Asahi configs 2025-11-16 18:24:23 -06:00
be4ce6fe1f
pkgs (common): Install agenix cli via overlay 2025-11-16 18:07:44 -06:00
71a086d07e
dock (corianne): Remove unavailable Chromium PWAs 2025-11-13 14:47:31 -06:00
4d56344446
secrets: Rekey secrets for secret purposes 2025-11-13 14:47:26 -06:00
3b9b7f684d
Revert "fix (crowdsec): hub permissions issues"
This reverts commit f982232c99.
2025-11-11 21:59:28 -06:00
2c4e709704
debug (crowdsec): Add verbose logging to Crowdsec collection install
step
2025-11-11 21:42:25 -06:00
f982232c99
fix (crowdsec): hub permissions issues 2025-11-11 21:39:34 -06:00
1fba403731
fix (crowdsec): Add sleep to avoid rate limits 2025-11-10 22:17:28 -06:00
b2928eb81f
fix (crowdsec): Proper URI syntax for API 2025-11-10 21:47:29 -06:00
4ca995f75a
fix (crowdsec): Add hub update steps 2025-11-10 21:41:27 -06:00
2ea0b68221
fix (crowdsec): API url 2025-11-10 16:00:16 -06:00
0fa3e1ec0e
fix (crowdsec): Scope of Journalctl access 2025-11-10 15:58:08 -06:00
54 changed files with 1530 additions and 727 deletions

74
.gitignore vendored Normal file
View file

@ -0,0 +1,74 @@
### Linux gitignore ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# Metadata left by Dolphin file manager, which comes with KDE Plasma
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
# Log files created by default by the nohup command
nohup.out
### MacOS gitignore ###
# General
.DS_Store
__MACOSX/
.AppleDouble
.LSOverride
Icon[]
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Nix gitignore ###
# Ignore build outputs from performing a nix-build or `nix build` command
result
result-*
# Ignore automatically generated direnv output
.direnv
### Vim gitignore ###
# Swap
[._]*.s[a-v][a-z]
# comment out the next line if you don't need vector files
!*.svg
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# Session
Session.vim
Sessionx.vim
# Temporary
.netrwhist
*~
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~

157
README.md Normal file
View file

@ -0,0 +1,157 @@
# nix-dotfiles
System and home configurations for my machines.
| Machine | Role | OS | Arch | System config tool | Home config tool |
| -------- | --------------- | ------ | ------- | --------------------------- | ---------------- |
| anderson | server | linux | x86_64 | dpkg/Docker (not this repo) | home-manager |
| bosephus | server | linux | x86_64 | NixOS | home-manager |
| mcentire | server | linux | x86_64 | NixOS | home-manager |
| corianne | MacBook | darwin | aarch64 | nix-darwin | home-manager |
| odyssey | workstation | linux | x86_64 | Ansible | home-manager |
## Quickstart
### Home dotfiles
> ![WARNING]
> Fedora systems will set this up automagically via Ansible. Follow the
[Fedora quickstart] instructions.
Ensure Nix is installed, with the `nix` command and flakes enabled. I try to use
the [Determinate Nix installer] (with upstream Nix) to install Nix with these
options turned on by default.
```bash
curl -fsSL https://install.determinate.systems/nix | sh -s -- install
```
Once Nix is installed, clone the repository to `~/.config/home-manager` and
initiate home-manager.
```bash
git clone https://code.millironx.com/millironx/nix-dotfiles.git ~/.config/home-manager
nix run home-manager -- switch --flake ~/.config/home-manager#$USER@$(hostname -s)
```
In the case that the host has not been assigned a configuration within this repo
yet, pick a hostname with the same system OS, arch, and role as the target
system to get temporary dotfiles up and running.
```bash
nix run home-manager -- switch --flake ~/.config/home-manager#millironx@anderson
```
Once an SSH (with or without GPG) key has been setup and added to the authorized
keys of the git server, switch the upstream to track an authorized (i.e.
read/write) version of the repo.
```bash
cd ~/.config/home-manager
git remote set-url origin git@code.millironx.com:millironx/nix-dotfiles.git
cd -
```
### NixOS
Switching to a flake-based config requires running as root. All of the following
commands are assumed to be running as root.
Ensure that the `nix` command and flakes are enabled.
```bash
sed -i '/^}/i nix.settings.experimental-features = [ "nix-command" "flakes" ];' /etc/nixos/configuration.nix
nixos-rebuild switch
```
> ![NOTE]
> To allow secret decryption in the system, the *machine*-specific SSH key must
> be added to the publicKeys attribute of all applicable secrets, and the
> `hardware-configuration.nix` file must be added to git. Copying arbitrary
> strings like SSH keys or disk UUIDs between systems can be painful, so it might
> be worth setting up the [home dotfiles] immediately after enabling flakes,
> then running these steps on the same machine to avoid typos. Alternatively, I
> might someday be smart enough to create an installer CD that automagically
> sets this up for me.
Get the machine-specific public SSH key.
```bash
cat /etc/ssh/ssh_host_ed25519_key.pub
```
On a separate machine, add the machine's SSH key to `./secrets.nix` and assign
it to any secrets it would need.
```nix
let
bosephus-host =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIxTfeg+GZsfmG8TuEV1xW1gXknAIKzZ3UjZ3guRY+EW root@nixos";
bosephus-millironx =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKaDPqRJHoqgY2pseh/mnhjaGWXprHk2s5I52LhHpHcF millironx@bosephus";
odyssey-millironx =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN9Aj7BtQp1Roa0tgopDrUo7g2am5WJ43lO1d1fDUz45 millironx@odyssey";
system-administrators = [
bosephus-millironx
odyssey-millironx
];
in {
"secrets/network-information.age".publicKeys = system-administrators
++ [ bosephus-host ];
}
```
Rekey the secrets, and push the updated secrets to the upstream repo.
```bash
nix run github:ryantm/agenix -- --rekey
git add secrets.nix secrets/*
git commit -m "added $NEW_HOST to secrets"
git push
```
Copy the target machine's `hardware-configuration.nix` file to this repo's
`./systems/linux/hardware-configuration/$NEW_HOST.nix`, and be sure to update
the configuration to import its own `hardware-configuration`.
```bash
cp /etc/nixos/hardware-configuration.nix ./systems/linux/hardware-configuration/$NEW_HOST.nix
```
```nix
{ config, pkgs, ... }: {
imports = [
./hardware-configuration/bosephus.nix
];
}
```
Commit and push the hardware configuration to the upstream repo.
```bash
git add systems/linux/*
git commit -m "added $NEW_HOST hardware configuration"
git push
```
Now switch to the flake by pulling and switching in one step.
```bash
nixos-rebuild switch --flake git+https://code.millironx.com/millironx/nix-dotfiles#$(hostname -s)
```
### Fedora
Fedora systems are managed using Ansible.
TODO
## Home settings
TODO
[determinate nix installer]: https://github.com/DeterminateSystems/nix-installer
[fedora quickstart]: #fedora
[home dotfiles]: #home-dotfiles

32
bin/secret-translator.jl Normal file
View file

@ -0,0 +1,32 @@
#!/usr/bin/env julia
using TOML: TOML
@show ENV["PATH"]
function remove_podman_secrets()
run(`podman secret rm --all`)
return nothing
end #function
function create_podman_secret(name, secret)
run(
addenv(
`podman secret create --env=true --replace $name SECRET`,
Dict("SECRET" => secret),
),
)
return nothing
end #function
function parse_toml_secrets(file)
foreach(f -> create_podman_secret(f[1], f[2]), TOML.parsefile(file))
return nothing
end #function
function main()
remove_podman_secrets()
foreach(parse_toml_secrets, ARGS)
return 0
end #function
main()

View file

@ -1,24 +0,0 @@
MenuBar=Disabled
[DetailsMode]
PreviewSize=16
[General]
BrowseThroughArchives=true
EditableUrl=true
GlobalViewProps=false
ShowFullPath=true
ShowStatusBar=FullWidth
ShowZoomSlider=true
Version=202
[KFileDialog Settings]
Places Icons Auto-resize=false
Places Icons Static Size=22
[MainWindow]
MenuBar=Disabled
[PreviewSettings]
Plugins=audiothumbnail,avif,blenderthumbnail,comicbookthumbnail,cursorthumbnail,djvuthumbnail,ebookthumbnail,exrthumbnail,directorythumbnail,fontthumbnail,imagethumbnail,jpegthumbnail,jxl,kraorathumbnail,windowsexethumbnail,windowsimagethumbnail,mobithumbnail,opendocumentthumbnail,gsthumbnail,rawthumbnail,svgthumbnail,gdk-pixbuf-thumbnailer,ffmpegthumbs,gsf-office

View file

@ -1,9 +0,0 @@
[Desktop Entry]
DefaultProfile=My Default.profile
[MainWindow]
StatusBar=Disabled
ToolBarsMovable=Disabled
[UiSettings]
ColorScheme=Default

181
flake.lock generated
View file

@ -14,11 +14,11 @@
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1754433428, "lastModified": 1762618334,
"narHash": "sha256-NA/FT2hVhKDftbHSwVnoRTFhes62+7dxZbxj5Gxvghs=", "narHash": "sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L+VSybPfiIgzU8lbQ=",
"owner": "ryantm", "owner": "ryantm",
"repo": "agenix", "repo": "agenix",
"rev": "9edb1787864c4f59ae5074ad498b6272b3ec308d", "rev": "fcdea223397448d35d9b31f798479227e80183f6",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -27,27 +27,6 @@
"type": "github" "type": "github"
} }
}, },
"crowdsec": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1752497357,
"narHash": "sha256-9epXn1+T6U4Kfyw8B9zMzbERxDB3VfaPXhVebtai6CE=",
"ref": "refs/heads/main",
"rev": "84db7dcea77f7f477d79e69e35fb0bb560232667",
"revCount": 42,
"type": "git",
"url": "https://codeberg.org/kampka/nix-flake-crowdsec.git"
},
"original": {
"type": "git",
"url": "https://codeberg.org/kampka/nix-flake-crowdsec.git"
}
},
"flake-parts": { "flake-parts": {
"inputs": { "inputs": {
"nixpkgs-lib": [ "nixpkgs-lib": [
@ -69,23 +48,6 @@
"type": "github" "type": "github"
} }
}, },
"flake-utils": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"id": "flake-utils",
"type": "indirect"
}
},
"home-manager": { "home-manager": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@ -93,16 +55,16 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1756679287, "lastModified": 1764613336,
"narHash": "sha256-Xd1vOeY9ccDf5VtVK12yM0FS6qqvfUop8UQlxEB+gTQ=", "narHash": "sha256-L979az28t/+SXvYw9qhOno5HLlDwkZOpz6LzCLnjmRM=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "07fc025fe10487dd80f2ec694f1cd790e752d0e8", "rev": "f3902b5d8767985680875ad86d028371100faeb3",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nix-community", "owner": "nix-community",
"ref": "release-25.05", "ref": "release-25.11",
"repo": "home-manager", "repo": "home-manager",
"type": "github" "type": "github"
} }
@ -114,59 +76,117 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1757432263, "lastModified": 1764161084,
"narHash": "sha256-qHn+/0+IOz5cG68BZUwL9BV3EO/e9eNKCjH3+N7wMdI=", "narHash": "sha256-HN84sByg9FhJnojkGGDSrcjcbeioFWoNXfuyYfJ1kBE=",
"owner": "LnL7", "owner": "LnL7",
"repo": "nix-darwin", "repo": "nix-darwin",
"rev": "1fef4404de4d1596aa5ab2bd68078370e1b9dcdb", "rev": "e95de00a471d07435e0527ff4db092c84998698e",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "LnL7", "owner": "LnL7",
"ref": "nix-darwin-25.05", "ref": "nix-darwin-25.11",
"repo": "nix-darwin", "repo": "nix-darwin",
"type": "github" "type": "github"
} }
}, },
"nix-rosetta-builder": {
"inputs": {
"nixos-generators": "nixos-generators",
"nixpkgs": [
"nixpkgs-darwin"
]
},
"locked": {
"lastModified": 1756177999,
"narHash": "sha256-aSbB7/jrt7ujiJ55f2uGhOo+usGxVSkqbAMVgg2jDls=",
"owner": "cpick",
"repo": "nix-rosetta-builder",
"rev": "ebb7162a975074fb570a2c3ac02bc543ff2e9df4",
"type": "github"
},
"original": {
"owner": "cpick",
"repo": "nix-rosetta-builder",
"type": "github"
}
},
"nixlib": {
"locked": {
"lastModified": 1736643958,
"narHash": "sha256-tmpqTSWVRJVhpvfSN9KXBvKEXplrwKnSZNAoNPf/S/s=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "1418bc28a52126761c02dd3d89b2d8ca0f521181",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"nixos-generators": {
"inputs": {
"nixlib": "nixlib",
"nixpkgs": [
"nix-rosetta-builder",
"nixpkgs"
]
},
"locked": {
"lastModified": 1737057290,
"narHash": "sha256-3Pe0yKlCc7EOeq1X/aJVDH0CtNL+tIBm49vpepwL1MQ=",
"owner": "nix-community",
"repo": "nixos-generators",
"rev": "d002ce9b6e7eb467cd1c6bb9aef9c35d191b5453",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixos-generators",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1757545623, "lastModified": 1764522689,
"narHash": "sha256-mCxPABZ6jRjUQx3bPP4vjA68ETbPLNz9V2pk9tO7pRQ=", "narHash": "sha256-SqUuBFjhl/kpDiVaKLQBoD8TLD+/cTUzzgVFoaHrkqY=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "8cd5ce828d5d1d16feff37340171a98fc3bf6526", "rev": "8bb5646e0bed5dbd3ab08c7a7cc15b75ab4e1d0f",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nixos", "owner": "nixos",
"ref": "nixos-25.05", "ref": "nixos-25.11",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
}, },
"nixpkgs-darwin": { "nixpkgs-darwin": {
"locked": { "locked": {
"lastModified": 1757590060, "lastModified": 1764572236,
"narHash": "sha256-EWwwdKLMZALkgHFyKW7rmyhxECO74+N+ZO5xTDnY/5c=", "narHash": "sha256-hLp6T/vKdrBQolpbN3EhJOKTXZYxJZPzpnoZz+fEGlE=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "0ef228213045d2cdb5a169a95d63ded38670b293", "rev": "b0924ea1889b366de6bb0018a9db70b2c43a15f8",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nixos", "owner": "nixos",
"ref": "nixpkgs-25.05-darwin", "ref": "nixpkgs-25.11-darwin",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
}, },
"nixpkgs-unstable": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1757034884, "lastModified": 1764642553,
"narHash": "sha256-PgLSZDBEWUHpfTRfFyklmiiLBE1i1aGCtz4eRA3POao=", "narHash": "sha256-mvbFFzVBhVK1FjyPHZGMAKpNiqkr7k++xIwy+p/NQvA=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "ca77296380960cd497a765102eeb1356eb80fed0", "rev": "f720de59066162ee879adcc8c79e15c51fe6bfb4",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -184,11 +204,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1757647720, "lastModified": 1764683664,
"narHash": "sha256-qf/utP3d1qBDl5R4yWUCt7E7CHTkw2NY8BEsS7lJ0dc=", "narHash": "sha256-Mr5HKf/bjAJ8H7/H0qJSk2BEV/OILkDIFKrGK0dUVUk=",
"owner": "nix-community", "owner": "nix-community",
"repo": "NUR", "repo": "NUR",
"rev": "ef767aa25f9f917fe25d3848051f0e54ae42349f", "rev": "b8b40e258cf4c959b06b7322648c87674633629b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -207,11 +227,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1756632588, "lastModified": 1763909441,
"narHash": "sha256-ydam6eggXf3ZwRutyCABwSbMAlX+5lW6w1SVZQ+kfSo=", "narHash": "sha256-56LwV51TX/FhgX+5LCG6akQ5KrOWuKgcJa+eUsRMxsc=",
"owner": "nix-community", "owner": "nix-community",
"repo": "plasma-manager", "repo": "plasma-manager",
"rev": "d47428e5390d6a5a8f764808a4db15929347cd77", "rev": "b24ed4b272256dfc1cc2291f89a9821d5f9e14b4",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -222,11 +242,11 @@
}, },
"quadlet-nix": { "quadlet-nix": {
"locked": { "locked": {
"lastModified": 1754008153, "lastModified": 1763141753,
"narHash": "sha256-MYT1mDtSkiVg343agxgBFsnuNU3xS8vRy399JXX1Vw0=", "narHash": "sha256-XAHkOkLEWbRQZ6t/SowwOukrUfIneNQOC/UEQlTaPBU=",
"owner": "SEIAROTg", "owner": "SEIAROTg",
"repo": "quadlet-nix", "repo": "quadlet-nix",
"rev": "1b2d27d460d8c7e4da5ba44ede463b427160b5c4", "rev": "211b5c626cf9ea91403b510e2ac5ca03a7194566",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -238,9 +258,9 @@
"root": { "root": {
"inputs": { "inputs": {
"agenix": "agenix", "agenix": "agenix",
"crowdsec": "crowdsec",
"home-manager": "home-manager", "home-manager": "home-manager",
"nix-darwin": "nix-darwin", "nix-darwin": "nix-darwin",
"nix-rosetta-builder": "nix-rosetta-builder",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"nixpkgs-darwin": "nixpkgs-darwin", "nixpkgs-darwin": "nixpkgs-darwin",
"nixpkgs-unstable": "nixpkgs-unstable", "nixpkgs-unstable": "nixpkgs-unstable",
@ -258,11 +278,11 @@
}, },
"locked": { "locked": {
"dir": "pkgs/firefox-addons", "dir": "pkgs/firefox-addons",
"lastModified": 1757591399, "lastModified": 1764648280,
"narHash": "sha256-OlvNzfsqDok0y5PDY+2dK5T53GsxAdm1YGdYHjxAiHM=", "narHash": "sha256-xniOnxIx/qhm+maO4mb9BZ7FytcUhNeTm1Y/QBjNf8o=",
"owner": "rycee", "owner": "rycee",
"repo": "nur-expressions", "repo": "nur-expressions",
"rev": "b7d4f61ce9db44ba82859e15f6e1c175959948e3", "rev": "119826bd51ad1a8012e0585f3a073571a35a812e",
"type": "gitlab" "type": "gitlab"
}, },
"original": { "original": {
@ -286,21 +306,6 @@
"repo": "default", "repo": "default",
"type": "github" "type": "github"
} }
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

View file

@ -3,8 +3,8 @@
inputs = { inputs = {
# Specify the source of Home Manager and Nixpkgs. # Specify the source of Home Manager and Nixpkgs.
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05"; nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
nixpkgs-darwin.url = "github:nixos/nixpkgs/nixpkgs-25.05-darwin"; nixpkgs-darwin.url = "github:nixos/nixpkgs/nixpkgs-25.11-darwin";
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixpkgs-unstable"; nixpkgs-unstable.url = "github:nixos/nixpkgs/nixpkgs-unstable";
# Inputs for both darwin and linux systems # Inputs for both darwin and linux systems
@ -17,7 +17,7 @@
}; };
}; };
home-manager = { home-manager = {
url = "github:nix-community/home-manager/release-25.05"; url = "github:nix-community/home-manager/release-25.11";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
nur = { nur = {
@ -30,10 +30,6 @@
}; };
# Linux-specific inputs # Linux-specific inputs
crowdsec = {
url = "git+https://codeberg.org/kampka/nix-flake-crowdsec.git";
inputs.nixpkgs.follows = "nixpkgs";
};
plasma-manager = { plasma-manager = {
url = "github:nix-community/plasma-manager"; url = "github:nix-community/plasma-manager";
inputs = { inputs = {
@ -45,23 +41,28 @@
# Darwin-specific inputs # Darwin-specific inputs
nix-darwin = { nix-darwin = {
url = "github:LnL7/nix-darwin/nix-darwin-25.05"; url = "github:LnL7/nix-darwin/nix-darwin-25.11";
inputs.nixpkgs.follows = "nixpkgs-darwin";
};
nix-rosetta-builder = {
url = "github:cpick/nix-rosetta-builder";
inputs.nixpkgs.follows = "nixpkgs-darwin"; inputs.nixpkgs.follows = "nixpkgs-darwin";
}; };
}; };
outputs = { self, nix-darwin, nixpkgs, nixpkgs-darwin, nixpkgs-unstable outputs = { self, nix-darwin, nixpkgs, nixpkgs-darwin, nixpkgs-unstable
, home-manager, agenix, rycee-nurpkgs, nur, crowdsec, plasma-manager , home-manager, agenix, rycee-nurpkgs, nur, plasma-manager, quadlet-nix
, quadlet-nix, ... }: , nix-rosetta-builder, ... }:
let let
mkHomeConfiguration = { hostname, arch ? "x86_64", os ? "linux" mkHomeConfiguration = { hostname, arch ? "x86_64", os ? "linux"
, desktop ? false, extraModules ? [ ] }: , desktop ? false, extraModules ? [ ] }:
let let
system = "${arch}-${os}"; system = "${arch}-${os}";
pkgs = import nixpkgs { syspkg = if os == "darwin" then nixpkgs-darwin else nixpkgs;
pkgs = import syspkg {
inherit system; inherit system;
config.allowUnfree = true; config.allowUnfree = true;
overlays = [ nur.overlays.default ]; overlays = [ nur.overlays.default agenix.overlays.default ];
}; };
pkgs-unstable = import nixpkgs-unstable { pkgs-unstable = import nixpkgs-unstable {
inherit system; inherit system;
@ -80,7 +81,7 @@
] ++ (if desktop then [ ./homes/desktop.nix ] else [ ]) ] ++ (if desktop then [ ./homes/desktop.nix ] else [ ])
++ (if (desktop && os == "linux") then [ ++ (if (desktop && os == "linux") then [
./homes/linux-desktop.nix ./homes/linux-desktop.nix
plasma-manager.homeManagerModules.plasma-manager plasma-manager.homeModules.plasma-manager
] else ] else
[ ]) ++ extraModules; [ ]) ++ extraModules;
extraSpecialArgs = { extraSpecialArgs = {
@ -101,16 +102,12 @@
"millironx@anderson" = mkHomeConfiguration { hostname = "anderson"; }; "millironx@anderson" = mkHomeConfiguration { hostname = "anderson"; };
"millironx@mcentire" = mkHomeConfiguration { hostname = "mcentire"; };
"millironx@bosephus" = mkHomeConfiguration { hostname = "bosephus"; }; "millironx@bosephus" = mkHomeConfiguration { hostname = "bosephus"; };
"tchristensen@beocat" = mkHomeConfiguration { hostname = "beocat"; }; "tchristensen@beocat" = mkHomeConfiguration { hostname = "beocat"; };
"millironx@harmony" = mkHomeConfiguration {
hostname = "harmony";
arch = "aarch64";
desktop = true;
};
"millironx@odyssey" = mkHomeConfiguration { "millironx@odyssey" = mkHomeConfiguration {
hostname = "odyssey"; hostname = "odyssey";
desktop = true; desktop = true;
@ -126,8 +123,11 @@
}; };
agenix = agenix; agenix = agenix;
}; };
modules = modules = [
[ ./systems/darwin/corianne.nix agenix.darwinModules.default ]; ./systems/darwin/corianne.nix
agenix.darwinModules.default
nix-rosetta-builder.darwinModules.default
];
}; };
nixosConfigurations = { nixosConfigurations = {
@ -142,13 +142,14 @@
"mcentire" = nixpkgs.lib.nixosSystem { "mcentire" = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
specialArgs = {
home-manager-quadlet-nix = quadlet-nix.homeManagerModules.quadlet;
};
modules = [ modules = [
./systems/linux/mcentire.nix ./systems/linux/mcentire.nix
agenix.nixosModules.default agenix.nixosModules.default
home-manager.nixosModules.home-manager
quadlet-nix.nixosModules.quadlet quadlet-nix.nixosModules.quadlet
crowdsec.nixosModules.crowdsec
crowdsec.nixosModules.crowdsec-firewall-bouncer
{ nixpkgs.overlays = [ crowdsec.overlays.default ]; }
]; ];
}; };
}; };

View file

@ -1,13 +1,4 @@
{ config, lib, pkgs, pkgs-unstable, ... }: { config, lib, pkgs, pkgs-unstable, custom-pkgs, ... }: {
let
runic_version = "1.5.0";
runic = pkgs.fetchFromGitHub {
owner = "fredrikekre";
repo = "Runic.jl";
rev = "v${runic_version}";
hash = "sha256-y+kiBA94vUMHH0fEEBg7+c9PEgzjGqh6nCuSRnawhQI=";
};
in {
imports = [ imports = [
./../programs/shells.nix ./../programs/shells.nix
./../programs/bat.nix ./../programs/bat.nix
@ -20,17 +11,8 @@ in {
]; ];
home = { home = {
stateVersion = "23.11"; stateVersion = "23.11";
file = {
".local/bin/runic" = {
source = runic + "/bin/runic";
executable = true;
};
".local/bin/git-runic" = {
source = runic + "/bin/git-runic";
executable = true;
};
};
packages = with pkgs; [ packages = with pkgs; [
agenix
btop btop
cowsay cowsay
figlet figlet
@ -44,7 +26,7 @@ in {
jq jq
julia-bin julia-bin
lynx lynx
micromamba mamba-cpp
most most
nextflow nextflow
p7zip p7zip
@ -52,6 +34,8 @@ in {
pipx pipx
python3 python3
zulu17 zulu17
custom-pkgs.jlfmt
custom-pkgs.runic
]; ];
sessionVariables = { sessionVariables = {
PAGER = "most"; PAGER = "most";
@ -83,24 +67,9 @@ in {
"tailscale set --exit-node=$(tailscale exit-node suggest | awk '{print $4}' | head -n1)"; "tailscale set --exit-node=$(tailscale exit-node suggest | awk '{print $4}' | head -n1)";
# tsed - TailScale Exit node Disconnect # tsed - TailScale Exit node Disconnect
tsed = "tailscale set --exit-node="; tsed = "tailscale set --exit-node=";
micromamba = "mamba";
}; };
sessionPath = [ "$HOME/.local/bin" ]; sessionPath = [ "$HOME/.local/bin" ];
activation = {
recordHmGitHash = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
cd "$HOME/.config/home-manager" || exit 1
if [ -z "$(${pkgs.git}/bin/git status --porcelain --untracked-files=no)" ]; then
run echo "$(${pkgs.git}/bin/git rev-parse HEAD)" | tee $HOME/.cache/hm-git-hash
else
run echo '*' | tee $HOME/.cache/hm-git-hash
fi
'';
installRunic = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
run ${pkgs.julia-bin}/bin/julia --project=@runic --startup-file=no -e 'using Pkg; Pkg.add(name="Runic", version="${runic_version}")'
'';
installJuliaFormatter = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
run ${pkgs.julia-bin}/bin/julia --project=@JuliaFormatter --startup-file=no -e 'using Pkg; Pkg.add(name="JuliaFormatter", version="2.1.6")'
'';
};
}; };
programs = { programs = {
home-manager.enable = true; home-manager.enable = true;

View file

@ -7,7 +7,7 @@
]; ];
home = { home = {
packages = with pkgs; [ packages = with pkgs; [
asitop macpm
pinentry_mac pinentry_mac
(pkgs.writeShellScriptBin "uq" '' (pkgs.writeShellScriptBin "uq" ''
xattr -rdv com.apple.quarantine "/Applications/$1.app" xattr -rdv com.apple.quarantine "/Applications/$1.app"
@ -34,22 +34,6 @@
launchd = { launchd = {
enable = true; enable = true;
agents = { agents = {
ollama = {
enable = true;
config = {
Label = "local.home-manager.ollama";
ProgramArguments = [ "${pkgs.ollama}/bin/ollama" "serve" ];
RunAtLoad = true;
KeepAlive = true;
StandardOutPath =
"${config.home.homeDirectory}/Library/Logs/ollama.log";
StandardErrorPath =
"${config.home.homeDirectory}/Library/Logs/ollama-error.log";
EnvironmentVariables = {
PATH = "${lib.makeBinPath [ pkgs.ollama ]}:$PATH";
};
};
};
freetube-sync = { freetube-sync = {
enable = true; enable = true;

View file

@ -2,7 +2,6 @@
imports = [ imports = [
./../programs/firefox.nix ./../programs/firefox.nix
./../programs/ghostty.nix
./../programs/zed.nix ./../programs/zed.nix
./../services/gpg-agent.nix ./../services/gpg-agent.nix
]; ];
@ -23,7 +22,7 @@
nil nil
nixd nixd
nixfmt-classic nixfmt-classic
ollama nixos-rebuild
quarto quarto
roboto-slab roboto-slab
shellcheck shellcheck

View file

@ -1,95 +0,0 @@
{ config, lib, pkgs, pkgs-unstable, ... }: {
# harmony is an Asahi Fedora box
# I don't use NixOS, so there are some programs that don't interact well with
# the base system (or won't even install) when installed from Nix.
# There is no uniform way to trigger dnf package installs from Nix, so I'm
# just going to list my packages here. I hope to create a custom script that
# mimics the ideas of a Brewfile someday
# TODO: Create a Brewfile equivalent for dnf
# dnf repos:
# https://github.com/terrapkg/packages?tab=readme-ov-file
# https://pkgs.tailscale.com/stable/fedora/tailscale.repo
# https://packagecloud.io/filips/FirefoxPWA
# copr repos:
# iucar/rstudio
# dnf packages:
# apptainer
# chromium
# firefoxpwa - The nix version installs an "immutable" runtime, which simply launches extra browser windows on non-NixOS
# inkscape
# kate
# kdiff3
# krita
# lutris
# musescore
# nextcloud-client
# nextcloud-client-dolphin
# obs-studio
# podman-compose
# podman-docker
# qownnotes
# qt
# rssguard
# rstudio-desktop
# steam
# supertuxkart
# tailscale
# thunderbird
# vlc
# vorta - The vorta package is aarch64 compatible, but you cannot see any icons, and it cannot access local ssh keys, so we have to use the dnf package instead
# yakuake
# zed
# zsh
# R
# https://downloads.sourceforge.net/project/mscorefonts2/rpms/msttcore-fonts-installer-2.6-1.noarch.rpm
home = {
username = "millironx";
homeDirectory = "/home/millironx";
# Signal desktop is not available in any other package repository for aarch64 linux
# Similarly, Bitwarden is non-functional in all other forms using a 16k page size
packages = with pkgs; [
trayscale
veracrypt
pkgs-unstable.signal-desktop
pkgs.bitwarden-desktop
];
};
programs = {
git = {
signing = {
key = "0x37A3041D1C8C4524!";
signByDefault = true;
};
};
};
services = {
gpg-agent = { sshKeys = [ "207D13371E19752A67AA2686C16354D9963821DB" ]; };
};
xdg = {
configFile = {
"nextflow.config".text = ''
params {
config_profile_description = 'harmony Asahi Linux local profile'
config_profile_contact = 'Thomas A. Christensen II <25492070+MillironX@users.noreply.github.com>'
config_profile_url = null
max_memory = 12.GB
max_cpus = 12
max_time = 7.d
}
apptainer {
enabled = true
autoMounts = true
}
process {
executor = 'local'
}
'';
};
};
}

View file

@ -113,20 +113,12 @@ in {
configFile = { configFile = {
"plasma-workspace/env/ZED_WINDOW_DECORATIONS.sh".text = "plasma-workspace/env/ZED_WINDOW_DECORATIONS.sh".text =
"export ZED_WINDOW_DECORATIONS=server"; "export ZED_WINDOW_DECORATIONS=server";
"dolphinrc".source =
mkOutOfStoreSymlink "${home-manager-repo}/dotfiles/dolphinrc";
"konsolerc".source =
mkOutOfStoreSymlink "${home-manager-repo}/dotfiles/konsolerc";
"onedrive/config".text = '' "onedrive/config".text = ''
force_session_upload = "true" force_session_upload = "true"
delay_inotify_processing = "true" delay_inotify_processing = "true"
''; '';
"yakuakerc".source =
mkOutOfStoreSymlink "${home-manager-repo}/dotfiles/yakuakerc";
}; };
dataFile = { dataFile = {
"konsole/My Default.profile".source =
mkOutOfStoreSymlink "${home-manager-repo}/dotfiles/MyDefault.profile";
"kio/servicemenus/kate.desktop".source = ./../dotfiles/kate.desktop; "kio/servicemenus/kate.desktop".source = ./../dotfiles/kate.desktop;
"kio/servicemenus/vlc.desktop".source = ./../dotfiles/vlc.desktop; "kio/servicemenus/vlc.desktop".source = ./../dotfiles/vlc.desktop;
"kio/servicemenus/word-to-pdf.desktop".source = "kio/servicemenus/word-to-pdf.desktop".source =

8
homes/mcentire.nix Normal file
View file

@ -0,0 +1,8 @@
{ ... }: {
home = {
username = "millironx";
homeDirectory = "/home/millironx";
};
programs = { };
services = { };
}

View file

@ -3,20 +3,13 @@ ungrouped:
hosts: hosts:
localhost: localhost:
ansible_connection: local ansible_connection: local
harmony:
ansible_connection: local
odyssey: odyssey:
ansible_connection: local ansible_connection: local
asahi:
hosts:
harmony:
amd64: amd64:
hosts: hosts:
odyssey: odyssey:
fedora: fedora:
hosts: hosts:
harmony:
odyssey: odyssey:

167
modules/podman-secrets.nix Normal file
View file

@ -0,0 +1,167 @@
# Warning to my future self: This module was "vibe coded" by Claude Sonnet 4.5.
# I originally had a hand-written module in here that did the secrets
# translation as the root user. I knew that I would want to support multiple
# secrets files and multiple users, and thought I should be able to create an
# arbitrary number of them, similar to how you can have an arbitrary number
# of `programs.firefox.profiles`. Unfortunately, even after looking at lots of
# example modules, I could not figure out the syntax (Nix has a serious lack
# of minimum working examples), so I broke down and asked Claude to rewrite it
# for me. Based on everything that I read, this seems to be exactly what I asked
# for.
#
# Here is the prompt I used to get here:
# [@Per service isolation on NixOS with Traefik](zed:///agent/thread/94cb8a22-ff0c-4772-a1a1-018b0107f334?name=Per+service+isolation+on+NixOS+with+Traefik)
#
# [@podman-secrets.nix](file:///home/millironx/.config/home-manager/modules/podman-secrets.nix)
#
# I originally wrote this module assuming that I would use Podman as root for
# all containers. I would like to fix the module to have as many secrets files
# processed as needed with services setup for each secret that is run as the
# appropriate user. Ideally, the syntax for working with secrets to be
# translated would be
#
# ```nix
# { config, ... }: {
# age.secrets = {
# "caddy.toml" = {
# file = ./../secrets/caddy.toml.age;
# owner = "caddy";
# group = "caddy";
# };
#
# "authentik.toml" = {
# file = ./../secrets/authentik.toml.age;
# owner = "authentik";
# group = "authentik";
# };
#
# "freshrss.toml" = {
# file = ./../secrets/freshrss.toml.age;
# owner = "freshrss";
# group = "freshrss";
# };
# };
#
# millironx.podman-secrets = with config; {
# caddy = {
# user = "caddy";
# secrets-files = [
# ./../not-really-secret.toml
# age.secrets."caddy.toml".path
# ];
# };
# authentik = {
# user = "authentik";
# secrets-files = [
# age.secrets."authentik.toml".path
# ];
# };
# freshrss = {
# user = "freshrss";
# secrets-files = [
# age.secrets."freshrss.toml".path
# ];
# };
# };
# }
# ```
#
# Can you help me rewrite the module to accomplish this?
#
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.millironx.podman-secrets;
secret-translator = pkgs.writeScriptBin "secret-translator"
(builtins.readFile ./../bin/secret-translator.jl);
# Submodule type for each service's secrets configuration
serviceSecretsType = types.submodule ({ config, name, ... }: {
options = {
user = mkOption {
type = types.str;
description = "User account to run the secrets translation service as";
example = "caddy";
};
secrets-files = mkOption {
type = types.listOf (types.either types.path types.string);
description =
"List of TOML files containing secrets to translate to Podman secrets";
example = literalExpression ''
[
"/run/agenix/caddy.toml"
./../not-really-secret.toml
]
'';
default = [ ];
};
ref = mkOption {
type = types.str;
description =
"Reference to the systemd service name for declaring dependencies";
readOnly = true;
default = "podman-secrets-${name}.service";
example = "podman-secrets-caddy.service";
};
};
});
# Generate a systemd user service for each configured service
mkSecretsService = name: serviceCfg:
nameValuePair "podman-secrets-${name}" {
description = "Podman secrets converter service for ${name}";
wantedBy = [ "default.target" ];
unitConfig.ConditionUser = "${serviceCfg.user}";
serviceConfig = {
Type = "oneshot";
ProtectProc = "invisible";
ExecStart = "${secret-translator}/bin/secret-translator ${
lib.concatStringsSep " " serviceCfg.secrets-files
}";
Environment = "PATH=/run/wrappers/bin:${
lib.makeBinPath (with pkgs; [ shadow podman julia-lts-bin ])
}";
};
};
# Filter out services with no secrets-files
enabledServices =
lib.filterAttrs (name: serviceCfg: serviceCfg.secrets-files != [ ]) cfg;
in {
options.millironx.podman-secrets = mkOption {
type = types.attrsOf serviceSecretsType;
description = ''
Per-service Podman secrets configuration.
Each attribute creates a separate systemd user service that translates TOML secrets
files into Podman secrets.
'';
example = literalExpression ''
{
caddy = {
user = "caddy";
secrets-files = [
./../not-really-secret.toml
config.age.secrets."caddy.toml".path
];
};
authentik = {
user = "authentik";
secrets-files = [
config.age.secrets."authentik.toml".path
];
};
}
'';
default = { };
};
config = mkIf (enabledServices != { }) {
systemd.user.services = lib.mapAttrs' mkSecretsService enabledServices;
};
}

View file

@ -1,6 +1,7 @@
{ pkgs, ... }: { pkgs, ... }:
with pkgs; {
{ ark = callPackage ./ark.nix { };
ark = pkgs.callPackage ./ark.nix { }; jlfmt = callPackage ./jlfmt.nix { };
sc4pac = pkgs.callPackage ./sc4pac.nix { }; runic = callPackage ./runic.nix { };
sc4pac = callPackage ./sc4pac.nix { };
} }

12
pkgs/jlfmt.nix Normal file
View file

@ -0,0 +1,12 @@
{ pkgs, ... }:
with pkgs;
let
juliaWithPkgs = julia-bin.withPackages.override { setDefaultDepot = false; }
[ "JuliaFormatter" ];
depotWithPkgs = runCommand "getDepot" { } ''
${juliaWithPkgs}/bin/julia -e 'println(first(DEPOT_PATH))' | tee $out
'';
in writeShellScriptBin "jlfmt" ''
export JULIA_DEPOT_PATH=$(< ${depotWithPkgs})
exec ${juliaWithPkgs}/bin/julia --startup-file=no -e 'using JuliaFormatter; print(format_text(String(read(stdin))));' -- "$@"
''

12
pkgs/runic.nix Normal file
View file

@ -0,0 +1,12 @@
{ pkgs, ... }:
with pkgs;
let
juliaWithRunic =
julia-bin.withPackages.override { setDefaultDepot = false; } [ "Runic" ];
depotWithRunic = runCommand "getRunicDepot" { } ''
${juliaWithRunic}/bin/julia -e 'println(first(DEPOT_PATH))' | tee $out
'';
in writeShellScriptBin "runic" ''
export JULIA_DEPOT_PATH=$(< ${depotWithRunic})
exec ${juliaWithRunic}/bin/julia --startup-file=no -e 'using Runic; exit(Runic.main(ARGS))' -- "$@"
''

View file

@ -11,7 +11,7 @@
mode: "755" mode: "755"
- name: Create Firefox DNS policy - name: Create Firefox DNS policy
ansible.builtin.template: ansible.builtin.template:
src: "{{ playbook_dir }}/../templates/policies.json" src: "policies.json"
dest: /etc/firefox/policies/policies.json dest: /etc/firefox/policies/policies.json
mode: "644" mode: "644"

View file

@ -45,7 +45,8 @@
register: home_manager_exists register: home_manager_exists
- name: Init home-manager - name: Init home-manager
ansible.builtin.shell: | ansible.builtin.shell: |
/nix/var/nix/profiles/default/bin/nix run home-manager -- switch --flake git+https://code.millironx.com/millironx/nix-dotfiles#{{ ansible_user_id }}@{{ ansible_hostname }} /nix/var/nix/profiles/default/bin/nix run home-manager -- switch \
--flake git+https://code.millironx.com/millironx/nix-dotfiles#{{ ansible_user_id }}@{{ ansible_hostname }}
when: not home_manager_exists.stat.exists when: not home_manager_exists.stat.exists
register: home_manager_init register: home_manager_init
changed_when: home_manager_init.rc == 0 changed_when: home_manager_init.rc == 0

View file

@ -1,78 +1,33 @@
--- ---
# These are repos and packages that are useless or unavailable on Asahi Linux, - name: Configure dnf packages
# or have completely separate install procedures.
- name: Configure amd64-specific dnf packages
hosts: amd64
become: true
tasks:
- name: Install x86-specific dnf packages
ansible.builtin.dnf:
name:
- libdvdcss
- mkvtoolnix
- mpv
- protontricks
- x264
- x264-libs
state: present
- name: Install VeraCrypt
ansible.builtin.dnf:
name: https://launchpad.net/veracrypt/trunk/1.26.20/+download/veracrypt-1.26.20-Fedora-40-x86_64.rpm
state: present
disable_gpg_check: true
- name: Configure amd64-specific Flatpaks
hosts: amd64
become: false
tasks:
- name: Install x86-specific Flatpaks
community.general.flatpak:
name:
- com.bitwarden.desktop
- com.slack.Slack
- dev.deedles.Trayscale
- org.signal.Signal
state: latest
method: user
remote: flathub
- name: Configure Asahi Linux-specific dnf packages
hosts: asahi
become: true
tasks:
- name: Install aarch64-specific dnf packages
ansible.builtin.dnf:
name:
- veracrypt
- name: Configure common (all arch) dnf packages
hosts: fedora hosts: fedora
become: true become: true
tasks: tasks:
- name: Install common (all arch) dnf packages - name: Install dnf packages
ansible.builtin.dnf: ansible.builtin.dnf:
name: name:
- chromium - chromium
- firefoxpwa
- fontconfig-devel - fontconfig-devel
- freetype-devel - freetype-devel
- fribidi-devel - fribidi-devel
- ghostty
- inkscape - inkscape
- jq - jq
- kate - kate
- kdenlive - kdenlive
- kdiff3 - kdiff3
- krita - krita
- libdvdcss
- libjpeg-devel - libjpeg-devel
- libpng-devel - libpng-devel
- libtiff-devel - libtiff-devel
- libwebp-devel - libwebp-devel
- musescore - mkvtoolnix
- mpv
- nextcloud-client - nextcloud-client
- nextcloud-client-dolphin - nextcloud-client-dolphin
- obs-studio - obs-studio
- onedrive - onedrive
- protontricks
- qownnotes - qownnotes
- qt - qt
- rssguard - rssguard
@ -82,6 +37,8 @@
- thunderbird - thunderbird
- vlc - vlc
- vorta - vorta
- x264
- x264-libs
- yakuake - yakuake
- zed - zed
- zsh - zsh
@ -92,6 +49,11 @@
name: https://downloads.sourceforge.net/project/mscorefonts2/rpms/msttcore-fonts-installer-2.6-1.noarch.rpm name: https://downloads.sourceforge.net/project/mscorefonts2/rpms/msttcore-fonts-installer-2.6-1.noarch.rpm
state: present state: present
disable_gpg_check: true disable_gpg_check: true
- name: Install VeraCrypt
ansible.builtin.dnf:
name: https://launchpad.net/veracrypt/trunk/1.26.20/+download/veracrypt-1.26.20-Fedora-40-x86_64.rpm
state: present
disable_gpg_check: true
- name: Install rig (R installation manager) - name: Install rig (R installation manager)
ansible.builtin.dnf: ansible.builtin.dnf:
name: https://github.com/r-lib/rig/releases/download/latest/r-rig-latest-1.{{ ansible_architecture }}.rpm name: https://github.com/r-lib/rig/releases/download/latest/r-rig-latest-1.{{ ansible_architecture }}.rpm
@ -109,21 +71,24 @@
name: "*" name: "*"
state: latest # noqa: package-latest state: latest # noqa: package-latest
- name: Configure common (all arch) Flatpaks - name: Configure Flatpaks
hosts: fedora hosts: fedora
become: false become: false
tasks: tasks:
- name: Install common (all arch) Flatpaks - name: Install Flatpaks
community.general.flatpak: community.general.flatpak:
name: name:
- com.bitwarden.desktop
- com.github.tchx84.Flatseal - com.github.tchx84.Flatseal
- com.logseq.Logseq - com.logseq.Logseq
- com.slack.Slack
- dev.deedles.Trayscale
- io.freetubeapp.FreeTube - io.freetubeapp.FreeTube
- io.github.alainm23.planify - io.github.alainm23.planify
- io.github.dweymouth.supersonic - io.github.dweymouth.supersonic
- io.openrct2.OpenRCT2 - io.openrct2.OpenRCT2
- org.signal.Signal
- org.zulip.Zulip - org.zulip.Zulip
- net.ankiweb.Anki
state: latest state: latest
method: user method: user
remote: flathub remote: flathub

View file

@ -1,6 +1,6 @@
--- ---
- name: Configure amd64-specific package repositories - name: Configure dnf package repositories
hosts: amd64 hosts: fedora
become: true become: true
tasks: tasks:
- name: Install RPM Fusion free repository - name: Install RPM Fusion free repository
@ -20,31 +20,6 @@
- name: Install Zotero COPR repository - name: Install Zotero COPR repository
community.general.copr: community.general.copr:
name: "mozes/zotero7" name: "mozes/zotero7"
# Asahi Linux comes with its own strange version of RPMFusion installed, so
# RPMFusion is installed only on amd64 systems. In addition, VeraCrypt and
# Zotero *are* available via COPR, but from different repos than their amd64
# counterparts.
# Also, Asahi has its own version string, so we have to manually specify the
# chroot for COPR repos added via Ansible. This is handled automatically when
# using `dnf copr enable ...`, but not via Ansible.
- name: Configure Asahi Linux-specific package repositories
hosts: asahi
become: true
tasks:
- name: Install Zotero COPR repository
community.general.copr:
name: "isaksamsten/Zotero"
chroot: "fedora-{{ ansible_distribution_major_version }}-aarch64"
- name: Install VeraCrypt COPR repository
community.general.copr:
name: "architektapx/veracrypt"
chroot: "fedora-{{ ansible_distribution_major_version }}-aarch64"
- name: Configure common (all arch) package repositories
hosts: fedora
become: true
tasks:
- name: Install Tailscale repo - name: Install Tailscale repo
ansible.builtin.yum_repository: ansible.builtin.yum_repository:
name: tailscale-stable name: tailscale-stable
@ -53,14 +28,6 @@
enabled: true enabled: true
gpgcheck: true gpgcheck: true
gpgkey: https://pkgs.tailscale.com/stable/fedora/repo.gpg gpgkey: https://pkgs.tailscale.com/stable/fedora/repo.gpg
- name: Install FirefoxPWA repository
ansible.builtin.yum_repository:
name: firefoxpwa
description: FirefoxPWA repository
baseurl: https://packagecloud.io/filips/FirefoxPWA/fedora/$releasever/$basearch
gpgcheck: true
gpgkey: https://packagecloud.io/filips/FirefoxPWA/gpgkey
enabled: true
# Note that I still have to specify the chroot for COPR repos b/c of Asahi # Note that I still have to specify the chroot for COPR repos b/c of Asahi
- name: Install RStudio copr repository - name: Install RStudio copr repository
community.general.copr: community.general.copr:
@ -110,7 +77,7 @@
register: terra_priority register: terra_priority
changed_when: terra_priority.rc != 0 changed_when: terra_priority.rc != 0
- name: Configure Flathub remote - name: Configure Flatpack remotes
hosts: fedora hosts: fedora
become: false become: false
tasks: tasks:

View file

@ -1,4 +1,4 @@
{ firefox-addons, buildFirefoxXpiAddon, lib, ... }: { { pkgs, firefox-addons, buildFirefoxXpiAddon, lib, ... }: {
programs.firefox = { programs.firefox = {
enable = true; enable = true;
package = package =
@ -31,49 +31,49 @@
}; };
}; };
containersForce = true; containersForce = true;
extensions.packages = with firefox-addons; [ extensions.packages = with firefox-addons;
bitwarden [
multi-account-containers bitwarden
floccus multi-account-containers
libredirect libredirect
old-reddit-redirect old-reddit-redirect
plasma-integration ublock-origin
pwas-for-firefox user-agent-string-switcher
ublock-origin zotero-connector
user-agent-string-switcher (buildFirefoxXpiAddon rec {
web-archives pname = "always_in_container";
zotero-connector version = "1.0.7";
(buildFirefoxXpiAddon rec { addonId = "{a1e9543e-5f73-4763-b376-04e53fd12cbd}";
pname = "always_in_container"; url =
version = "1.0.7"; "https://addons.mozilla.org/firefox/downloads/file/4032840/${pname}-${version}.xpi";
addonId = "{a1e9543e-5f73-4763-b376-04e53fd12cbd}"; sha256 = "sha256-bLxjL2P6Sd06q98MSHYRTNigtcjGwn/C2r4ANWCqKrw=";
url = meta = with lib; {
"https://addons.mozilla.org/firefox/downloads/file/4032840/${pname}-${version}.xpi"; homepage = "https://github.com/tiansh/always-in-container";
sha256 = "sha256-bLxjL2P6Sd06q98MSHYRTNigtcjGwn/C2r4ANWCqKrw="; description =
meta = with lib; { "Chose a container every time you try to open a page out of a container";
homepage = "https://github.com/tiansh/always-in-container"; license = licenses.mpl20;
description = platforms = platforms.all;
"Chose a container every time you try to open a page out of a container"; };
license = licenses.mpl20; })
platforms = platforms.all; (buildFirefoxXpiAddon rec {
}; pname = "open_with";
}) version = "7.2.6";
(buildFirefoxXpiAddon rec { addonId = "openwith@darktrojan.net";
pname = "open_with"; url =
version = "7.2.6"; "https://addons.mozilla.org/firefox/downloads/file/3831723/${pname}-${version}.xpi";
addonId = "openwith@darktrojan.net"; sha256 = "sha256-f9eGhLxg4UyVn4o5e4DRkraLWzj11SGto/GOwsJa9kg=";
url = meta = with lib; {
"https://addons.mozilla.org/firefox/downloads/file/3831723/${pname}-${version}.xpi"; homepage = "https://darktrojan.github.io/openwith/";
sha256 = "sha256-f9eGhLxg4UyVn4o5e4DRkraLWzj11SGto/GOwsJa9kg="; description =
meta = with lib; { "Quickly test out your web pages in Chrome, Edge, Safari, or Opera. Open With opens the current page in your other browsers with just two clicks.";
homepage = "https://darktrojan.github.io/openwith/"; license = licenses.mpl20;
description = platforms = platforms.all;
"Quickly test out your web pages in Chrome, Edge, Safari, or Opera. Open With opens the current page in your other browsers with just two clicks."; };
license = licenses.mpl20; })
platforms = platforms.all; ] ++ (if pkgs.stdenv.hostPlatform.isDarwin then
}; [ ]
}) else
]; [ plasma-integration ]);
search = { search = {
default = "Kagi"; default = "Kagi";
privateDefault = "Milliron X Search"; privateDefault = "Milliron X Search";
@ -246,7 +246,6 @@
"floccus_handmadeideas_org-browser-action" "floccus_handmadeideas_org-browser-action"
"7esoorv3_alefvanoon_anonaddy_me-browser-action" "7esoorv3_alefvanoon_anonaddy_me-browser-action"
"plasma-browser-integration_kde_org-browser-action" "plasma-browser-integration_kde_org-browser-action"
"firefoxpwa_filips_si-browser-action"
"_d07ccf11-c0cd-4938-a265-2a4d6ad01189_-browser-action" # Web Archives "_d07ccf11-c0cd-4938-a265-2a4d6ad01189_-browser-action" # Web Archives
"openwith_darktrojan_net-browser-action" "openwith_darktrojan_net-browser-action"
"zotero_chnm_gmu_edu-browser-action" "zotero_chnm_gmu_edu-browser-action"
@ -282,7 +281,6 @@
"floccus_handmadeideas_org-browser-action" "floccus_handmadeideas_org-browser-action"
"7esoorv3_alefvanoon_anonaddy_me-browser-action" "7esoorv3_alefvanoon_anonaddy_me-browser-action"
"plasma-browser-integration_kde_org-browser-action" "plasma-browser-integration_kde_org-browser-action"
"firefoxpwa_filips_si-browser-action"
"ublock0_raymondhill_net-browser-action" "ublock0_raymondhill_net-browser-action"
"_d07ccf11-c0cd-4938-a265-2a4d6ad01189_-browser-action" "_d07ccf11-c0cd-4938-a265-2a4d6ad01189_-browser-action"
"zotero_chnm_gmu_edu-browser-action" "zotero_chnm_gmu_edu-browser-action"

View file

@ -1,19 +0,0 @@
{ pkgs, ... }: {
programs.ghostty =
let modifierKey = if pkgs.stdenv.isDarwin then "cmd" else "ctrl";
in {
enable = true;
package = null;
enableBashIntegration = true;
enableZshIntegration = true;
settings = {
quick-terminal-position = "top";
quick-terminal-screen = "main";
quick-terminal-autohide = true;
quick-terminal-size = "50%,50%";
keybind = "global:${modifierKey}+backquote=toggle_quick_terminal";
macos-hidden = "always";
linux-cgroup = "always";
};
};
}

View file

@ -1,9 +1,11 @@
{ ... }: { { ... }: {
programs.git = { programs.git = {
enable = true; enable = true;
userName = "Thomas A. Christensen II"; settings = {
userEmail = "25492070+MillironX@users.noreply.github.com"; user = {
extraConfig = { name = "Thomas A. Christensen II";
email = "25492070+MillironX@users.noreply.github.com";
};
core = { editor = "nvim"; }; core = { editor = "nvim"; };
credential = { helper = "store"; }; credential = { helper = "store"; };
color = { ui = "auto"; }; color = { ui = "auto"; };
@ -40,6 +42,11 @@
}; };
merge = { conflictstyle = "zdiff3"; }; merge = { conflictstyle = "zdiff3"; };
pull = { rebase = true; }; pull = { rebase = true; };
"url \"ssh://git@github.com/\"".insteadOf = "https://github.com/";
"url \"ssh://git@gitlab.com/\"".insteadOf = "https://gitlab.com/";
"url \"ssh://git@codeberg.com/\"".insteadOf = "https://codeberg.com/";
"url \"ssh://git@code.millironx.com/\"".insteadOf =
"https://code.millironx.com/";
}; };
}; };
} }

23
programs/konsole.nix Normal file
View file

@ -0,0 +1,23 @@
{ ... }: {
programs.konsole = {
enable = true;
defaultProfile = "millironx";
profiles.millironx = {
colorScheme = "Breeze";
font = {
name = "MesloLGS NF";
size = 10;
};
extraConfig = {
"Cursor Options".CursorShape = 1;
General.RemoteTabTitleFormat = "[SSH] %H";
"Interaction Options" = {
CopyTextAsHTML = false;
MouseWheelZoomEnabled = false;
UnderlineFilesEnabled = true;
};
"Terminal Features".BlinkingCursorEnabled = true;
};
};
};
}

View file

@ -1,7 +1,177 @@
{ config, ... }: { { config, ... }: {
imports = [ ./konsole.nix ./yakuake.nix ];
programs.plasma = { programs.plasma = {
enable = true; enable = true;
overrideConfig = true;
shortcuts = { yakuake.toggle-window-state = "Ctrl+`"; };
configFile = {
dolphinrc = {
DetailsMode.PreviewSize = 16;
General = {
BrowseThroughArchives = true;
EditableUrl = true;
GlobalViewProps = false;
ShowFullPath = true;
ShowStatusBar = "FullWidth";
ShowZoomSlider = true;
};
"KFileDialog Settings" = {
"Places Icons Auto-resize" = false;
"Places Icons Static Size" = 22;
};
PreviewSettings.Plugins =
"audiothumbnail,avif,blenderthumbnail,comicbookthumbnail,cursorthumbnail,djvuthumbnail,ebookthumbnail,exrthumbnail,directorythumbnail,fontthumbnail,imagethumbnail,jpegthumbnail,jxl,kraorathumbnail,windowsexethumbnail,windowsimagethumbnail,mobithumbnail,opendocumentthumbnail,gsthumbnail,rawthumbnail,svgthumbnail,gdk-pixbuf-thumbnailer,ffmpegthumbs,gsf-office";
};
};
input.mice = [{
enable = true;
name = "Logitech M705";
vendorId = "046d";
productId = "406d";
naturalScroll = true;
}];
kwin = {
cornerBarrier = false;
titlebarButtons = {
left = [ "close" "minimize" "maximize" ];
right = [ "help" ];
};
virtualDesktops = {
number = 2;
rows = 1;
};
};
panels = [
### Screen 0 panels ###
##### Top: Fedora menu | App switcher | Menu bar | CPU monitor | Memory monitor | Network monitor | System tray | clock #####
{
location = "top";
floating = true;
height = 27;
lengthMode = "fill";
opacity = "adaptive";
hiding = "normalpanel";
screen = 0;
widgets = [
{ kickoff = { icon = "fedora-logo-icon"; }; }
"org.kde.plasma.marginsseparator"
"org.kde.plasma.windowlist"
"org.kde.plasma.appmenu"
"org.kde.plasma.panelspacer"
{
name = "org.kde.plasma.systemmonitor.cpu";
config = {
Appearance.chartFace = "org.kde.ksysguard.barchart";
Sensors.highPrioritySensorIds = "[${
builtins.concatStringsSep "," (builtins.genList
(i: ''"cpu/cpu${builtins.toString i}/usage"'') 12)
}]";
};
}
{
name = "org.kde.plasma.systemmonitor.memory";
config.Appearance.chartFace = "org.kde.ksysguard.horizontalbars";
}
{
name = "org.kde.plasma.systemmonitor.net";
config = {
Appearance.chartFace = "org.kde.ksysguard.horizontalbars";
Sensors.highPrioritySensorIds =
''[ "network/all/download","network/all/upload" ]'';
# These are the values needed to make the network indicator
# actually useful, but it appears that plasma-manager doesn't
# support nesting this deep yet. Disable for now.
# "org.kde.ksysguard.horizontalbars".General = {
# rangeAuto = false;
# rangeFromMultiplier = 1048576;
# rangeFromUnit = 202;
# rangeToMultiplier = 1048576;
# rangeToUnit = 202;
# };
};
}
{ systemTray = { }; }
{ digitalClock = { }; }
];
}
##### Bottom: Virtual desktop pager | Full-name taskbar w/ pins | Downloads folder | Trash folder
{
location = "bottom";
floating = true;
height = 44;
lengthMode = "fill";
opacity = "adaptive";
hiding = "normalpanel";
screen = 0;
widgets = [
"org.kde.plasma.pager"
{
iconTasks = {
iconsOnly = false;
behavior.showTasks.onlyInCurrentScreen = true;
launchers = [
"applications:systemsettings.desktop"
"applications:org.kde.discover.desktop"
"preferred://filemanager"
"preferred://browser"
"applications:net.thunderbird.Thunderbird.desktop"
"applications:io.github.alainm23.planify.desktop"
"applications:dev.zed.Zed.desktop"
"applications:com.logseq.Logseq.desktop"
"applications:net.lutris.Lutris.desktop"
];
};
}
"org.kde.plasma.panelspacer"
"org.kde.plasma.marginsseparator"
{
name = "org.kde.plasma.folder";
config = {
General.url = "file://${config.home.homeDirectory}/Downloads";
};
}
"org.kde.plasma.trash"
];
}
### Screen 1 panels ###
##### Top: App switcher | Menu bar #####
{
location = "top";
floating = true;
height = 27;
lengthMode = "fill";
opacity = "adaptive";
hiding = "normalpanel";
screen = 1;
widgets = [ "org.kde.plasma.windowlist" "org.kde.plasma.appmenu" ];
}
##### Bottom: Virtual desktop pager | Full-name taskbar w/o pins #####
{
location = "bottom";
floating = true;
height = 44;
lengthMode = "fill";
opacity = "adaptive";
hiding = "normalpanel";
screen = 1;
widgets = [
"org.kde.plasma.pager"
{
iconTasks = {
iconsOnly = false;
behavior.showTasks.onlyInCurrentScreen = true;
launchers = [ ];
};
}
];
}
];
powerdevil.AC.autoSuspend.action = "nothing";
workspace = { workspace = {
lookAndFeel = "org.kde.breezedark.desktop";
wallpaperFillMode = "preserveAspectCrop"; wallpaperFillMode = "preserveAspectCrop";
wallpaperSlideShow = { wallpaperSlideShow = {
interval = 86400; interval = 86400;

View file

@ -1,7 +1,7 @@
{ pkgs, ... }: { pkgs, ... }:
let let
conda_init = shell: '' conda_init = shell: ''
eval "$(${pkgs.micromamba}/bin/micromamba shell hook --shell ${shell})" eval "$(${pkgs.mamba-cpp}/bin/mamba shell hook --shell ${shell})"
''; '';
nd_bash_function = '' nd_bash_function = ''
@ -10,11 +10,53 @@ let
} }
''; '';
sourceCodeDirectory =
if pkgs.stdenv.hostPlatform.isDarwin then "~/Developer" else "~/src";
clone_bash_function = ''
unalias gc
function gc() {
REPO_ID="$(echo "''${1}" | \
awk '{
sub(/^git@/, "");
sub(/^https:\/\//, "");
sub (/:/, "/");
sub(/\.git$/, "");
print
}')"
git clone "https://''${REPO_ID}.git" ${sourceCodeDirectory}/''${REPO_ID}
cd ${sourceCodeDirectory}/''${REPO_ID}
}
'';
repo_init_function = ''
function rinit() {
REPO_ID="$(echo "''${1}" | \
awk '{
sub(/^git@/, "");
sub(/^https:\/\//, "");
sub (/:/, "/");
sub(/\.git$/, "");
print
}')"
mkdir -p ${sourceCodeDirectory}/''${REPO_ID}
cd ${sourceCodeDirectory}/''${REPO_ID}
git init
git remote add origin git@''${REPO_ID/\//:}.git
}
'';
shell_functions = shell:
(conda_init shell) + nd_bash_function + clone_bash_function
+ repo_init_function;
in { in {
programs = { programs = {
bash = { bash = {
enable = true; enable = true;
initExtra = conda_init "bash" + nd_bash_function + '' initExtra = shell_functions "bash" + ''
export PS1="[\[\e[32m\]\u\[\e[m\]@\[\e[33m\]\h\[\e[m\] \[\e[34m\]\W\[\e[m\]] \\$ " export PS1="[\[\e[32m\]\u\[\e[m\]@\[\e[33m\]\h\[\e[m\] \[\e[34m\]\W\[\e[m\]] \\$ "
''; '';
}; };
@ -37,7 +79,7 @@ in {
"zsh-users/zsh-completions" "zsh-users/zsh-completions"
]; ];
}; };
initContent = conda_init "zsh" + nd_bash_function; initContent = shell_functions "zsh";
}; };
}; };
} }

View file

@ -25,6 +25,10 @@
bundleIdentifier = "org.mozilla.thunderbird"; bundleIdentifier = "org.mozilla.thunderbird";
action = "launchOrActivateApp"; action = "launchOrActivateApp";
} }
{
bundleIdentifier = "com.microsoft.Outlook";
action = "launchOrActivateApp";
}
{ {
bundleIdentifier = "dev.zed.Zed"; bundleIdentifier = "dev.zed.Zed";
action = "launchOrActivateApp"; action = "launchOrActivateApp";
@ -34,11 +38,13 @@
action = "launchOrActivateApp"; action = "launchOrActivateApp";
} }
{ {
# Instinct dashboard
bundleIdentifier = bundleIdentifier =
"com.apple.Safari.WebApp.2F51A6D0-087A-438F-92D3-A73FE09CB4CC"; "com.apple.Safari.WebApp.2F51A6D0-087A-438F-92D3-A73FE09CB4CC";
action = "launchOrActivateApp"; action = "launchOrActivateApp";
} }
{ {
# Carestream
bundleIdentifier = bundleIdentifier =
"com.apple.Safari.WebApp.5EC6478E-03A6-4147-8A4D-6EF3DE3F06D3"; "com.apple.Safari.WebApp.5EC6478E-03A6-4147-8A4D-6EF3DE3F06D3";
action = "launchOrActivateApp"; action = "launchOrActivateApp";

19
programs/yakuake.nix Normal file
View file

@ -0,0 +1,19 @@
# Note: this file uses the lower-level `programs.plasma.configFile` syntax
# since plasma-manager does not yet support a high-level module for Yakuake
{ ... }: {
programs.plasma.configFile.yakuakerc = {
"Desktop Entry".DefaultProfile = "millironx.profile";
Shortcuts = {
next-session = "Shift+Right; Ctrl+Shift+Tab";
previous-terminal = "none";
};
Window = {
DynamicTabTitles = true;
Height = 60;
Screen = 1;
ShowSystrayIcon = false;
Width = 60;
};
Dialogs.FirstRun = false;
};
}

View file

@ -1,4 +1,4 @@
{ ... }: { { pkgs, ... }: {
programs.zed-editor = { programs.zed-editor = {
enable = true; enable = true;
extensions = [ extensions = [
@ -23,27 +23,27 @@
use_modifier_to_send = true; use_modifier_to_send = true;
default_model = { default_model = {
provider = "zed.dev"; provider = "zed.dev";
model = "claude-3-7-sonnet"; model = "claude-sonnet-4-5";
}; };
default_profile = "minimal"; default_profile = "minimal";
}; };
buffer_font_family = "FiraCode Nerd Font"; buffer_font_family = "FiraCode Nerd Font";
buffer_font_size = 11; buffer_font_size = 11;
features = { edit_prediction_provider = "zed"; }; features = { edit_prediction_provider = "zed"; };
git_hosting_providers = [
{
provider = "forgejo";
base_url = "https://code.millironx.com";
name = "Milliron X Code";
}
{
provider = "forgejo";
base_url = "https://codeberg.org";
name = "Codeberg";
}
];
languages = { languages = {
Julia = { Julia = { formatter = { external = { command = "jlfmt"; }; }; };
formatter = {
external = {
command = "julia";
arguments = [
"--project=@JuliaFormatter"
"--startup-file=no"
"-e"
"using JuliaFormatter; print(format_text(String(read(stdin))));"
];
};
};
};
LaTeX = { LaTeX = {
formatter = { formatter = {
external = { external = {
@ -52,13 +52,30 @@
}; };
}; };
}; };
Nix = {
formatter.external.command = "${pkgs.nixfmt-classic}/bin/nixfmt";
};
}; };
lsp = { lsp = {
nil = { nil = { settings.nix.flake.autoArchive = true; };
initialization_options.formatting.command = [ "nixfmt" ]; texlab = {
settings.nix.flake.autoArchive = true; settings = {
build = {
onSave = false;
forwardSearchAfter = true;
};
forwardSearch = if pkgs.stdenv.hostPlatform.isDarwin then {
executable =
"/Applications/Skim.app/Contents/SharedSupport/displayline";
args = [ "-r" "-g" "%l" "%p" "%f" ];
} else {
executable = "/usr/bin/okular";
args = [ "--unique" "file:%p#src:%l%f" ];
};
};
}; };
tinymist = { tinymist = {
initialization_options = { preview.background.enabled = true; };
settings = { settings = {
exportPdf = "onSave"; exportPdf = "onSave";
outputPath = "$root/$name"; outputPath = "$root/$name";
@ -81,5 +98,28 @@
ui_font_size = 16; ui_font_size = 16;
wrap_guides = [ 80 92 120 ]; wrap_guides = [ 80 92 120 ];
}; };
userTasks = [
{
label = "latexmk (project)";
command = "latexmk";
args = [ "-synctex=1" "-pdf" "-recorder" ];
cwd = "$ZED_DIRNAME";
tags = [ "latex-build" ];
}
{
label = "Open Typst preview";
command = "${
if pkgs.stdenv.hostPlatform.isDarwin then "open" else "xdg-open"
} http://127.0.0.1:23635/";
use_new_terminal = true;
allow_concurrent_runs = false;
reveal = "never";
reveal_target = "dock";
hide = "always";
shell = "system";
show_summary = true;
show_command = true;
}
];
}; };
} }

View file

@ -6,25 +6,36 @@ let
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIxTfeg+GZsfmG8TuEV1xW1gXknAIKzZ3UjZ3guRY+EW root@nixos"; "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIxTfeg+GZsfmG8TuEV1xW1gXknAIKzZ3UjZ3guRY+EW root@nixos";
bosephus-millironx = bosephus-millironx =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKaDPqRJHoqgY2pseh/mnhjaGWXprHk2s5I52LhHpHcF millironx@bosephus"; "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKaDPqRJHoqgY2pseh/mnhjaGWXprHk2s5I52LhHpHcF millironx@bosephus";
odyssey-millironx = corianne-host =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN9Aj7BtQp1Roa0tgopDrUo7g2am5WJ43lO1d1fDUz45 millironx@odyssey"; "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHKKkucebeb1GcerOZAAs5GQsgTS8kXw5W41b9Fy9+hp root@corianne.local";
corianne-millironx = corianne-millironx =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOgL2lO9RJBdQYANoxGyWXcNKi5/NZkRHHo/rNqaYMc/ millironx@corianne"; "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOgL2lO9RJBdQYANoxGyWXcNKi5/NZkRHHo/rNqaYMc/ millironx@corianne";
harmony-millironx = mcentire-host =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFBYxsCkw+ObDzIvU8z/rSlYcQx0JIt1bCVxKcDxeNNZ millironx@harmony"; "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINT51tQgsKzTIQc9WSQj01h/gPRvAD3k9jRhXppY7xmd root@nixos";
mcentire-millironx =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOdC6eNx2nBi3PWK/n4GJMbVf+NlQJv13aUqxse/h1kL millironx@mcentire";
odyssey-millironx =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKM5Q2zl3b91j+foqcVeQT+wb5DFEp+MbgotTTaKqZZi millironx@odyssey";
system-administrators = [ system-administrators = [
anderson-millironx anderson-millironx
bosephus-millironx bosephus-millironx
odyssey-millironx
corianne-millironx corianne-millironx
harmony-millironx mcentire-millironx
odyssey-millironx
]; ];
in { in {
"secrets/ansible-vault-password.age".publicKeys = system-administrators;
"secrets/authentik.toml.age".publicKeys = system-administrators
++ [ mcentire-host ];
"secrets/borgmatic-passphrase.age".publicKeys = system-administrators
++ [ mcentire-host ];
"secrets/borgmatic-ssh-config.age".publicKeys = system-administrators
++ [ mcentire-host ];
"secrets/darwin-policies-json.age".publicKeys = system-administrators
++ [ corianne-host ];
"secrets/freshrss.toml.age".publicKeys = system-administrators
++ [ mcentire-host ];
"secrets/network-information.age".publicKeys = system-administrators "secrets/network-information.age".publicKeys = system-administrators
++ [ bosephus-host ]; ++ [ bosephus-host ];
"secrets/pihole.age".publicKeys = system-administrators ++ [ bosephus-host ];
"secrets/ansible-vault-password.age".publicKeys = system-administrators;
"secrets/darwin-policies-json.age".publicKeys = system-administrators;
} }

View file

@ -1,13 +1,13 @@
age-encryption.org/v1 age-encryption.org/v1
-> ssh-ed25519 il3lzQ Ni2CHjeijXHfF62cUqVTm8MAOn6rRg8UrhqN6xvdkyk -> ssh-ed25519 il3lzQ SoqTRahd/xUVe/pDmQI3jT5X0lTxOwhy8hct20fwil4
DsT0Ysx88FlCLeRzoOGctX7KqatX9/UCr5WdtdLJAf4 UuYpQa5GpDALKQEMbSLnH2rp3kgPL+4zJZbJirkB5Q0
-> ssh-ed25519 1g/xww jRn91F29sISMyi41anAlzVCzt1t1DnUqxtryqkTQPlM -> ssh-ed25519 1g/xww gYtrdwJlp1pxcZ7l+RvawRScFOh/ami3yJobbKPyLiM
cysgZLQR0YhiJYXBl59DjKbm+N8FnjA46wkQtnAzBFA oQ8dwIUIakV8WVvuknn87BYcmEBBT+UI3BxImd71/jE
-> ssh-ed25519 +kBihw t6wlSnDKGgSzGhNJnryXVbDR40DATaV3fHovtI/u7zo -> ssh-ed25519 dbKeHw KVdpRmBWRYd5NC3UK3e8Em3XefnVxxc9KfXzbksvTC0
zOyCZtzfLKeer9K6SMpfTxn6El4HB7gQFQqLOxIYB5U fwyK7ORnCadX8Czs0WKW3ZDa1jeu7Wjba7Vm9nKqCBs
-> ssh-ed25519 dbKeHw cn+8WTwis58bYm2pfEra6LeLvzEZ8GhZrOEeN+kkhCM -> ssh-ed25519 3qPtug nEHt7lMjUrcehOGjtznFd+u60OdfG1dPJr/+aFP4OXY
fnlUAj8JtG8+r7Cj8xYUgF+JM6Pwqawn4sGI1LOeN78 DRtfbYQZJhMIfj1yHgpTdSU15z0Ld5/2wl0ATPN0W6w
-> ssh-ed25519 Svnssw zmDBR8TdRZ9NzNhwPYRN6c8naTxAkULyUZpKgk7Gshk -> ssh-ed25519 FRQvIA a4zYtpYFVGSum3wD850lM/wEcokckt4mlDRsrb6QrHY
0XCwpegEIlGXhnzLLUtmciKQiYiZRgnSOSvCcYeXXk8 QF75fGiiKZc1oHSOdy+QvPnQ1hhaLRebaE7i0keZxHw
--- D/lZ36n5sVste2NWfdOx8/klPh0CTmMjVQN74KIqDRY --- 8Y5Q9SlGWEzp9jeVcoHFrv3PR+eDyhOPFXIFRxZ1Koo
]%得ヌC}<7D>鶲ネモ"vホネ#<23>アェ釋「tュ、ワ_Q;^*!サ+<+ア瑁詞ネdBラ/Kメ<4B>` ÜJáżŢóóDlv\é÷÷lĹu$­0 ëë±{<7B>Ďri·śP7ĎĄPÚ锓…Äkr(ÇPˇĹHWË]r ĚĆŮr¸

BIN
secrets/authentik.toml.age Normal file

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,16 @@
age-encryption.org/v1
-> ssh-ed25519 il3lzQ 6815+wa1JjdVUu8U8vaRah8kVsjR3Fsot99HKWl4SSA
hPYVZuN1yTKQYFIQvIRdmr400aijXleA22Bxh1nXKdc
-> ssh-ed25519 1g/xww BPxSszlrjPTVJC+YOvo1N6ICUUdL7WKZX3DeambLjBY
JkJQFPGtxDtqeGj8Z1YtVq/pm6hgYKwzMW9MbtkvOwY
-> ssh-ed25519 dbKeHw PU5cZrKCkAvUjI/opkboDQKSWJ8osAOQiI62f9lbfRY
ef1z6ZcBASkhC4fdcN+RRE7q28rB/DN8CVdoNVkC81I
-> ssh-ed25519 3qPtug RWCMZiLQlS+bOOIBRGmoECOfqEI2uoaWCq/4ZuI86B4
VOaLaH1VYnGoQzjb8seU6wVviB94W3qCdYW9Wf4PGIc
-> ssh-ed25519 FRQvIA LCDwNMNVtTcI3GHPR2mcgtR16yAYYwLplI2nKUwNxDQ
vwXBIDlK7FBOsKt48Zv8mp0WFA/TKH2UJxtUxZoxzMI
-> ssh-ed25519 +C0WRg a/R13LfNMjVjJxt2TtTHaqZOhsYJLY+HUGMHEDnkZWo
T2EfeE/a4W4bFvauynfh+4aJL1jhCpO8iBG2aTmKtyM
--- o7tyupfhbxh3dwSrBLsYX0V61va0USlqxheNsdBjVuQ
A ¤q,:_™aɪ”)Àžj“¹<E2809C>1ß2 #¼¾²t,G®£*«
X¿TÛ³(óŽòœ5øtúñ6‡¡ÕB“çš©èã8à0Í Ú*Ïâìèi׆Ðì^ÇÓߨ@ÔaóB@̃Ž+oF¯…<C2AF>ü÷w‰÷²¼åPciˆ2Ü7Y¨SXd²“<C2B2> ÚØg±É̲ñJ

Binary file not shown.

BIN
secrets/freshrss.toml.age Normal file

Binary file not shown.

Binary file not shown.

View file

@ -1,15 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 il3lzQ Q+/uqZhUWs5pb5T1ocD+/qTSo4DJbd/W1exruQ34zAE
8HFRvEblGVrkoVaqAl/Af6wrDn6A+3unZIMBipEkwgA
-> ssh-ed25519 1g/xww PqXxTvLaF6ZlcVov81VrVH130jFh2iGmHPRtBYV4ME4
1VBknQzaNZyoz2wvgKX+IZGaOEnJ1xGvxPYxq10ar/U
-> ssh-ed25519 +kBihw QXNxY9OQeIM98OqmHoa/S2kMZqSX+ndgxGyCJpHJ+gg
b3DmfUswyPQ09sp57v3QMNEF/Ka3w9Qj2s1kGUSinmQ
-> ssh-ed25519 dbKeHw 5GzjKgjUX5e6Net7voWBykC17zRcdSFDFbDsSwp5FAU
GwTEg3YR9HdcQHPg+XjP2Lg1BpcWA4VunbZSBdxVaYU
-> ssh-ed25519 Svnssw imRjD5CJu/jOac3t/APHbYBnsyJVQdebR6K52A6GdwM
n+Q9kEEkYRBuEzWlSwbjJNsjF8uKloeUEWYxHa29B4U
-> ssh-ed25519 jb0ALQ 4qbGIofHcyhJVfL24peGqqzg0tFdxbWBHJFenwehIAI
Ta3ye4quyHvvE+2CGZwYvQMwWfdrLIdqADLvJYhllPY
--- 3hbht7PYqFafVmcQWQwv3q2gUXM8HXajtmAaMnrh59s
 +óX9ð¾84R2ƒª,òôˆ±¨(#42ì#*, bùôŒç¦½Hã_z…œ…¨Í }ß… ®ëxñ7Aœ!<21>)ê)vÊž¨¨•W-÷¿eX-G‡<´¸@~â¢èEÜk¬?kGlQK¬4c&*JöÂå9V_Ä0Õö µzÓ+ɰ¯CÞ ÑžÀQ°ò«ÃGô§XÁ˜k¡g*£æð -Àjƒö¼l½ú3¿‰1ÏJš´üM·OE†[=S

View file

@ -1,10 +1,8 @@
$ANSIBLE_VAULT;1.1;AES256 $ANSIBLE_VAULT;1.1;AES256
65366137313461383534313965646333656565353061336361363661613033393264353661346337 33613635643765623937663135313833396162343134383466343966333964386364356134663264
3838653162383134393463323631613439373663396363380a633339396236363962313333343465 3137633339396462633431316634623834646437646162360a626564313831373761636161656232
31623961393532666136616438633734366261353866383264323730383432326635626637343739 35316566336232666336646231356665366633303530623961666465366163306166623336656364
3235313062623637380a386235316437396534353261383832643165316565386263396664363962 3835353035333031620a633332376237336530343134623832363534383761616564616138363766
62393364333335373631356161373263313930343565626433383539373030363662353630633933 30306361383462353361636161636335313461313835663362393839623735313738316465656537
63336333613965653635313637336437653139616564313861336332323739653865383531356233 66396635323432376530346532353238346139376261366237343763373535623364633731323830
31373530343766343131346663656566363038643230343462336332323135323337353539303763 333730373965613131336166626230333263
33366638393064323431323636346161343936643062323861313766613264336465326132333631
33306666383561653965303539313366653030663330393363363565333439383133

View file

@ -1,6 +0,0 @@
$ANSIBLE_VAULT;1.1;AES256
38383539613238613864336630316433666436623334313334393762396536663530336264306661
3338616565316138616666343862366638643134343931320a633366363539326461346636373738
66393138653463663536313065623332383166386332303564323939336630333163623637386434
6538393966633731660a616437356233643234363562366433663437383439326161353330356331
63346432663036353332303266343361346266396437396131376531303265356233

View file

@ -1,6 +1,9 @@
$ANSIBLE_VAULT;1.1;AES256 $ANSIBLE_VAULT;1.1;AES256
30343638643335363463653231623566623961613534323261393639623865633964653634333562 61363033383536303833366237323662663236313163663033306138383162383062643830616466
3838613035393661656362383736313561366466396439390a383162366362643364636335613664 6531636430613462646161343939343363663533373737340a613433363666353432383463356439
39646137666437353762363764373562393736626530333336626261366232383063633732623238 33656266633131336565613433653062656563656637656464346232656238646339303961373265
6531633638366335640a363461383535646663316533386137323966326237373836363561323462 6639643637303433380a393163366331373964353261383662656664643031626432366231346332
66646635383137333834363165666365366235333734646364616637383363666239 34303964346137616233343930333331306363326332383465653163386539306430303965316437
30343333373565623431653436653832356366343937653136346535316166383262623730343831
62376532346237323465653261316339353034323633623632313630666531373839633665333637
34356162356565396564

205
services/authentik.nix Normal file
View file

@ -0,0 +1,205 @@
{ config, pkgs, home-manager-quadlet-nix, ... }:
let
user = "authentik";
state-directory = "/var/lib/authentik";
port = "9000";
in {
# Secrets are translated in the system NixOS scope, but performed by the user,
# via a user systemd unit, so are available in the user's Podman secrets
age.secrets = {
"authentik.toml" = {
file = ./../secrets/authentik.toml.age;
owner = "${user}";
};
};
millironx.podman-secrets.authentik = {
user = "${user}";
secrets-files = [ config.age.secrets."authentik.toml".path ];
};
# Podman, unlike Docker apparently, does not automatically create mount points
# within folders, so every mounted folder needs to be specified here.
systemd.tmpfiles.rules = [
"d ${state-directory} 1775 ${user} ${user} -"
"d ${state-directory}/database 1775 ${user} ${user} -"
"d ${state-directory}/media 1775 ${user} ${user} -"
"d ${state-directory}/certs 1775 ${user} ${user} -"
"d ${state-directory}/custom-templates 1775 ${user} ${user} -"
];
services.caddy.virtualHosts."auth.millironx.com".extraConfig = ''
reverse_proxy http://127.0.0.1:${port}
'';
services.borgmatic.configurations."${config.networking.hostName}" = {
source_directories = [
"${state-directory}/media"
"${state-directory}/certs"
"${state-directory}/custom-templates"
];
postgresql_databases = [{
name = "authentik";
psql_command =
"/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec authentik-db psql --username=${user}";
pg_dump_command =
"/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec authentik-db pg_dump --username=${user}";
pg_restore_command =
"/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec authentik-db pg_restore --username=${user}";
}];
};
# Create a dedicated user for this service
users.users."${user}" = {
# Group is technically not mandatory, but NixOS complains that an unset
# group is "unsafe." The group has to be declared below
group = "${user}";
# System users don't have a shell. For security purposes, that *would* be
# superior, but that means that, e.g. borgmatic can't `sudo` into the
# account to access Podman commands
isNormalUser = true;
# A home directory is mandatory in order to allow systemd user units to be
# created and run
home = "${state-directory}";
createHome = true;
# Settings for running containers while a login shell is not active
linger = true;
autoSubUidGidRange = true;
};
users.groups."${user}" = { };
home-manager.users."${user}" = { config, osConfig, ... }: {
imports = [ home-manager-quadlet-nix ];
home.stateVersion = "25.05";
virtualisation.quadlet = {
containers = {
authentik-db = {
autoStart = true;
containerConfig = {
image = "docker.io/library/postgres:16";
environments = {
POSTGRES_DB = "${user}";
POSTGRES_USER = "${user}";
};
secrets = [
# POSTGRES_PASSWORD is used by the container to setup the
# database, PGPASSWORD is used by pg_dump to authenticate for
# backup purposes
"AUTHENTIK_POSTGRESQL__PASSWORD,type=env,target=POSTGRES_PASSWORD"
"AUTHENTIK_POSTGRESQL__PASSWORD,type=env,target=PGPASSWORD"
];
# Double dollarsigns are required for use of *container* environment
# variables, Nix escaping creates the weird $\${} syntax
healthCmd = "pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}";
healthInterval = "30s";
healthRetries = 5;
healthStartPeriod = "20s";
# Volumes have to be bound with the :U label to allow for username
# remapping in rootless containers. :Z/:z is not needed b/c NixOS
# does not support SELinux
volumes =
[ "${state-directory}/database:/var/lib/postgresql/data:U" ];
# A network is actually required for these containers to talk to one
# another. I suppose the more idiomatic way would be for these
# related containers to be in a "pod," but I'm still struggling
# learning the idiosyncrasies of quadlet/rootless/podman, so we'll
# stick with this for now
networks =
[ config.virtualisation.quadlet.networks.authentik-net.ref ];
};
# Allowing this container to start before the secrets are translated
# will lead to errors. Use osConfig b/c secrets are declared in the
# system NixOS scope, even though it is a user process.
unitConfig.Requires =
[ osConfig.millironx.podman-secrets.authentik.ref ];
unitConfig.After =
[ osConfig.millironx.podman-secrets.authentik.ref ];
};
authentik-worker = {
autoStart = true;
containerConfig = {
image = "ghcr.io/goauthentik/server:2025.10.2";
environments = {
AUTHENTIK_POSTGRESQL__HOST = "authentik-db";
AUTHENTIK_POSTGRESQL__NAME = "${user}";
AUTHENTIK_POSTGRESQL__USER = "${user}";
};
exec = "worker";
secrets = [
"AUTHENTIK_POSTGRESQL__PASSWORD,type=env"
"AUTHENTIK_SECRET_KEY,type=env"
];
volumes = [
"${state-directory}/media:/media:U"
"${state-directory}/custom-templates:/templates:U"
"${state-directory}/certs:/certs:U"
];
networks =
[ config.virtualisation.quadlet.networks.authentik-net.ref ];
};
unitConfig.Requires =
[ config.virtualisation.quadlet.containers.authentik-db.ref ];
unitConfig.After =
[ config.virtualisation.quadlet.containers.authentik-db.ref ];
};
authentik = {
autoStart = true;
containerConfig = {
image = "ghcr.io/goauthentik/server:2025.10.2";
environments = {
AUTHENTIK_POSTGRESQL__HOST = "authentik-db";
AUTHENTIK_POSTGRESQL__NAME = "${user}";
AUTHENTIK_POSTGRESQL__USER = "${user}";
};
exec = "server";
secrets = [
"AUTHENTIK_POSTGRESQL__PASSWORD,type=env"
"AUTHENTIK_SECRET_KEY,type=env"
"AUTHENTIK_EMAIL__HOST,type=env"
"AUTHENTIK_EMAIL__PORT,type=env"
"AUTHENTIK_EMAIL__USERNAME,type=env"
"AUTHENTIK_EMAIL__PASSWORD,type=env"
"AUTHENTIK_EMAIL__USE_SSL,type=env"
"AUTHENTIK_EMAIL__FROM,type=env"
];
# Change from Traefik: publish ports to localhost only via 127.0.0.1
# and then reverse proxy to that port. Authentik does not appear to
# have a way to configure the port, so we will use the default of
# 9000 for non-secured traffic.
publishPorts = [ "127.0.0.1:${port}:${port}" ];
volumes = [
"${state-directory}/media:/media:U"
"${state-directory}/custom-templates:/templates:U"
];
networks =
[ config.virtualisation.quadlet.networks.authentik-net.ref ];
};
unitConfig.Requires =
[ config.virtualisation.quadlet.containers.authentik-db.ref ];
unitConfig.After =
[ config.virtualisation.quadlet.containers.authentik-db.ref ];
};
};
networks.authentik-net = { };
# One of the main advantages of using Quadlet
autoUpdate.enable = true;
};
};
}

35
services/borgmatic.nix Normal file
View file

@ -0,0 +1,35 @@
{ pkgs, config, ... }: {
# We don't want to expose the location where borg backups are going, so we
# will setup an encrypted ssh config that references the host/username
# combo as simply 'borgserver'
age.secrets = {
borgmatic-ssh-config = { file = ./../secrets/borgmatic-ssh-config.age; };
borgmatic-passphrase = { file = ./../secrets/borgmatic-passphrase.age; };
};
services.borgmatic = {
enable = true;
# This is the bare-bones way to get Borgmatic up and running. Other services
# are expected to declare their stateful directories by adding to
# `services.borgmatic.configurations."${config.networking.hostName}".source_directories`
# and to add their databases to
# `services.borgmatic.configurations."${config.networking.hostName}".[mariadb|postgresql|etc]_databases`
configurations."${config.networking.hostName}" = {
source_directories = [ "/home" "/root" ];
repositories = [{
label = "${config.networking.hostName}-default";
path = "ssh://borgserver/./repo";
}];
ssh_command =
"${pkgs.openssh}/bin/ssh -F ${config.age.secrets.borgmatic-ssh-config.path}";
encryption_passcommand =
"${pkgs.coreutils}/bin/cat ${config.age.secrets.borgmatic-passphrase.path}";
keep_daily = 7;
keep_weekly = 4;
keep_monthly = 6;
};
};
}

View file

@ -1,90 +1,49 @@
{ pkgs, config, ... }: { pkgs, config, ... }: {
let
crowdsec-url = "127.0.0.1:2763";
firewall-bouncer-name = "fw-bouncer";
# Although this key can be reproduced by anyone who actually cares to, the
# Crowdsec API will not be exposed to the outside world, so keeping this key
# super secret really isn't that important to me. Still make it look random
# so that hungry botnets can't just slurp up the password in plaintext.
firewall-bouncer-key = builtins.hashString "sha256"
"${config.networking.hostName}-crowdsec-bouncer-salt";
toMultiYAML = items:
pkgs.lib.concatMapStrings (item:
''
---
'' + (pkgs.lib.generators.toYAML { } item) + "\n") items;
in {
services = { services = {
crowdsec = { crowdsec = {
enable = true; enable = true;
settings = { localConfig = {
api.server = { listen_uri = crowdsec-url; }; acquisitions = [
allowLocalJournalAccess = true; {
crowdsec_service.acquisition_path = pkgs.writeText "acquisitions.yaml" source = "journalctl";
(toMultiYAML [ journalctl_filter = [ "_SYSTEMD_UNIT=sshd.service" ];
{ labels.type = "syslog";
source = "journalctl"; }
journalctl_filter = [ "_SYSTEMD_UNIT=sshd.service" ]; {
labels.type = "syslog"; filenames = [ "/var/log/auth.log" ];
} labels.type = "syslog";
{ }
filenames = [ "/var/log/auth.log" ]; {
labels.type = "syslog"; filenames = [ "/var/log/syslog" "/var/log/kern.log" ];
} labels.type = "syslog";
{ }
filenames = [ "/var/log/syslog" "/var/log/kern.log" ]; ];
labels.type = "syslog";
}
]);
}; };
hub = {
collections = [
"crowdsecurity/base-http-scenarios"
"crowdsecurity/http-cve"
"crowdsecurity/http-dos"
"crowdsecurity/iptables"
"crowdsecurity/linux"
"crowdsecurity/sshd"
"crowdsecurity/whitelist-good-actors"
];
};
settings = {
general = { api.server.enable = true; };
# See https://github.com/NixOS/nixpkgs/issues/445342
lapi.credentialsFile = "/var/lib/crowdsec/lapi-credentials.yaml";
};
autoUpdateService = true;
}; };
crowdsec-firewall-bouncer = { crowdsec-firewall-bouncer = {
enable = true; enable = true;
settings = { registerBouncer.enable = true;
api_url = firewall-bouncer-name;
api_key = firewall-bouncer-key;
};
}; };
}; };
systemd.services.crowdsec.serviceConfig = { systemd.tmpfiles.rules = let cfg = config.services.crowdsec;
ExecStartPre = let in [ "d /var/lib/crowdsec 0755 ${cfg.user} ${cfg.group}" ];
bouncer-script = pkgs.writeScriptBin "register-bouncer" ''
#!${pkgs.runtimeShell}
set -eu
set -o pipefail
if ! cscli bouncers list | grep -q "${firewall-bouncer-name}"; then
cscli bouncers add "${firewall-bouncer-name}" --key "${firewall-bouncer-key}"
fi
'';
collection-check = collection: ''
if ! cscli collections list | grep -q "${collection}"; then
cscli collections install "${collection}"
fi
'';
collections = [
"crowdsecurity/base-http-scenarios"
"crowdsecurity/http-cve"
"crowdsecurity/http-dos"
"crowdsecurity/iptables"
"crowdsecurity/linux"
"crowdsecurity/sshd"
"crowdsecurity/whitelist-good-actors"
];
collection-script = pkgs.writeScriptBin "install-collections" ''
#!${pkgs.runtimeShell}
set -eu
set -o pipefail
${pkgs.lib.concatMapStrings collection-check collections}
'';
in [
"${bouncer-script}/bin/register-bouncer"
"${collection-script}/bin/install-collections"
];
};
} }

146
services/freshrss.nix Normal file
View file

@ -0,0 +1,146 @@
{ config, pkgs, home-manager-quadlet-nix, ... }:
let
user = "freshrss";
port = "37374";
stateDirectory = "/var/lib/freshrss";
serviceContainer = "freshrss";
stateSubDir = subDir: "${stateDirectory}/${subDir}";
createTmpfilesRule = subDir: "d ${stateSubDir subDir} 1755 ${user} ${user}";
dbDirectories = [ "database" ];
serviceDirectories = [ "data" "extensions" ];
in {
age.secrets = {
"freshrss.toml" = {
file = ./../secrets/freshrss.toml.age;
owner = "${user}";
};
};
millironx.podman-secrets.freshrss = {
user = "${user}";
secrets-files = [ config.age.secrets."freshrss.toml".path ];
};
services.caddy.virtualHosts."feeds.millironx.com".extraConfig = ''
reverse_proxy http://127.0.0.1:${port} {
header_up X-Forwarded-Port 443
}
'';
systemd.tmpfiles.rules = builtins.map createTmpfilesRule
([ stateDirectory ] ++ dbDirectories ++ serviceDirectories);
services.borgmatic.configurations."${config.networking.hostName}" = {
source_directories = builtins.map stateSubDir dbDirectories;
postgresql_databases = [{
name = serviceContainer;
psql_command =
"/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${serviceContainer}-db psql --username=${user}";
pg_dump_command =
"/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${serviceContainer}-db pg_dump --username=${user}";
pg_restore_command =
"/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${serviceContainer}-db pg_restore --username=${user}";
}];
};
users.users."${user}" = {
group = "${user}";
isNormalUser = true;
home = "${stateDirectory}";
createHome = true;
linger = true;
autoSubUidGidRange = true;
};
users.groups."${user}" = { };
home-manager.users."${user}" = { config, osConfig, ... }: {
imports = [ home-manager-quadlet-nix ];
home.stateVersion = "25.05";
virtualisation.quadlet = let
inherit (config.virtualisation.quadlet) containers;
inherit (config.virtualisation.quadlet) networks;
secrets = osConfig.millironx.podman-secrets.freshrss;
in {
containers = {
"${serviceContainer}-db" = {
autoStart = true;
containerConfig = {
image = "docker.io/library/postgres:16";
environments = {
POSTGRES_DB = "${user}";
POSTGRES_USER = "${user}";
};
secrets = [
"POSTGRES_PASSWORD,type=env"
"POSTGRES_PASSWORD,type=env,target=PGPASSWORD"
];
healthCmd = "pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}";
healthInterval = "30s";
healthRetries = 5;
healthStartPeriod = "20s";
volumes =
[ "${stateDirectory}/database:/var/lib/postgresql/data:U" ];
networks = [ networks."${serviceContainer}".ref ];
};
unitConfig.Requires = [ secrets.ref ];
unitConfig.After = [ secrets.ref ];
};
"${serviceContainer}" = {
autoStart = true;
containerConfig = {
image = "docker.io/freshrss/freshrss:1";
# Required to allow the container to talk to the host ports, in
# other words, to resolve Authentik correctly
addHosts = [ "auth.millironx.com:host-gateway" ];
environments = {
TZ = osConfig.time.timeZone;
CRON_MIN = "2,32";
LISTEN = "0.0.0.0:${port}";
TRUSTED_PROXY = "172.16.0.1/12 192.168.0.1/16";
OIDC_ENABLED = "1";
OIDC_PROVIDER_METADATA_URL =
"https://auth.millironx.com/application/o/freshrss/.well-known/openid-configuration";
OIDC_REMOTE_USER_CLAIM = "preferred_username";
OIDC_SCOPES = "openid email profile";
OIDC_X_FORWARDED_HEADERS =
"X-Forwarded-Host X-Forwarded-Port X-Forwarded-Proto";
};
secrets = [
"OIDC_CLIENT_ID,type=env"
"OIDC_CLIENT_SECRET,type=env"
"OIDC_CLIENT_CRYPTO_KEY,type=env"
];
healthCmd = "cli/health.php";
healthTimeout = "10s";
healthStartPeriod = "60s";
healthStartupInterval = "11s";
healthInterval = "75s";
healthRetries = 3;
networks = [ networks."${serviceContainer}".ref ];
publishPorts = [ "127.0.0.1:${port}:${port}" ];
volumes = [
"${stateDirectory}/data:/var/www/FreshRSS/data:U"
"${stateDirectory}/extensions:/var/www/FreshRSS/extensions:U"
];
};
unitConfig.Requires =
[ secrets.ref containers."${serviceContainer}-db".ref ];
unitConfig.After =
[ secrets.ref containers."${serviceContainer}-db".ref ];
};
};
networks."${serviceContainer}" = { };
autoUpdate.enable = true;
autoEscape = true;
};
};
}

View file

@ -1,50 +0,0 @@
# This file is designed to be used in the imports
{ pkgs, config, ... }:
{
environment.systemPackages = [
(pkgs.writeScriptBin "update-nixos" ''
#!${pkgs.bash}/bin/bash
echo "Requesting system update..."
${pkgs.systemd}/bin/systemctl start nixos-update.service
'')
];
# Service to update NixOS configuration from git repo
systemd.services."nixos-update" = {
description = "Update NixOS configuration from git repository";
path = with pkgs; [ coreutils ];
script = ''
# Rebuild the system directly from the remote flake
${pkgs.nixos-rebuild}/bin/nixos-rebuild switch --flake git+https://code.millironx.com/millironx/nix-dotfiles.git#${config.networking.hostName}
'';
serviceConfig = {
Type = "oneshot";
User = "root";
};
};
# Timer to run the update service daily at 3am
systemd.timers."nixos-update" = {
wantedBy = [ "timers.target" ];
description = "Run NixOS update daily at 3am";
timerConfig = {
OnCalendar = "3:00";
Persistent = true;
Unit = "nixos-update.service";
};
};
# Polkit rule to allow non-root users to trigger the update
security.polkit.extraConfig = ''
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "nixos-update.service" &&
action.lookup("verb") == "start" &&
subject.isInGroup("wheel")) {
return polkit.Result.YES;
}
});
'';
}

View file

@ -1,27 +0,0 @@
{ config, ... }:
{
age.secrets = {
pihole-credentials = {
file = ./../secrets/pihole.age;
owner = "root";
group = "root";
};
};
virtualisation = {
quadlet = {
containers = {
pihole = {
containerConfig = {
image = "docker.io/pihole/pihole:2025.06.2";
publishPorts =
[ "53:53/tcp" "53:53/udp" "80:80/tcp" "443:443/tcp" ];
environmentFiles = [ config.age.secrets.pihole-credentials.path ];
networks = [ "bridge" ];
dns = [ "127.0.0.1" "194.242.2.9" "9.9.9.9" ];
};
};
};
};
};
}

View file

@ -2,7 +2,6 @@
services.samba = { services.samba = {
enable = true; enable = true;
package = pkgs.sambaFull; package = pkgs.sambaFull;
securityType = "user";
openFirewall = true; openFirewall = true;
settings = { settings = {
global = { global = {

View file

@ -15,6 +15,8 @@ in {
rig-install rig-install
]; ];
age.secrets.firefox-policy.file = ./../../secrets/darwin-policies-json.age;
# Use a custom configuration.nix location. # Use a custom configuration.nix location.
# $ darwin-rebuild switch -I darwin-config=$HOME/.config/nixpkgs/darwin/configuration.nix # $ darwin-rebuild switch -I darwin-config=$HOME/.config/nixpkgs/darwin/configuration.nix
environment.darwinConfig = "$HOME/.config/home-manager/configuration.nix"; environment.darwinConfig = "$HOME/.config/home-manager/configuration.nix";
@ -24,9 +26,27 @@ in {
}; };
# Auto upgrade nix package and the daemon service. # Auto upgrade nix package and the daemon service.
nix.enable = true; nix = {
#services.nix-daemon.tempDir = "/nix/tmp"; enable = true;
nix.package = pkgs.nix; gc = {
automatic = true;
interval = { Weekday = 1; };
options = ''
--delete-older-than 14d
'';
};
# Needed for rosetta-builder, see
# <https://github.com/cpick/nix-rosetta-builder/issues/40#issuecomment-3368602687>
# <https://github.com/cpick/nix-rosetta-builder/issues/37>
linux-builder = {
enable = true;
ephemeral = true;
};
extraOptions = ''
extra-platforms = x86_64-darwin
'';
};
nix-rosetta-builder.onDemand = true;
# Create /etc/zshrc that loads the nix-darwin environment. # Create /etc/zshrc that loads the nix-darwin environment.
programs.zsh.enable = true; # default shell on catalina programs.zsh.enable = true; # default shell on catalina
@ -71,11 +91,12 @@ in {
in [ in [
(sysApp "Firefox") (sysApp "Firefox")
(sysApp "Thunderbird") (sysApp "Thunderbird")
(sysApp "Logseq") (sysApp "Microsoft Outlook")
(sysApp "Zed") (sysApp "Zed")
(sysApp "Logseq")
(sysApp "Steam") (sysApp "Steam")
(chromeApp "Instinct Dashboard") (localApp "Instinct Dashboard")
(chromeApp "Carestream") (localApp "Carestream")
]; ];
show-process-indicators = true; show-process-indicators = true;
show-recents = false; show-recents = false;
@ -130,6 +151,11 @@ in {
--user=${config.system.primaryUser} \ --user=${config.system.primaryUser} \
--set-home \ --set-home \
_rig-install ${r-version} _rig-install ${r-version}
echo "Applying custom defaults..."
/usr/bin/defaults import \
/Library/Preferences/org.mozilla.firefox \
${config.age.secrets.firefox-policy.path}
''; '';
nix.settings.experimental-features = [ "nix-command" "flakes" ]; nix.settings.experimental-features = [ "nix-command" "flakes" ];
@ -177,23 +203,18 @@ in {
"docker" "docker"
"docker-buildx" "docker-buildx"
"docker-credential-helper" "docker-credential-helper"
"firefoxpwa"
"mpv" "mpv"
]; ];
casks = [ casks = [
"alt-tab" "alt-tab"
"anki"
"db-browser-for-sqlite" "db-browser-for-sqlite"
"dolphin" "dolphin"
"firefox" "firefox"
"freetube" "freetube"
"ghostty"
"inkscape" "inkscape"
"iterm2" "iterm2"
"logi-options+"
"logseq" "logseq"
"macfuse" "macfuse"
"musescore"
"nextcloud" "nextcloud"
"openrct2" "openrct2"
"qownnotes" "qownnotes"
@ -201,6 +222,7 @@ in {
"rig" "rig"
"rstudio" "rstudio"
"signal" "signal"
"skim"
"slack" "slack"
"stats" "stats"
"steam" "steam"
@ -210,6 +232,7 @@ in {
"ungoogled-chromium" "ungoogled-chromium"
"veracrypt" "veracrypt"
"vlc" "vlc"
"vienna"
"vorta" "vorta"
"zed" "zed"
"zotero" "zotero"

View file

@ -8,9 +8,7 @@
imports = [ imports = [
./hardware-configuration/bosephus.nix ./hardware-configuration/bosephus.nix
./hardware-configuration/bosephus-external-drives.nix ./hardware-configuration/bosephus-external-drives.nix
./../../services/nixos-update.nix
./../../services/samba.nix ./../../services/samba.nix
./../../services/pihole.nix
]; ];
# Bootloader. # Bootloader.
@ -18,8 +16,8 @@
boot.loader.efi.canTouchEfiVariables = true; boot.loader.efi.canTouchEfiVariables = true;
# Ignore lid - so I can close without having the system go into sleep mode # Ignore lid - so I can close without having the system go into sleep mode
services.logind.lidSwitch = "ignore"; services.logind.settings.Login.HandleLidSwitch = "ignore";
services.logind.lidSwitchDocked = "ignore"; services.logind.settings.Login.HandleLidSwitchDocked = "ignore";
# Secrets # Secrets
age.secrets = { age.secrets = {

View file

@ -3,8 +3,11 @@
{ {
imports = [ # Include the results of the hardware scan. imports = [ # Include the results of the hardware scan.
./hardware-configuration/mcentire.nix ./hardware-configuration/mcentire.nix
./../../services/nixos-update.nix ./../../modules/podman-secrets.nix
./../../services/borgmatic.nix
./../../services/crowdsec.nix ./../../services/crowdsec.nix
./../../services/authentik.nix
./../../services/freshrss.nix
]; ];
# Use the GRUB 2 boot loader. # Use the GRUB 2 boot loader.
@ -15,6 +18,7 @@
useDHCP = false; useDHCP = false;
interfaces.eth0.useDHCP = true; interfaces.eth0.useDHCP = true;
hostName = "mcentire"; # Define your hostname. hostName = "mcentire"; # Define your hostname.
firewall.allowedTCPPorts = [ 80 443 ];
}; };
# Set your time zone. # Set your time zone.
@ -40,7 +44,7 @@
millironx = { millironx = {
isNormalUser = true; isNormalUser = true;
description = "Thomas A. Christensen II"; description = "Thomas A. Christensen II";
extraGroups = [ "wheel" ]; extraGroups = [ "adm" "wheel" ];
}; };
}; };
@ -54,8 +58,15 @@
services = { services = {
openssh.enable = true; openssh.enable = true;
tailscale.enable = true; tailscale.enable = true;
caddy.enable = true;
# Do not "enable" database services, but include the package configuration
# so that borgmatic does not freak out about unset variables
postgresql.package = pkgs.postgresql_17;
}; };
virtualisation.quadlet.enable = true;
system.stateVersion = "25.05"; # Did you read the comment? system.stateVersion = "25.05"; # Did you read the comment?
nix = { extraOptions = "experimental-features = nix-command flakes"; }; nix = { extraOptions = "experimental-features = nix-command flakes"; };
} }