Add Rupert’s configuration
This commit is contained in:
commit
2b4264d32d
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
configuration.nix
|
||||||
|
hardware-configuration.nix
|
||||||
|
result
|
||||||
|
personal.nix
|
10
base/default.nix
Normal file
10
base/default.nix
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./xkb
|
||||||
|
./neovim.nix
|
||||||
|
./packages.nix
|
||||||
|
./users.nix
|
||||||
|
./locale.nix
|
||||||
|
];
|
||||||
|
}
|
10
base/locale.nix
Normal file
10
base/locale.nix
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{ pkgs, lib, ... }:
|
||||||
|
{
|
||||||
|
time.timeZone = "Europe/Berlin";
|
||||||
|
|
||||||
|
i18n.defaultLocale = "en_GB.UTF-8";
|
||||||
|
console = {
|
||||||
|
font = "Lat2-Terminus16";
|
||||||
|
keyMap = "de";
|
||||||
|
};
|
||||||
|
}
|
134
base/neovim-init.vim
Normal file
134
base/neovim-init.vim
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
set nocompatible
|
||||||
|
set backspace=indent,eol,start
|
||||||
|
syntax enable
|
||||||
|
set mouse=a
|
||||||
|
set mousemodel=extend
|
||||||
|
set title
|
||||||
|
let g:airline_theme='term_light'
|
||||||
|
|
||||||
|
filetype plugin on
|
||||||
|
filetype indent on
|
||||||
|
|
||||||
|
" Enable spell check for commit messages
|
||||||
|
autocmd FileType gitcommit setlocal spell spelllang=en_gb
|
||||||
|
|
||||||
|
" Use spaces instead of tabs
|
||||||
|
set expandtab
|
||||||
|
|
||||||
|
" Be smart when using tabs ;)
|
||||||
|
set smarttab
|
||||||
|
|
||||||
|
" 1 tab == 4 spaces
|
||||||
|
set shiftwidth=4
|
||||||
|
set tabstop=4
|
||||||
|
|
||||||
|
set ai "Auto indent
|
||||||
|
set si "Smart indent
|
||||||
|
set wrap "Wrap lines
|
||||||
|
|
||||||
|
set nobackup
|
||||||
|
set nowb
|
||||||
|
set noswapfile
|
||||||
|
|
||||||
|
" Set to auto read when a file is changed from the outside
|
||||||
|
set autoread
|
||||||
|
|
||||||
|
|
||||||
|
" Leader
|
||||||
|
let mapleader = ","
|
||||||
|
let g:mapleader = ","
|
||||||
|
|
||||||
|
" Fast saving
|
||||||
|
nmap <leader>w :w!<cr>
|
||||||
|
|
||||||
|
" Save and start shell
|
||||||
|
nmap <leader># :w!<cr>:te<cr>i
|
||||||
|
"tnoremap <ESC> <C-\><C-n>:buffer #<CR>
|
||||||
|
tnoremap <C-c> <C-\><C-n>:buffer #<CR>
|
||||||
|
"autocmd TermClose * bd! " quit when a terminal closes instead of showing exit code and waiting
|
||||||
|
|
||||||
|
" Highlight search results
|
||||||
|
set hlsearch
|
||||||
|
" Makes search act like search in modern browsers
|
||||||
|
set incsearch
|
||||||
|
|
||||||
|
" Smart case when searching
|
||||||
|
set ignorecase
|
||||||
|
set smartcase
|
||||||
|
|
||||||
|
" Show results of pattern matching/replacing while typing
|
||||||
|
set inccommand=split
|
||||||
|
|
||||||
|
" When you press <leader>r you can search and replace the selected text
|
||||||
|
vnoremap <silent> <leader>r :call VisualSelection('replace')<CR>
|
||||||
|
|
||||||
|
" Disable highlight when <leader><cr> is pressed
|
||||||
|
map <silent> <leader><cr> :noh<cr>
|
||||||
|
|
||||||
|
" For regular expressions turn magic on
|
||||||
|
set magic
|
||||||
|
|
||||||
|
" Visual mode pressing * or # searches for the current selection
|
||||||
|
" Super useful! From an idea by Michael Naumann
|
||||||
|
vnoremap <silent> * :call VisualSelection('f')<CR>
|
||||||
|
vnoremap <silent> # :call VisualSelection('b')<CR>
|
||||||
|
|
||||||
|
" Show matching brackets when text indicator is over them
|
||||||
|
set showmatch
|
||||||
|
" How many tenths of a second to blink when matching brackets
|
||||||
|
set mat=2
|
||||||
|
|
||||||
|
" Spell checking
|
||||||
|
map <leader>ss :setlocal spell! spelllang=de_20<cr>
|
||||||
|
map <leader>se :setlocal spell! spelllang=en-curly_gb<cr>
|
||||||
|
map <leader>su :setlocal spell! spelllang=en-curly_us<cr>
|
||||||
|
|
||||||
|
" Treat long lines as break lines (useful when moving around in them)
|
||||||
|
map j gj
|
||||||
|
map k gk
|
||||||
|
|
||||||
|
" Smart way to move between windows
|
||||||
|
map <C-j> <C-W>j
|
||||||
|
map <C-k> <C-W>k
|
||||||
|
map <C-h> <C-W>h
|
||||||
|
map <C-l> <C-W>l
|
||||||
|
|
||||||
|
" More natural behaviour when splitting
|
||||||
|
set splitbelow
|
||||||
|
set splitright
|
||||||
|
|
||||||
|
" Useful mappings for managing tabs
|
||||||
|
map <leader>tn :tabnew<cr>
|
||||||
|
map <leader>to :tabonly<cr>
|
||||||
|
map <leader>tc :tabclose<cr>
|
||||||
|
map <leader>tm :tabmove
|
||||||
|
|
||||||
|
" Jump to particular tab directly
|
||||||
|
noremap <leader>1 1gt
|
||||||
|
noremap <leader>2 2gt
|
||||||
|
noremap <leader>3 3gt
|
||||||
|
noremap <leader>4 4gt
|
||||||
|
noremap <leader>5 5gt
|
||||||
|
noremap <leader>6 6gt
|
||||||
|
noremap <leader>7 7gt
|
||||||
|
noremap <leader>8 8gt
|
||||||
|
noremap <leader>9 9gt
|
||||||
|
noremap <leader>0 :tablast<cr>
|
||||||
|
|
||||||
|
" Switch CWD to the directory of the open buffer
|
||||||
|
map <leader>cd :cd %:p:h<cr>:pwd<cr>
|
||||||
|
|
||||||
|
" Remember info about open buffers on close
|
||||||
|
set viminfo^=%
|
||||||
|
|
||||||
|
" Toggle paste mode on and off
|
||||||
|
map <leader>pp :setlocal paste!<cr>
|
||||||
|
|
||||||
|
" Save and make
|
||||||
|
nnoremap <leader>m :wa <BAR> :Make<CR>
|
||||||
|
|
||||||
|
hi ColorColumn ctermbg=47
|
||||||
|
|
||||||
|
let g:vimtex_compiler_enabled = 0
|
||||||
|
|
||||||
|
let g:local_vimrc = {'names': ['.local.vimrc'], 'hash_fun': 'LVRHashOfFile'}
|
28
base/neovim.nix
Normal file
28
base/neovim.nix
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
programs.neovim = {
|
||||||
|
enable = true;
|
||||||
|
vimAlias = true;
|
||||||
|
viAlias = true;
|
||||||
|
defaultEditor = true;
|
||||||
|
configure = {
|
||||||
|
customRC = (builtins.readFile ./neovim-init.vim);
|
||||||
|
packages.myVimPackage = with pkgs.vimPlugins; {
|
||||||
|
start = [
|
||||||
|
vim-lastplace
|
||||||
|
direnv-vim
|
||||||
|
vim-addon-local-vimrc
|
||||||
|
vim-nix
|
||||||
|
vim-airline
|
||||||
|
vim-airline-themes
|
||||||
|
vim-colorschemes
|
||||||
|
changeColorScheme-vim
|
||||||
|
vim-dispatch
|
||||||
|
vimtex
|
||||||
|
suda-vim
|
||||||
|
];
|
||||||
|
opt = [];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
46
base/packages.nix
Normal file
46
base/packages.nix
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
{
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
direnv nix-direnv
|
||||||
|
tmux zellij
|
||||||
|
wget
|
||||||
|
rsync
|
||||||
|
git
|
||||||
|
gnupg
|
||||||
|
file
|
||||||
|
ripgrep
|
||||||
|
fd
|
||||||
|
htop
|
||||||
|
ncdu
|
||||||
|
ranger nnn joshuto
|
||||||
|
hexyl
|
||||||
|
rink
|
||||||
|
|
||||||
|
kitty
|
||||||
|
kitty-themes
|
||||||
|
] ++ lib.optionals config.services.xserver.enable [
|
||||||
|
wine
|
||||||
|
pavucontrol
|
||||||
|
xsensors
|
||||||
|
|
||||||
|
kitty
|
||||||
|
kitty-themes
|
||||||
|
|
||||||
|
firefox
|
||||||
|
ungoogled-chromium
|
||||||
|
|
||||||
|
zathura
|
||||||
|
gthumb
|
||||||
|
vlc
|
||||||
|
|
||||||
|
feh
|
||||||
|
xsel
|
||||||
|
];
|
||||||
|
|
||||||
|
fonts.fonts = with pkgs; [
|
||||||
|
vollkorn
|
||||||
|
alegreya alegreya-sans
|
||||||
|
b612
|
||||||
|
raleway
|
||||||
|
];
|
||||||
|
}
|
19
base/users.nix
Normal file
19
base/users.nix
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{ pkgs, lib, ... }:
|
||||||
|
let
|
||||||
|
definedInPersonalDotNix = lib.mkDefault (throw "Configuration option missing from personal.nix");
|
||||||
|
in
|
||||||
|
{
|
||||||
|
users.users = {
|
||||||
|
fruchti = {
|
||||||
|
isNormalUser = true;
|
||||||
|
extraGroups = [ "wheel" "networkmanager" "audio" "video" ];
|
||||||
|
openssh.authorizedKeys.keys = definedInPersonalDotNix;
|
||||||
|
shell = pkgs.fish;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
users.extraGroups = {
|
||||||
|
system = {
|
||||||
|
members = [ "fruchti" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
16
base/xkb/default.nix
Normal file
16
base/xkb/default.nix
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
services.xserver.layout = "us-fruchti";
|
||||||
|
services.xserver.extraLayouts = {
|
||||||
|
de-fruchti = {
|
||||||
|
description = "DE layout with some small changes";
|
||||||
|
languages = [ "deu" ];
|
||||||
|
symbolsFile = ./symbols/de-fruchti;
|
||||||
|
};
|
||||||
|
us-fruchti = {
|
||||||
|
description = "US-altgr-intl layout with some small changes";
|
||||||
|
languages = [ "eng" ];
|
||||||
|
symbolsFile = ./symbols/us-fruchti;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
8
base/xkb/symbols/de-fruchti
Normal file
8
base/xkb/symbols/de-fruchti
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
xkb_symbols "de-fruchti"
|
||||||
|
{
|
||||||
|
include "de(basic)"
|
||||||
|
|
||||||
|
// Swap insert/print screen
|
||||||
|
key <PRSC> { [ Insert ] };
|
||||||
|
key <INS> { [ Print ] };
|
||||||
|
};
|
44
base/xkb/symbols/us-fruchti
Normal file
44
base/xkb/symbols/us-fruchti
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
partial alphanumeric_keys
|
||||||
|
xkb_symbols "us-fruchti" {
|
||||||
|
include "us(altgr-intl)"
|
||||||
|
name[Group1]="English (intl., with AltGr dead keys, customised)";
|
||||||
|
|
||||||
|
key <AC02> {
|
||||||
|
// Change: Replace section with U1E9E (capital sharp s)
|
||||||
|
[ s, S, ssharp, U1E9E ]
|
||||||
|
};
|
||||||
|
key <AC04> {
|
||||||
|
// Change: Replace f with U017F (long s)
|
||||||
|
// Change: Replace F with section
|
||||||
|
[ f, F, U017F, section ]
|
||||||
|
};
|
||||||
|
key <AC05> {
|
||||||
|
// Change: replace g with doublelowquotemark
|
||||||
|
// Change: replace G with singlelowquotemark
|
||||||
|
[ g, G, doublelowquotemark, singlelowquotemark ]
|
||||||
|
};
|
||||||
|
key <AC06> {
|
||||||
|
// Change: replace h with leftdoublequotemark
|
||||||
|
// Change: replace H with leftsinglequotemark
|
||||||
|
[ h, H, leftdoublequotemark, leftsinglequotemark ]
|
||||||
|
};
|
||||||
|
key <AC08> {
|
||||||
|
// oe/OE are already available with AltGr+(Shift+)X
|
||||||
|
// Change: Replace oe with endash
|
||||||
|
// Change: Replace OE with emdash
|
||||||
|
[ k, K, endash, emdash ]
|
||||||
|
};
|
||||||
|
key <AB05> {
|
||||||
|
// Change: Replace b with U2026 (ellipsis)
|
||||||
|
// Change: Replace B with Greek_OMEGA
|
||||||
|
[ b, B, U2026, Greek_OMEGA ]
|
||||||
|
};
|
||||||
|
key <AB07> {
|
||||||
|
// Change: Replace mu with endash
|
||||||
|
[ m, M, mu, endash ]
|
||||||
|
};
|
||||||
|
key <SPCE> {
|
||||||
|
// Change: Add thinspace for AltGr+Space
|
||||||
|
[ space, space, U2009, nobreakspace ]
|
||||||
|
};
|
||||||
|
};
|
119
hosts/Rupert.nix
Normal file
119
hosts/Rupert.nix
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
definedInPersonalDotNix = lib.mkDefault (throw "Configuration option missing from personal.nix");
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./nextcloud.nix
|
||||||
|
./dyndns.nix
|
||||||
|
./adguard.nix
|
||||||
|
./mpd.nix
|
||||||
|
./burp-server.nix
|
||||||
|
./hedgedoc.nix
|
||||||
|
./transcode.nix
|
||||||
|
./development.nix
|
||||||
|
./bspwm.nix
|
||||||
|
|
||||||
|
# ./open-pgsql.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
users.users = {
|
||||||
|
waldi = {
|
||||||
|
isNormalUser = true;
|
||||||
|
extraGroups = [ "audio" ];
|
||||||
|
shell = pkgs.fish;
|
||||||
|
openssh.authorizedKeys.keys = definedInPersonalDotNix;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
users.extraGroups = {
|
||||||
|
pulse-access = {
|
||||||
|
members = [ "waldi" "fruchti" ];
|
||||||
|
};
|
||||||
|
music = {
|
||||||
|
members = [ "fruchti" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
ntfsprogs
|
||||||
|
texlive.combined.scheme-full
|
||||||
|
ncmpcpp
|
||||||
|
];
|
||||||
|
|
||||||
|
services.burp.client = {
|
||||||
|
enable = true;
|
||||||
|
password = config.services.burp.server.clients."${config.networking.hostName}".password;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Flatpak
|
||||||
|
services.flatpak.enable = true;
|
||||||
|
xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
|
||||||
|
xdg.portal.enable = true;
|
||||||
|
|
||||||
|
hardware.bluetooth = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Some programs need SUID wrappers, can be configured further or are
|
||||||
|
# started in user sessions.
|
||||||
|
# programs.mtr.enable = true;
|
||||||
|
programs.gnupg.agent = {
|
||||||
|
enable = true;
|
||||||
|
enableSSHSupport = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# List services that you want to enable:
|
||||||
|
|
||||||
|
# Enable the OpenSSH daemon.
|
||||||
|
services.openssh = {
|
||||||
|
enable = true;
|
||||||
|
forwardX11 = true;
|
||||||
|
passwordAuthentication = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.avahi.enable = true;
|
||||||
|
networking.firewall.allowedTCPPorts = [
|
||||||
|
22
|
||||||
|
1935 # RTMP
|
||||||
|
4971 # BURP
|
||||||
|
];
|
||||||
|
|
||||||
|
# Copy the NixOS configuration file and link it from the resulting system
|
||||||
|
# (/run/current-system/configuration.nix). This is useful in case you
|
||||||
|
# accidentally delete configuration.nix.
|
||||||
|
# system.copySystemConfiguration = true;
|
||||||
|
|
||||||
|
system.autoUpgrade.enable = true;
|
||||||
|
system.autoUpgrade.allowReboot = false;
|
||||||
|
system.autoUpgrade.sendEmail = true;
|
||||||
|
# systemd.services.nixos-upgrade.onFailure = lib.mkIf config.system.autoUpgrade.enable [ "status-email@%n.service" ];
|
||||||
|
|
||||||
|
nix.gc = {
|
||||||
|
automatic = true;
|
||||||
|
dates = "weekly";
|
||||||
|
options = "--delete-older-than 30d";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.btrfsScrub = {
|
||||||
|
enable = true;
|
||||||
|
paths = {
|
||||||
|
"/" = {
|
||||||
|
onCalendar = "*-*-* 02:00:00";
|
||||||
|
};
|
||||||
|
"/data" = {
|
||||||
|
onCalendar = "Thu *-*-* 02:00:00";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
security.acme = {
|
||||||
|
defaults = {
|
||||||
|
email = config.email.adminEmail;
|
||||||
|
};
|
||||||
|
acceptTerms = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.udev.extraRules = ''
|
||||||
|
SUBSYSTEM=="video4linux", ATTRS{idProduct}=="0002", ATTRS{idVendor}=="1d6b", SYMLINK+="hdmi_capture"
|
||||||
|
'';
|
||||||
|
}
|
28
hosts/adguard.nix
Normal file
28
hosts/adguard.nix
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
|
services.adguardhome = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx = {
|
||||||
|
enable = true;
|
||||||
|
virtualHosts = {
|
||||||
|
"ad.guard" = {
|
||||||
|
listenAddresses = [ "0.0.0.0" "[::]" ];
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://localhost:5380";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedUDPPorts = [ 53 67 68 ];
|
||||||
|
|
||||||
|
# Capabilities for DHCP server
|
||||||
|
systemd.services.adguardhome.serviceConfig.AmbientCapabilities = [ "CAP_NET_RAW" ];
|
||||||
|
|
||||||
|
systemd.services."adguardhome" = {
|
||||||
|
# requires = ["dhcpcd.service"];
|
||||||
|
after = ["dhcpcd.service"];
|
||||||
|
};
|
||||||
|
}
|
22
hosts/bspwm.nix
Normal file
22
hosts/bspwm.nix
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
|
services.xserver = {
|
||||||
|
enable = true;
|
||||||
|
windowManager.bspwm.enable = true;
|
||||||
|
displayManager = {
|
||||||
|
defaultSession = "none+bspwm";
|
||||||
|
lightdm.enable = true;
|
||||||
|
autoLogin.enable = true;
|
||||||
|
autoLogin.user = "waldi";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.unclutter-xfixes = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
rofi
|
||||||
|
ranger
|
||||||
|
];
|
||||||
|
}
|
38
hosts/burp-server.nix
Normal file
38
hosts/burp-server.nix
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
let
|
||||||
|
definedInPersonalDotNix = lib.mkDefault (throw "Configuration option missing from personal.nix");
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.burp.server = {
|
||||||
|
enable = true;
|
||||||
|
dataDirectory = "/data/burp";
|
||||||
|
sslKeyPassword = definedInPersonalDotNix;
|
||||||
|
workingDirRecoveryMethod = "resume";
|
||||||
|
maxResumeAttempts = 3;
|
||||||
|
keep = [ 14 4 6 2 ];
|
||||||
|
clients = {
|
||||||
|
${config.networking.hostName} = {
|
||||||
|
password = definedInPersonalDotNix;
|
||||||
|
};
|
||||||
|
Pullach = {
|
||||||
|
password = definedInPersonalDotNix;
|
||||||
|
};
|
||||||
|
Disco = {
|
||||||
|
password = definedInPersonalDotNix;
|
||||||
|
};
|
||||||
|
Berthold = {
|
||||||
|
password = definedInPersonalDotNix;
|
||||||
|
};
|
||||||
|
Ernesto = {
|
||||||
|
password = definedInPersonalDotNix;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
superClients = [
|
||||||
|
config.networking.hostName
|
||||||
|
];
|
||||||
|
timerArgs = [
|
||||||
|
"20h"
|
||||||
|
"Mon,Tue,Wed,Thu,Fri,Sat,Sun,00,01,02,03,04,05,06,07,08,17,18,19,20,21,22,23"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
14
hosts/development.nix
Normal file
14
hosts/development.nix
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
picocom
|
||||||
|
usbutils # lsusb etc.
|
||||||
|
binwalk
|
||||||
|
];
|
||||||
|
|
||||||
|
users.extraGroups = {
|
||||||
|
plugdev = {
|
||||||
|
members = [ "fruchti" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
54
hosts/dyndns.nix
Normal file
54
hosts/dyndns.nix
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
let
|
||||||
|
definedInPersonalDotNix = lib.mkDefault (throw "Configuration option missing from personal.nix");
|
||||||
|
getipv6 = pkgs.writeText "getipv6.sh" ''
|
||||||
|
${pkgs.nettools}/bin/ifconfig enp3s0 | sed -n -E 's/^\ *inet6 (2001(:[0-9a-f]+)+)\ .*$/\1/p'
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
networking.tempAddresses = "disabled";
|
||||||
|
# networking.interfaces.enp3s0 = {
|
||||||
|
# tempAddress = "disabled";
|
||||||
|
# ipv4.addresses = [{
|
||||||
|
# address = "192.168.178.43";
|
||||||
|
# prefixLength = 24;
|
||||||
|
# }];
|
||||||
|
# };
|
||||||
|
networking.defaultGateway = "192.168.178.1";
|
||||||
|
networking.nameservers = [ "9.9.9.9" "8.8.8.8" ];
|
||||||
|
|
||||||
|
networking.dhcpcd = {
|
||||||
|
enable = true;
|
||||||
|
persistent = true;
|
||||||
|
extraConfig = ''
|
||||||
|
duid
|
||||||
|
vendorclassid
|
||||||
|
slaac hwaddr
|
||||||
|
noipv4ll
|
||||||
|
#ia_pd 1 internal
|
||||||
|
|
||||||
|
interface enp3s0
|
||||||
|
static ip_address=192.168.178.43/24
|
||||||
|
static routers=192.168.178.1
|
||||||
|
static domain_name_servers=192.168.178.1 8.8.8.8
|
||||||
|
|
||||||
|
ia_pd
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
services.ddclient = {
|
||||||
|
enable = true;
|
||||||
|
verbose = true;
|
||||||
|
use = "cmd, cmd='${pkgs.bash}/bin/bash ${getipv6}'";
|
||||||
|
domains = [
|
||||||
|
((lib.toLower config.networking.hostName) + ".gvfr.de")
|
||||||
|
];
|
||||||
|
ipv6 = true;
|
||||||
|
server = definedInPersonalDotNix;
|
||||||
|
username = definedInPersonalDotNix;
|
||||||
|
passwordFile = "/secrets/dyndns_password_${config.services.ddclient.username}.txt";
|
||||||
|
extraConfig = ''
|
||||||
|
wildcard=no
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
79
hosts/hedgedoc.nix
Normal file
79
hosts/hedgedoc.nix
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
domain = "md.gvfr.de";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.hedgedoc = {
|
||||||
|
enable = true;
|
||||||
|
workDir = "/data/hedgedoc";
|
||||||
|
settings = {
|
||||||
|
port = 7000;
|
||||||
|
domain = domain;
|
||||||
|
protocolUseSSL = true;
|
||||||
|
uploadsPath = "/data/hedgedoc/uploads";
|
||||||
|
allowGravatar = false;
|
||||||
|
db = {
|
||||||
|
dialect = "postgres";
|
||||||
|
host = "/run/postgresql";
|
||||||
|
username = "hedgedoc";
|
||||||
|
database = "hedgedoc";
|
||||||
|
};
|
||||||
|
allowAnonymous = false;
|
||||||
|
allowAnonymousEdits = true;
|
||||||
|
csp = {
|
||||||
|
enable = true;
|
||||||
|
directives = {
|
||||||
|
scriptSrc = "gvfr.de";
|
||||||
|
};
|
||||||
|
upgradeInsecureRequest = "auto";
|
||||||
|
addDefaults = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
allowEmailRegister = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.postgresql = {
|
||||||
|
enable = true;
|
||||||
|
ensureUsers = [
|
||||||
|
{
|
||||||
|
name = "hedgedoc";
|
||||||
|
ensurePermissions = {
|
||||||
|
"DATABASE hedgedoc" = "ALL PRIVILEGES";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ensureDatabases = [ "hedgedoc" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx = {
|
||||||
|
enable = true;
|
||||||
|
virtualHosts.${domain} = {
|
||||||
|
listenAddresses = [ "0.0.0.0" "[::]" ];
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
locations = {
|
||||||
|
"/" = {
|
||||||
|
proxyPass = "http://localhost:7000";
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
"/socket.io/" = {
|
||||||
|
proxyPass = "http://localhost:7000";
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
63
hosts/mpd.nix
Normal file
63
hosts/mpd.nix
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
let
|
||||||
|
httpStreamPort = 8000;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.mpd = {
|
||||||
|
enable = true;
|
||||||
|
musicDirectory = "/data/music/flac";
|
||||||
|
playlistDirectory = "/data/music/playlists";
|
||||||
|
network.listenAddress = "any";
|
||||||
|
extraConfig = ''
|
||||||
|
audio_output {
|
||||||
|
type "pulse"
|
||||||
|
name "Local Music Player Daemon"
|
||||||
|
server "127.0.0.1"
|
||||||
|
mixer_type "software"
|
||||||
|
}
|
||||||
|
|
||||||
|
audio_output {
|
||||||
|
type "fifo"
|
||||||
|
name "fft"
|
||||||
|
path "/tmp/mpd.fifo"
|
||||||
|
format "44100:16:2"
|
||||||
|
}
|
||||||
|
|
||||||
|
audio_output {
|
||||||
|
type "httpd"
|
||||||
|
name "HTTP-Stream (Port 8000)"
|
||||||
|
encoder "vorbis" # optional
|
||||||
|
bind_to_address "0.0.0.0"
|
||||||
|
port "${toString httpStreamPort}"
|
||||||
|
# quality "5.0" # do not define if bitrate is defined
|
||||||
|
bitrate "128" # do not define if quality is defined
|
||||||
|
format "48000:16:1"
|
||||||
|
always_on "yes" # prevent MPD from disconnecting all listeners when playback is stopped.
|
||||||
|
tags "yes" # httpd supports sending tags to listening streams.
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
hardware.pulseaudio = {
|
||||||
|
enable = true;
|
||||||
|
systemWide = true;
|
||||||
|
tcp.enable = true;
|
||||||
|
tcp.anonymousClients.allowedIpRanges = [ "127.0.0.1" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
users.extraGroups.pulse-access = {
|
||||||
|
members = [ "mpd" ];
|
||||||
|
};
|
||||||
|
# users.extraGroups.music = {
|
||||||
|
# members = [ "mpd" ];
|
||||||
|
# };
|
||||||
|
|
||||||
|
# Workaround https://github.com/NixOS/nixpkgs/issues/114399
|
||||||
|
system.activationScripts.fix-pulse-permissions = ''
|
||||||
|
chmod 755 /run/pulse
|
||||||
|
'';
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [ mpc-cli ];
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ config.services.mpd.network.port httpStreamPort ];
|
||||||
|
}
|
62
hosts/nextcloud.nix
Normal file
62
hosts/nextcloud.nix
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
hostName = (lib.toLower config.networking.hostName) + ".gvfr.de";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.nextcloud = {
|
||||||
|
enable = true;
|
||||||
|
https = true;
|
||||||
|
package = pkgs.nextcloud25;
|
||||||
|
hostName = hostName;
|
||||||
|
datadir = "/data/nextcloud";
|
||||||
|
config = {
|
||||||
|
dbtype = "pgsql";
|
||||||
|
dbhost = "/run/postgresql";
|
||||||
|
adminpassFile = "/secrets/nextcloud_admin_password.txt";
|
||||||
|
extraTrustedDomains = [
|
||||||
|
((lib.toLower config.networking.hostName) + ".lan")
|
||||||
|
(lib.toLower config.networking.hostName)
|
||||||
|
];
|
||||||
|
};
|
||||||
|
caching.redis = true;
|
||||||
|
enableBrokenCiphersForSSE = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.postgresql = {
|
||||||
|
enable = true;
|
||||||
|
ensureUsers = [
|
||||||
|
{
|
||||||
|
name = "nextcloud";
|
||||||
|
ensurePermissions = {
|
||||||
|
"DATABASE nextcloud" = "ALL PRIVILEGES";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "superuser";
|
||||||
|
ensurePermissions = {
|
||||||
|
"ALL TABLES IN SCHEMA public" = "ALL PRIVILEGES";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ensureDatabases = [ "nextcloud" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Ensure that postgres is running *before* running the setup
|
||||||
|
systemd.services."nextcloud-setup" = {
|
||||||
|
requires = ["postgresql.service"];
|
||||||
|
after = ["postgresql.service"];
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||||
|
|
||||||
|
services.nginx = {
|
||||||
|
virtualHosts.${hostName} = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
users.extraGroups.music = {
|
||||||
|
members = [ "nextcloud" ];
|
||||||
|
};
|
||||||
|
}
|
11
hosts/open-pgsql.nix
Normal file
11
hosts/open-pgsql.nix
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
# Open PostgreSQL port for data transfer
|
||||||
|
services.postgresql = {
|
||||||
|
enableTCPIP = true;
|
||||||
|
authentication = ''
|
||||||
|
host all all 192.168.178.0/24 trust
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
networking.firewall.allowedTCPPorts = [ 5432 ];
|
||||||
|
}
|
42
hosts/reboot-check-email.nix
Normal file
42
hosts/reboot-check-email.nix
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
{ pkgs, lib, config, ... }:
|
||||||
|
{
|
||||||
|
systemd.services.reboot-check = {
|
||||||
|
description = "Check if the system needs a reboot";
|
||||||
|
onFailure = [ "status-email@%n.service" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
#!${pkgs.bash}/bin/bash
|
||||||
|
|
||||||
|
booted="$(readlink /run/booted-system/{initrd,kernel,kernel-modules})"
|
||||||
|
built="$(readlink /nix/var/nix/profiles/system/{initrd,kernel,kernel-modules})"
|
||||||
|
|
||||||
|
indent()
|
||||||
|
{
|
||||||
|
while read line ; do
|
||||||
|
echo " $line"
|
||||||
|
done <<< "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$booted" != "$built" ] ; then
|
||||||
|
echo "Booted kernel version"
|
||||||
|
indent "$booted"
|
||||||
|
echo "does not match currently active"
|
||||||
|
indent "$built"
|
||||||
|
echo "A reboot is required."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.timers.reboot-check = {
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
enable = true;
|
||||||
|
timerConfig = {
|
||||||
|
Unit = "reboot-check.service";
|
||||||
|
OnCalendar = "*-*-* 18:30:00";
|
||||||
|
Persistent = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
33
hosts/transcode.nix
Normal file
33
hosts/transcode.nix
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
let
|
||||||
|
transcode = pkgs.callPackage ../packages/transcode.nix {};
|
||||||
|
flacPath = "/data/music/flac";
|
||||||
|
mp3Path = "/data/music/mp3";
|
||||||
|
oggPath = "/data/music/ogg";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
systemd.services.transcode = {
|
||||||
|
description = "Transcode music form FLAC to MP3 and OGG";
|
||||||
|
onFailure = [ "status-email@%n.service" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
ExecStart = "${transcode}/bin/transcode --mp3-out \"${mp3Path}\" --ogg-out \"${oggPath}\" \"${flacPath}\"";
|
||||||
|
DynamicUser = true;
|
||||||
|
Group = "music";
|
||||||
|
UMask = "002";
|
||||||
|
ReadOnlyDirectories = [ flacPath ];
|
||||||
|
ReadWriteDirectories = [ mp3Path oggPath ];
|
||||||
|
Nice = 19;
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
PrivateTmp = true;
|
||||||
|
PrivateDevices = true;
|
||||||
|
PrivateUsers = true;
|
||||||
|
ProtectClock = true;
|
||||||
|
ProtectSystem = "strict";
|
||||||
|
ProtectHome = true;
|
||||||
|
ProtectKernelLogs = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectProc = "invisible";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
164
options/auto-upgrade.nix
Normal file
164
options/auto-upgrade.nix
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
{ pkgs, lib, config, ... }:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
fromAddress = config.email.fromAddress;
|
||||||
|
fromIdentity = config.email.fromIdentity;
|
||||||
|
toAddress = config.email.adminEmail;
|
||||||
|
cfg = config.system.autoUpgrade;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.system.autoUpgrade = {
|
||||||
|
sendEmail = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = mdDoc ''
|
||||||
|
Whether to send a status email after an upgrade.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
systemd.services.nixos-upgrade.script = mkOverride 50 (
|
||||||
|
let
|
||||||
|
nixos-rebuild = "${config.system.build.nixos-rebuild}/bin/nixos-rebuild";
|
||||||
|
date = "${pkgs.coreutils}/bin/date";
|
||||||
|
readlink = "${pkgs.coreutils}/bin/readlink";
|
||||||
|
grep = "${pkgs.gnugrep}/bin/grep";
|
||||||
|
shutdown = "${config.systemd.package}/bin/shutdown";
|
||||||
|
sendmail = "${pkgs.system-sendmail}/bin/sendmail";
|
||||||
|
upgradeFlag = optional (cfg.channel == null) "--upgrade";
|
||||||
|
in ''
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
upgrade() {
|
||||||
|
${nixos-rebuild} ${cfg.operation} ${toString (cfg.flags ++ upgradeFlag)}
|
||||||
|
}
|
||||||
|
|
||||||
|
indent()
|
||||||
|
{
|
||||||
|
while read -r line ; do
|
||||||
|
echo " $line"
|
||||||
|
done <<< "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
start_time="$(${date})"
|
||||||
|
reboot_allowed="no"
|
||||||
|
do_reboot="no"
|
||||||
|
exit_code=0
|
||||||
|
|
||||||
|
${optionalString cfg.allowReboot ''
|
||||||
|
reboot_allowed="yes"
|
||||||
|
|
||||||
|
${optionalString (cfg.rebootWindow != null) ''
|
||||||
|
current_time="$(${date} +%H:%M)"
|
||||||
|
lower="${cfg.rebootWindow.lower}"
|
||||||
|
upper="${cfg.rebootWindow.upper}"
|
||||||
|
if [[ "''${lower}" < "''${upper}" ]]; then
|
||||||
|
if [[ "''${current_time}" > "''${lower}" ]] && \
|
||||||
|
[[ "''${current_time}" < "''${upper}" ]]; then
|
||||||
|
reboot_allowed="yes"
|
||||||
|
else
|
||||||
|
reboot_allowed="no"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# lower > upper, so we are crossing midnight (e.g. lower=23h, upper=6h)
|
||||||
|
# we want to reboot if cur > 23h or cur < 6h
|
||||||
|
if [[ "''${current_time}" < "''${upper}" ]] || \
|
||||||
|
[[ "''${current_time}" > "''${lower}" ]]; then
|
||||||
|
reboot_allowed="yes"
|
||||||
|
else
|
||||||
|
reboot_allowed="no"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
''}
|
||||||
|
''}
|
||||||
|
|
||||||
|
output_file="$(mktemp)"
|
||||||
|
upgrade 2>&1 | tee "$output_file" || exit_code=$?
|
||||||
|
upgrade_output="$(cat "$output_file")"
|
||||||
|
rm -f "$output_file"
|
||||||
|
|
||||||
|
send_email=no
|
||||||
|
email_subject="Upgrade succeeded"
|
||||||
|
email_body="The system upgrade started at $start_time has succeeded."
|
||||||
|
if [ "$exit_code" -ne 0 ] ; then
|
||||||
|
send_email=yes
|
||||||
|
email_subject="Upgrade failed (exit code $exit_code)"
|
||||||
|
email_body="The system upgrade started at $start_time has failed with exit code $exit_code."
|
||||||
|
fi
|
||||||
|
|
||||||
|
possible_warnings="$(${grep} -e "^trace:" <<<"$upgrade_output" || true)"
|
||||||
|
if [ "$possible_warnings" != "" ] ; then
|
||||||
|
send_email=yes
|
||||||
|
email_subject="$email_subject with warnings"
|
||||||
|
email_body="$(cat <<-EOF
|
||||||
|
$email_body
|
||||||
|
|
||||||
|
|
||||||
|
These trace messages and warnings were encountered:
|
||||||
|
---------------------------------------------------
|
||||||
|
$possible_warnings
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
booted_version="$(${readlink} /run/booted-system/{initrd,kernel,kernel-modules})"
|
||||||
|
built_version="$(${readlink} /nix/var/nix/profiles/system/{initrd,kernel,kernel-modules})"
|
||||||
|
|
||||||
|
if [ "$booted_version" != "$built_version" ] ; then
|
||||||
|
version_comparison="$(cat <<-EOF
|
||||||
|
The booted kernel version
|
||||||
|
$(indent "$booted_version")
|
||||||
|
does not match currently active
|
||||||
|
$(indent "$built_version")
|
||||||
|
.
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
echo "$version_comparison"
|
||||||
|
send_email=yes
|
||||||
|
email_subject="$email_subject, reboot required"
|
||||||
|
email_body="$(cat <<-EOF
|
||||||
|
$email_body
|
||||||
|
|
||||||
|
|
||||||
|
A reboot is required, because:
|
||||||
|
------------------------------
|
||||||
|
$version_comparison
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
if [ "$reboot_allowed" = "yes" ] && [ $exit_code -eq 0 ] ; then
|
||||||
|
email_body="$(printf "%s\n%s" "$email_body" "The system will reboot now.")"
|
||||||
|
do_reboot="yes"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
${optionalString cfg.sendEmail ''
|
||||||
|
if [ "$send_email" = "yes" ] ; then
|
||||||
|
${sendmail} -t -X - <<-EOF
|
||||||
|
To: ${toAddress}
|
||||||
|
From: ${fromIdentity}
|
||||||
|
Subject: $email_subject
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
X-Priority: 3
|
||||||
|
|
||||||
|
$email_body
|
||||||
|
|
||||||
|
|
||||||
|
Full upgrade output:
|
||||||
|
--------------------
|
||||||
|
$upgrade_output
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
''}
|
||||||
|
|
||||||
|
if [ "$do_reboot" = "yes" ] ; then
|
||||||
|
echo "Rebooting system."
|
||||||
|
${shutdown} -r +1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit $exit_code
|
||||||
|
''
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
56
options/btrfs-scrub.nix
Normal file
56
options/btrfs-scrub.nix
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
{ pkgs, utils, lib, config, ... }:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.services.btrfsScrub;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.btrfsScrub = {
|
||||||
|
enable = mkEnableOption "Periodically run btrfs-scrub on filesystems";
|
||||||
|
enableFailureEmail = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = mdDoc "Send e-mail on scrub failure";
|
||||||
|
};
|
||||||
|
paths = mkOption {
|
||||||
|
type = with types; attrsOf (submodule {
|
||||||
|
options = {
|
||||||
|
onCalendar = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "*-*-* 02:00:00";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config.services.statusEmail.enable = mkIf (cfg.enable && cfg.enableFailureEmail) true;
|
||||||
|
|
||||||
|
config.systemd.services."btrfs-scrub@" = mkIf cfg.enable {
|
||||||
|
unitConfig = {
|
||||||
|
Description = "Scrub btrfs volume %I";
|
||||||
|
OnFailure = mkIf cfg.enableFailureEmail "status-email@%n.service";
|
||||||
|
};
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
ExecStart = "${pkgs.btrfs-progs}/bin/btrfs scrub start -B -d %f";
|
||||||
|
# ExecStop = "-${pkgs.btrfs-progs}/bin/btrfs scrub cancel %f";
|
||||||
|
Nice = 19;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config.systemd.timers = mkIf cfg.enable (mapAttrs' (name: value:
|
||||||
|
let
|
||||||
|
pathEscaped = utils.escapeSystemdPath name;
|
||||||
|
in
|
||||||
|
nameValuePair "btrfs-scrub-${pathEscaped}"
|
||||||
|
{
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
enable = true;
|
||||||
|
timerConfig = {
|
||||||
|
Unit = "btrfs-scrub@${pathEscaped}.service";
|
||||||
|
OnCalendar = value.onCalendar;
|
||||||
|
RandomizedDelaySec = "1h";
|
||||||
|
Persistent = true;
|
||||||
|
};
|
||||||
|
}) cfg.paths);
|
||||||
|
}
|
432
options/burp.nix
Normal file
432
options/burp.nix
Normal file
|
@ -0,0 +1,432 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
libDir = "/var/lib/burp";
|
||||||
|
clientCertDir = "${libDir}/CA-client";
|
||||||
|
cfg = config.services.burp;
|
||||||
|
|
||||||
|
clientConf = pkgs.writeText "burp.conf" ''
|
||||||
|
mode = client
|
||||||
|
pidfile = /run/burp/burp.pid
|
||||||
|
port = ${toString cfg.client.port}
|
||||||
|
status_port = ${toString cfg.client.statusPort}
|
||||||
|
server = ${cfg.client.server}
|
||||||
|
password = ${cfg.client.password}
|
||||||
|
cname = ${cfg.client.clientName}
|
||||||
|
ca_burp_ca = ${cfg.package}/bin/burp_ca
|
||||||
|
ca_csr_dir = ${clientCertDir}
|
||||||
|
ssl_cert_ca = ${libDir}/ssl_cert_ca.pem
|
||||||
|
ssl_cert = ${libDir}/ssl_cert-client.pem
|
||||||
|
ssl_key = ${libDir}/ssl_cert-client.key
|
||||||
|
ssl_key_password = ${cfg.client.sslKeyPassword}
|
||||||
|
ssl_peer_cn = burpserver
|
||||||
|
${concatMapStringsSep "\n" (x: "include = " + x) cfg.client.includes}
|
||||||
|
${concatMapStringsSep "\n" (x: "exclude = " + x) cfg.client.excludes}
|
||||||
|
nobackup = .nobackup
|
||||||
|
${cfg.client.extraConfig}
|
||||||
|
'';
|
||||||
|
|
||||||
|
serverHome = "/var/lib/burp";
|
||||||
|
serverClientConfDir = serverHome + "/clientconfdir";
|
||||||
|
|
||||||
|
serverCaConf = pkgs.writeText "CA.cnf" ''
|
||||||
|
CA_DIR = ${serverHome}/CA
|
||||||
|
|
||||||
|
[ ca ]
|
||||||
|
dir = $ENV::CA_DIR
|
||||||
|
database = $dir/index.txt
|
||||||
|
serial = $dir/serial.txt
|
||||||
|
certs = $dir/certs
|
||||||
|
new_certs_dir = $dir/newcerts
|
||||||
|
crlnumber = $dir/crlnumber.txt
|
||||||
|
|
||||||
|
unique_subject = no
|
||||||
|
|
||||||
|
default_md = sha256
|
||||||
|
default_days = 7300
|
||||||
|
default_crl_days = 7300
|
||||||
|
|
||||||
|
#????
|
||||||
|
name_opt = ca_default
|
||||||
|
cert_opt = ca_default
|
||||||
|
|
||||||
|
x509_extensions = usr_cert
|
||||||
|
copy_extensions = copy
|
||||||
|
policy = policy_anything
|
||||||
|
|
||||||
|
[ usr_cert ]
|
||||||
|
basicConstraints = CA:FALSE
|
||||||
|
|
||||||
|
[ policy_anything ]
|
||||||
|
commonName = supplied
|
||||||
|
'';
|
||||||
|
|
||||||
|
serverConf = pkgs.writeText "burp-server.conf" ''
|
||||||
|
mode = server
|
||||||
|
pidfile = /run/burp/burp-server.pid
|
||||||
|
listen = ${cfg.server.listen}
|
||||||
|
max_children = 5;
|
||||||
|
listen_status = ${cfg.server.listenStatus}
|
||||||
|
max_status_children = 5;
|
||||||
|
|
||||||
|
user = burp
|
||||||
|
group = burp
|
||||||
|
umask = 0022
|
||||||
|
clientconfdir = ${serverClientConfDir}
|
||||||
|
directory = ${cfg.server.dataDirectory}
|
||||||
|
|
||||||
|
ca_conf = ${serverCaConf}
|
||||||
|
ca_name = burpCA
|
||||||
|
ca_server_name = burpserver
|
||||||
|
ca_burp_ca = ${cfg.package}/bin/burp_ca
|
||||||
|
ca_crl_check = 1
|
||||||
|
ssl_cert_ca = ${serverHome}/ssl_cert_ca.pem
|
||||||
|
ssl_cert = ${serverHome}/ssl_cert-server.pem
|
||||||
|
ssl_key = ${serverHome}/ssl_cert-server.key
|
||||||
|
ssl_dhfile = ${serverHome}/dhfile.pem
|
||||||
|
ssl_key_password = ${cfg.server.sslKeyPassword}
|
||||||
|
|
||||||
|
${concatMapStringsSep "\n" (x: "keep = " + toString x) cfg.server.keep}
|
||||||
|
timer_script = ${cfg.server.timerScript}
|
||||||
|
${concatMapStringsSep "\n" (x: "timer_arg = " + x) cfg.server.timerArgs}
|
||||||
|
|
||||||
|
dedup_group = global
|
||||||
|
working_dir_recovery_method = ${cfg.server.workingDirRecoveryMethod}
|
||||||
|
max_resume_attempts = ${toString cfg.server.maxResumeAttempts}
|
||||||
|
|
||||||
|
${concatMapStringsSep "\n" (x: "super_client = " + x) cfg.server.superClients}
|
||||||
|
${concatMapStringsSep "\n" (x: "restore_client = " + x) cfg.server.restoreClients}
|
||||||
|
|
||||||
|
${cfg.server.extraConfig}
|
||||||
|
'';
|
||||||
|
|
||||||
|
clientConfigs = lib.attrsets.mapAttrs (name: config: (pkgs.writeText name ''
|
||||||
|
password = ${config.password}
|
||||||
|
${config.extraConfig}
|
||||||
|
'')) cfg.server.clients;
|
||||||
|
|
||||||
|
in {
|
||||||
|
options = {
|
||||||
|
services.burp.package = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
default = pkgs.burp;
|
||||||
|
description = ''
|
||||||
|
The package which is used as a burp server/client.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
services.burp.server = {
|
||||||
|
enable = mkEnableOption "Burp server";
|
||||||
|
|
||||||
|
listen = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = ":::4971";
|
||||||
|
description = ''
|
||||||
|
Listen address used for backup communication.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
listenStatus = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = ":::4972";
|
||||||
|
description = ''
|
||||||
|
Listen address used for querying backup and server status.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
dataDirectory = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "/var/spool/burp";
|
||||||
|
description = ''
|
||||||
|
Where the backup data is stored.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
sslKeyPassword = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "change-this-password";
|
||||||
|
description = ''
|
||||||
|
SSL key password for loading a certificate with encryption.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
keep = mkOption {
|
||||||
|
type = types.listOf types.int;
|
||||||
|
default = [ 7 ];
|
||||||
|
description = ''
|
||||||
|
How many backups to keep.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
timerScript = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "${cfg.package}/share/burp/scripts/timer_script";
|
||||||
|
description = ''
|
||||||
|
Timer script used to evaluate if it's backup time.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
timerArgs = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [
|
||||||
|
"20h"
|
||||||
|
"Mon,Tue,Wed,Thu,Fri,00,01,02,03,04,05,19,20,21,22,23"
|
||||||
|
"Sat,Sun,00,01,02,03,04,05,06,07,08,17,18,19,20,21,22,23"
|
||||||
|
];
|
||||||
|
description = ''
|
||||||
|
How often should backups be triggered.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
superClients = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [];
|
||||||
|
description = ''
|
||||||
|
Clients that are permitted to list, verify, restore, delete, and diff files belonging to any other client, according to the super_client's client_can permissions (eg, 'client_can_list'). If this is too permissive, you may set a super_client for individual original clients in the individual clientconfdir files, or look at the 'restoreClients' option.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
restoreClients = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [];
|
||||||
|
description = ''
|
||||||
|
Clients that are permitted to list, verify, restore, delete, and diff files belonging to any other client, according to the client_can permissions on both the restore_client and the original_client (eg, 'client_can_list'). If this is too permissive, you may set a restoreClient for individual original clients in the individual clientconfdir files.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
workingDirRecoveryMethod = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "delete";
|
||||||
|
description = ''
|
||||||
|
This option tells the server what to do when it finds the working directory of an interrupted backup (perhaps somebody pulled the plug on the server, or something). This can be overridden by the client configurations files in clientconfdir on the server. Options are...
|
||||||
|
|
||||||
|
delete: Just delete the old working directory.
|
||||||
|
|
||||||
|
resume: Continue the previous backup from the point at which it left off. NOTE: If the client has changed its include/exclude configuration since the backup was interrupted, the recovery method will automatically switch to 'delete'. See also the 'resume attempts' option.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
maxResumeAttempts = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 0;
|
||||||
|
description = ''
|
||||||
|
If workingDirRecoveryMethod is 'resume', this option tells the server how many times to attempt to resume before giving up and deleting the working directory. The default is 0, which means to never give up.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
clients = mkOption {
|
||||||
|
type = types.attrsOf (types.submodule ({ ... }: {
|
||||||
|
options = {
|
||||||
|
password = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "change-this-password";
|
||||||
|
description = ''
|
||||||
|
Password used by the client for first contact with the server.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = mkOption {
|
||||||
|
type = types.lines;
|
||||||
|
default = "";
|
||||||
|
description = ''
|
||||||
|
Extra configuration for burp client. Contents will be added verbatim to the
|
||||||
|
configuration file.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = mkOption {
|
||||||
|
type = types.lines;
|
||||||
|
default = "";
|
||||||
|
description = ''
|
||||||
|
Extra configuration for burp client. Contents will be added verbatim to the
|
||||||
|
configuration file.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.burp.client = {
|
||||||
|
enable = mkEnableOption "Burp client";
|
||||||
|
|
||||||
|
frequency = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "hourly";
|
||||||
|
description = ''
|
||||||
|
Controls how frequently the systemd timer is triggered and a backup
|
||||||
|
is attempted.
|
||||||
|
Backup frequency is still determined by the server, this
|
||||||
|
controls only how often the client tries.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
server = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "127.0.0.1";
|
||||||
|
description = ''
|
||||||
|
Address of burp server the client should contact.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = 4971;
|
||||||
|
description = ''
|
||||||
|
Port used for backup communication.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
statusPort = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = 4972;
|
||||||
|
description = ''
|
||||||
|
Port used for querying backup and server status.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
clientName = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "${config.networking.hostName}";
|
||||||
|
description = ''
|
||||||
|
Name the client should use to identify itself to the server.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
password = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "change-this-password";
|
||||||
|
description = ''
|
||||||
|
Password used by the client for first contact with the server.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
sslKeyPassword = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "change-this-password";
|
||||||
|
description = ''
|
||||||
|
SSL key password for loading a certificate with encryption.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
includes = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ "/etc" "/root" "/var" "/home" ];
|
||||||
|
description = ''
|
||||||
|
List of locations to include in backups.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
excludes = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ ];
|
||||||
|
description = ''
|
||||||
|
List of locations to exclude from the backup.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = mkOption {
|
||||||
|
type = types.lines;
|
||||||
|
default = "";
|
||||||
|
description = ''
|
||||||
|
Extra configuration for burp client. Contents will be added verbatim to the
|
||||||
|
configuration file.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
environment.systemPackages = mkIf cfg.client.enable [ cfg.package ];
|
||||||
|
|
||||||
|
systemd.timers.burp-client = mkIf cfg.client.enable {
|
||||||
|
description = "Timer for triggering Burp client and start a backup";
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
timerConfig = {
|
||||||
|
OnCalendar = cfg.client.frequency;
|
||||||
|
Unit = "burp-client.service";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.burp-client = mkIf cfg.client.enable {
|
||||||
|
description = "Burp client";
|
||||||
|
after = [ "network.target" ];
|
||||||
|
path = [ cfg.package pkgs.nettools pkgs.openssl ];
|
||||||
|
|
||||||
|
preStart = ''
|
||||||
|
if [ ! -d "${libDir}" ]; then
|
||||||
|
mkdir -m 0755 -p ${libDir}
|
||||||
|
mkdir -m 0700 -p ${clientCertDir}
|
||||||
|
${cfg.package}/bin/burp -c ${libDir}/burp.conf -g
|
||||||
|
fi
|
||||||
|
ln -f -s ${clientConf} ${libDir}/burp.conf
|
||||||
|
'';
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
ExecStart = "${cfg.package}/bin/burp -c ${libDir}/burp.conf -a t";
|
||||||
|
SuccessExitStatus = "3";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
users = mkIf cfg.server.enable {
|
||||||
|
users.burp = {
|
||||||
|
group = "burp";
|
||||||
|
uid = 497;
|
||||||
|
home = "${serverHome}";
|
||||||
|
createHome = true;
|
||||||
|
description = "Burp Server user";
|
||||||
|
shell = "${pkgs.bash}/bin/bash";
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
groups.burp = {
|
||||||
|
gid = 497;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.burp-server = mkIf cfg.server.enable {
|
||||||
|
description = "Burp Server";
|
||||||
|
after = [ "network.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
path = [ cfg.package pkgs.nettools pkgs.openssl ];
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStart = "${cfg.package}/bin/burp -F -v -c ${serverConf}";
|
||||||
|
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
||||||
|
|
||||||
|
User = "burp";
|
||||||
|
Group = "burp";
|
||||||
|
UMask = "0077";
|
||||||
|
RuntimeDirectory = "burp";
|
||||||
|
PrivateTmp = true;
|
||||||
|
PrivateDevices = true;
|
||||||
|
ProtectSystem = true;
|
||||||
|
ProtectHome = true;
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
ReadWriteDirectories = [
|
||||||
|
cfg.server.dataDirectory
|
||||||
|
serverHome
|
||||||
|
];
|
||||||
|
|
||||||
|
ExecStartPre = "+${pkgs.writeScript "burp-prestart" ''
|
||||||
|
#!/${pkgs.bash}/bin/bash
|
||||||
|
if ! [ -d "${cfg.server.dataDirectory}" ] ; then
|
||||||
|
mkdir -p "${cfg.server.dataDirectory}"
|
||||||
|
fi
|
||||||
|
if ! [ -d "${serverClientConfDir}" ] ; then
|
||||||
|
mkdir -p "${serverClientConfDir}"
|
||||||
|
fi
|
||||||
|
chown burp:burp "${cfg.server.dataDirectory}" "${serverClientConfDir}"
|
||||||
|
chmod 700 "${cfg.server.dataDirectory}" "${serverClientConfDir}"
|
||||||
|
${concatStringsSep "\n" (mapAttrsToList(name: file:
|
||||||
|
"ln -fs " + file + " " + serverClientConfDir + "/" + name) clientConfigs)}
|
||||||
|
''}";
|
||||||
|
|
||||||
|
Nice = 19;
|
||||||
|
IOSchedulingClass = "idle";
|
||||||
|
CPUSchedulingPolicy = "idle";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
10
options/default.nix
Normal file
10
options/default.nix
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./email.nix
|
||||||
|
./burp.nix
|
||||||
|
./auto-upgrade.nix
|
||||||
|
./status-email.nix
|
||||||
|
./btrfs-scrub.nix
|
||||||
|
];
|
||||||
|
}
|
28
options/email.nix
Normal file
28
options/email.nix
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
with lib;
|
||||||
|
{
|
||||||
|
options.email = {
|
||||||
|
fromAddress = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "noreply@example.com";
|
||||||
|
description = ''
|
||||||
|
E-Mail address automated e-mails are sent from.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
fromIdentity = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "${config.networking.hostName} <${config.email.fromAddress}>";
|
||||||
|
example = "Maintenance (no reply) <noreply@example.com>";
|
||||||
|
description = ''
|
||||||
|
E-Mail identity automated e-mails are sent from.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
adminEmail = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "admin@example.com";
|
||||||
|
description = ''
|
||||||
|
E-Mail address automated e-mails are sent to.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
95
options/status-email.nix
Normal file
95
options/status-email.nix
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
{ pkgs, lib, config, ... }:
|
||||||
|
let
|
||||||
|
fromAddress = config.email.fromAddress;
|
||||||
|
fromIdentity = config.email.fromIdentity;
|
||||||
|
toAddress = config.email.adminEmail;
|
||||||
|
cfg = config.services.statusEmail;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.statusEmail = {
|
||||||
|
enable = lib.mkEnableOption "Send systemd status e-mails";
|
||||||
|
};
|
||||||
|
|
||||||
|
config.programs.msmtp = lib.mkIf cfg.enable {
|
||||||
|
enable = true;
|
||||||
|
setSendmail = true;
|
||||||
|
accounts = {
|
||||||
|
default = {
|
||||||
|
auth = true;
|
||||||
|
host = "gvfr.de";
|
||||||
|
passwordeval = "cat /secrets/email_password.txt";
|
||||||
|
user = fromAddress;
|
||||||
|
from = fromAddress;
|
||||||
|
port = 465;
|
||||||
|
tls = true;
|
||||||
|
tls_starttls = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config.systemd.services."status-email@" = let
|
||||||
|
sendStatusEmail = pkgs.writeScript "send-status-email" ''
|
||||||
|
#!${pkgs.bash}/bin/bash
|
||||||
|
|
||||||
|
from="${fromIdentity}"
|
||||||
|
to="${toAddress}"
|
||||||
|
service="$1"
|
||||||
|
full_status="$(systemctl status --full --lines 200 "$service")"
|
||||||
|
exit_code="$(echo "$full_status" | head -n5 | tail -1 | sed -e 's/.*status=\(.*\))$/\1/g')"
|
||||||
|
# state="$(systemctl is-failed "$service")"
|
||||||
|
|
||||||
|
fail_priority=1
|
||||||
|
fail_subject="Unit \"$service\" failure report (exit code $exit_code)"
|
||||||
|
success_priority=3
|
||||||
|
success_subject="Unit \"$service\" report (success)"
|
||||||
|
|
||||||
|
shift
|
||||||
|
while [ $# -gt 0 ] ; do
|
||||||
|
case "$1" in
|
||||||
|
'-s'|'--fail-subject')
|
||||||
|
fail_subject="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
'-p'|'--fail-priority')
|
||||||
|
fail_priority="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$exit_code" != "0/SUCCESS" ] ; then
|
||||||
|
subject="$fail_subject"
|
||||||
|
priority="$fail_priority"
|
||||||
|
else
|
||||||
|
subject="$success_subject"
|
||||||
|
priority="$success_priority"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Sending e-mail \"$subject\" to \"$to\"."
|
||||||
|
|
||||||
|
${pkgs.system-sendmail}/bin/sendmail -t -X - <<ERRMAIL
|
||||||
|
To: $to
|
||||||
|
From: $from
|
||||||
|
Subject: $subject
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
X-Priority: $priority
|
||||||
|
|
||||||
|
$full_status
|
||||||
|
|
||||||
|
ERRMAIL
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
lib.mkIf cfg.enable {
|
||||||
|
unitConfig = {
|
||||||
|
Description = "Send a status e-mail for %I";
|
||||||
|
};
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${sendStatusEmail} %i";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
19
overlays/burp.nix
Normal file
19
overlays/burp.nix
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
(self: super: {
|
||||||
|
burp = (super.burp.overrideAttrs (old: {
|
||||||
|
version = "3.1.4";
|
||||||
|
src = super.fetchFromGitHub {
|
||||||
|
owner = "grke";
|
||||||
|
repo = "burp";
|
||||||
|
rev = "3.1.4";
|
||||||
|
hash = "sha256-/vYon0XUIuMAaaaRNehzMspKMHWp0tJm8JubRt1KmZU=";
|
||||||
|
};
|
||||||
|
configureFlags = [ "--sysconfdir=/var/lib/burp" ];
|
||||||
|
buildInputs = with super; [ librsync ncurses openssl_1_1 zlib uthash ];
|
||||||
|
patches = [];
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
6
overlays/default.nix
Normal file
6
overlays/default.nix
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./burp.nix
|
||||||
|
];
|
||||||
|
}
|
48
packages/transcode.nix
Normal file
48
packages/transcode.nix
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
{ stdenv
|
||||||
|
, lib
|
||||||
|
, fetchgit
|
||||||
|
, resholve
|
||||||
|
, bash
|
||||||
|
, file
|
||||||
|
, vorbis-tools
|
||||||
|
, flac
|
||||||
|
, ffmpeg
|
||||||
|
, unixtools
|
||||||
|
, exiftool
|
||||||
|
, makeWrapper
|
||||||
|
}:
|
||||||
|
stdenv.mkDerivation rec {
|
||||||
|
pname = "transcode";
|
||||||
|
version = "0.3.0";
|
||||||
|
src = fetchgit {
|
||||||
|
url = "https://git.25120.org/fruchti/transcode.git";
|
||||||
|
hash = "sha256-BN40KEQUQBRlwxMGWoPf8kya1kk2KveoU4ReASaKzZc=";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
dontConfigure = true;
|
||||||
|
dontBuild = true;
|
||||||
|
|
||||||
|
buildInputs = [ bash file vorbis-tools flac ffmpeg unixtools.xxd exiftool ];
|
||||||
|
nativeBuildInputs = [ makeWrapper ];
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
install -D transcode $out/bin/transcode
|
||||||
|
wrapProgram $out/bin/transcode \
|
||||||
|
--prefix PATH : ${lib.makeBinPath [ bash file vorbis-tools flac ffmpeg unixtools.xxd exiftool ]}
|
||||||
|
'';
|
||||||
|
|
||||||
|
# solutions = {
|
||||||
|
# default = {
|
||||||
|
# scripts = [ "bin/transcode" ];
|
||||||
|
# interpreter = "${bash}/bin/bash";
|
||||||
|
# inputs = [ vorbis-tools flac ffmpeg unixtools.xxd exiftool ];
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
homepage = "https://git.25120.org/fruchti/transcode";
|
||||||
|
description = "Transcode music from FLAC to MP3 and OGG";
|
||||||
|
platforms = platforms.linux;
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue