copy nb configuration and modules
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
# Edit this configuration file to define what should be installed on
|
||||
# your system. Help is available in the configuration.nix(5) man page
|
||||
# and in the NixOS manual (accessible by running ‘nixos-help’).
|
||||
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
||||
imports =
|
||||
[ # Include the results of the hardware scan.
|
||||
./utils/modules/clevis.nix
|
||||
|
||||
./utils/modules/sops.nix
|
||||
./utils/modules/nur.nix
|
||||
./utils/modules/sway/sway.nix
|
||||
# ./modules/gnome.nix
|
||||
./utils/modules/nvim/default.nix
|
||||
./utils/modules/tuxedo.nix
|
||||
./utils/modules/autoupgrade.nix
|
||||
|
||||
# ./pkgs/howdy/howdy-module.nix
|
||||
# ./pkgs/howdy/ir-toggle-module.nix
|
||||
|
||||
# ./modules/howdy
|
||||
|
||||
./hardware-configuration.nix
|
||||
];
|
||||
|
||||
nixpkgs.overlays = [ (import ./overlays/packages.nix) ];
|
||||
|
||||
# security.sudo.wheelNeedsPassword = false;
|
||||
services.clevis.uuid = "7435d48f-f942-485b-9817-328ad3fc0b93";
|
||||
|
||||
# nixos cross building qemu
|
||||
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
|
||||
boot.supportedFilesystems = [ "ntfs" ];
|
||||
boot.plymouth.enable = true;
|
||||
boot.plymouth.theme = "breeze";
|
||||
boot.kernelParams = ["quiet"];
|
||||
# boot.loader.systemd-boot.netbootxyz.enable = true;
|
||||
# boot.plymouth.themePackages = [ pkgs.nixos-bgrt-plymouth ];
|
||||
# boot.plymouth.theme = "nixos-bgrt";
|
||||
# allow hibernation
|
||||
security.protectKernelImage = false;
|
||||
|
||||
sops.defaultSopsFile = ./secrets.yaml;
|
||||
sops.age.keyFile = "/var/lib/sops-nix/key.txt";
|
||||
sops.age.generateKey = true;
|
||||
|
||||
sops.secrets.epicenter_vpn_ca = {};
|
||||
sops.secrets.epicenter_vpn_cert = {};
|
||||
sops.secrets.epicenter_vpn_key = {};
|
||||
sops.secrets.wg_private_key = {};
|
||||
sops.secrets.wg_preshared_key = {};
|
||||
sops.secrets.wg-cloonar-key = {};
|
||||
|
||||
virtualisation.docker.enable = true;
|
||||
virtualisation.virtualbox.host = {
|
||||
enable = true;
|
||||
enableExtensionPack = true;
|
||||
};
|
||||
|
||||
networking.hostName = "cl-nb-01"; # Define your hostname.
|
||||
networking.resolvconf.enable = true;
|
||||
networking.networkmanager.enable = true; # Easiest to use and most distros use this by default.
|
||||
networking.extraHosts = ''
|
||||
10.25.0.25 archive.zeichnemit.at epicenter.works en.epicenter.works
|
||||
10.25.0.100 download.intra.epicenter.works
|
||||
127.0.0.1 wohnservice.local mieterhilfe.local wohnpartner.local wohnberatung.local wienbautvor.local wienwohntbesser.local
|
||||
127.0.0.1 wohnservice-wien.local mieterhilfe.local wohnpartner-wien.local wohnberatung-wien.local wienbautvor.local wienwohntbesser.local
|
||||
127.0.0.1 diabetes.local
|
||||
'';
|
||||
|
||||
# Set your time zone.
|
||||
time.timeZone = "Europe/Vienna";
|
||||
console.keyMap = "de";
|
||||
|
||||
users.users.dominik = {
|
||||
isNormalUser = true;
|
||||
extraGroups = [ "wheel" "disk" "video" "audio" "mysql" "docker" "vboxusers" "networkmanager" "onepassword" "onepassword-cli" "dialout" ]; # Enable ‘sudo’ for the user.
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
bento
|
||||
vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
|
||||
wget
|
||||
docker-compose
|
||||
drone-cli
|
||||
wireguard-tools
|
||||
libftdi1
|
||||
];
|
||||
|
||||
environment.variables = {
|
||||
TERMINAL_COMMAND = "alacritty";
|
||||
};
|
||||
|
||||
services.blueman.enable = true;
|
||||
|
||||
services.printing.enable = true;
|
||||
services.printing.drivers = [ pkgs.brlaser ];
|
||||
|
||||
services.mysql = {
|
||||
enable = true;
|
||||
package = pkgs.mariadb;
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "dominik";
|
||||
ensurePermissions = {
|
||||
"*.*" = "ALL PRIVILEGES";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "dominik";
|
||||
ensurePermissions = {
|
||||
"DATABASE \"zammad\"" = "ALL PRIVILEGES";
|
||||
};
|
||||
}
|
||||
];
|
||||
ensureDatabases = [ "zammad" ];
|
||||
};
|
||||
|
||||
system.stateVersion = "22.11"; # Did you read the comment?
|
||||
|
||||
security.polkit.enable = true;
|
||||
systemd = {
|
||||
user.services.polkit-gnome-authentication-agent-1 = {
|
||||
description = "polkit-gnome-authentication-agent-1";
|
||||
wantedBy = [ "graphical-session.target" ];
|
||||
wants = [ "graphical-session.target" ];
|
||||
after = [ "graphical-session.target" ];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
ExecStart = "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 1;
|
||||
TimeoutStopSec = 10;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
networking.firewall = {
|
||||
allowedUDPPorts = [ 51820 ]; # Clients and peers can use the same port, see listenport
|
||||
# if packets are still dropped, they will show up in dmesg
|
||||
logReversePathDrops = true;
|
||||
# wireguard trips rpfilter up
|
||||
extraCommands = ''
|
||||
ip46tables -t mangle -I nixos-fw-rpfilter -p udp -m udp --sport 51820 -j RETURN
|
||||
ip46tables -t mangle -I nixos-fw-rpfilter -p udp -m udp --dport 51820 -j RETURN
|
||||
'';
|
||||
extraStopCommands = ''
|
||||
ip46tables -t mangle -D nixos-fw-rpfilter -p udp -m udp --sport 51820 -j RETURN || true
|
||||
ip46tables -t mangle -D nixos-fw-rpfilter -p udp -m udp --dport 51820 -j RETURN || true
|
||||
'';
|
||||
};
|
||||
# networking.wireguard.interfaces = {
|
||||
# wg0 = {
|
||||
# # Determines the IP address and subnet of the client's end of the tunnel interface.
|
||||
# ips = [ "10.42.98.201/32" ];
|
||||
# listenPort = 51820; # to match firewall allowedUDPPorts (without this wg uses random port numbers)
|
||||
#
|
||||
# # Path to the private key file.
|
||||
# #
|
||||
# # Note: The private key can also be included inline via the privateKey option,
|
||||
# # but this makes the private key world-readable; thus, using privateKeyFile is
|
||||
# # recommended.
|
||||
# privateKeyFile = config.sops.secrets.wg-cloonar-key.path;
|
||||
#
|
||||
# peers = [
|
||||
# {
|
||||
# publicKey = "TKQVDmBnf9av46kQxLQSBDhAeaK8r1zh8zpU64zuc1Q=";
|
||||
# allowedIPs = [ "0.0.0.0/0" ];
|
||||
# endpoint = "vpn.cloonar.com:51820"; # ToDo: route to endpoint not automatically configured https://wiki.archlinux.org/index.php/WireGuard#Loop_routing https://discourse.nixos.org/t/solved-minimal-firewall-setup-for-wireguard-client/7577
|
||||
# persistentKeepalive = 25;
|
||||
# }
|
||||
# ];
|
||||
# };
|
||||
# };
|
||||
|
||||
# Facial recognition "Windows hello"
|
||||
# services.ir-toggle.enable = true;
|
||||
# services.howdy = {
|
||||
# enable = true;
|
||||
# device = "/dev/video2";
|
||||
# };
|
||||
nix = {
|
||||
settings.auto-optimise-store = true;
|
||||
# autoOptimiseStore = true;
|
||||
gc = {
|
||||
automatic = true;
|
||||
dates = "weekly";
|
||||
options = "--delete-older-than 30d";
|
||||
};
|
||||
# Free up to 1GiB whenever there is less than 100MiB left.
|
||||
extraOptions = ''
|
||||
min-free = ${toString (100 * 1024 * 1024)}
|
||||
max-free = ${toString (1024 * 1024 * 1024)}
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
58
hosts/nb-dominik/hardware-configuration.nix
Normal file
58
hosts/nb-dominik/hardware-configuration.nix
Normal file
@@ -0,0 +1,58 @@
|
||||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
{
|
||||
imports = [
|
||||
(modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "sd_mod" "rtsx_pci_sdmmc" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-intel" ];
|
||||
boot.kernelParams = [ "resume=/swap/swapfile" "resume_offset=533760" ];
|
||||
boot.resumeDevice = "/dev/disk/by-uuid/92284909-c5dd-4e0f-ab22-64157c8175cb";
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" =
|
||||
{ device = "/dev/disk/by-uuid/92284909-c5dd-4e0f-ab22-64157c8175cb";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=root" ];
|
||||
};
|
||||
|
||||
# boot.initrd.luks.devices."nixos-enc".device = "/dev/disk/by-uuid/7435d48f-f942-485b-9817-328ad3fc0b93";
|
||||
|
||||
fileSystems."/home" =
|
||||
{ device = "/dev/disk/by-uuid/92284909-c5dd-4e0f-ab22-64157c8175cb";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=home" ];
|
||||
};
|
||||
|
||||
fileSystems."/boot" =
|
||||
{ device = "/dev/disk/by-uuid/C281-E509";
|
||||
fsType = "vfat";
|
||||
};
|
||||
|
||||
fileSystems."/swap" =
|
||||
{ device = "/dev/disk/by-uuid/92284909-c5dd-4e0f-ab22-64157c8175cb";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=swap" ];
|
||||
};
|
||||
|
||||
swapDevices = [{
|
||||
device = "/swap/swapfile";
|
||||
size = (1024 * 16);
|
||||
}];
|
||||
|
||||
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||
# still possible to use this option, but it's recommended to use it in conjunction
|
||||
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
|
||||
networking.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.wlp52s0.useDHCP = lib.mkDefault true;
|
||||
|
||||
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
|
||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
}
|
||||
7
utils/modules/autoupgrade.nix
Normal file
7
utils/modules/autoupgrade.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{ config, ... }:
|
||||
|
||||
{
|
||||
system.autoUpgrade.enable = true;
|
||||
system.autoUpgrade.allowReboot = false;
|
||||
system.autoUpgrade.channel = "https://channels.nixos.org/nixos-23.05";
|
||||
}
|
||||
36
utils/modules/bento/fleet.nix
Normal file
36
utils/modules/bento/fleet.nix
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
create_users = host: {
|
||||
users.users."${host.username}" = {
|
||||
createHome = false;
|
||||
home = "/home/chroot/" + host.username;
|
||||
isNormalUser = false;
|
||||
isSystemUser = true;
|
||||
group = "sftp_users";
|
||||
openssh.authorizedKeys.keys = [host.key];
|
||||
shell = null;
|
||||
};
|
||||
};
|
||||
|
||||
users = [
|
||||
{
|
||||
username = "notebook";
|
||||
key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDN/2SAFm50kraB1fepAizox/QRXxB7WbqVbH+5OPalDT47VIJGNKOKhixQoqhABHxEoLxdf/C83wxlCVlPV9poLfDgVkA3Lyt5r3tSFQ6QjjOJAgchWamMsxxyGBedhKvhiEzcr/Lxytnoz3kjDG8fqQJwEpdqMmJoMUfyL2Rqp16u+FQ7d5aJtwO8EUqovhMaNO7rggjPpV/uMOg+tBxxmscliN7DLuP4EMTA/FwXVzcFNbOx3K9BdpMRAaSJt4SWcJO2cS2KHA5n/H+PQI7nz5KN3Yr/upJN5fROhi/SHvK39QOx12Pv7FCuWlc+oR68vLaoCKYhnkl3DnCfc7A7";
|
||||
}
|
||||
];
|
||||
in {
|
||||
imports = builtins.map create_users users;
|
||||
|
||||
users.groups = {sftp_users = {};};
|
||||
|
||||
services.openssh.extraConfig = ''
|
||||
Match Group sftp_users
|
||||
X11Forwarding no
|
||||
AllowTcpForwarding no
|
||||
ChrootDirectory %h
|
||||
ForceCommand internal-sftp
|
||||
'';
|
||||
}
|
||||
116
utils/modules/bitwarden.nix
Normal file
116
utils/modules/bitwarden.nix
Normal file
@@ -0,0 +1,116 @@
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
ldapConfig = {
|
||||
vaultwarden_url = "https://bitwarden.cloonar.com";
|
||||
vaultwarden_admin_token = "@ADMIN_TOKEN@";
|
||||
ldap_host = "localhost";
|
||||
ldap_bind_dn = "cn=vmail,dc=cloonar,dc=com";
|
||||
ldap_bind_password = "@LDAP_PASSWORD@";
|
||||
ldap_search_base_dn = "dc=cloonar,dc=com";
|
||||
ldap_search_filter = "(&(objectClass=inetOrgPerson))";
|
||||
ldap_sync_interval_seconds = 3600;
|
||||
};
|
||||
|
||||
ldapConfigFile =
|
||||
pkgs.runCommand "config.toml"
|
||||
{
|
||||
buildInputs = [pkgs.remarshal];
|
||||
preferLocalBuild = true;
|
||||
} ''
|
||||
remarshal -if json -of toml \
|
||||
< ${pkgs.writeText "config.json" (builtins.toJSON ldapConfig)} \
|
||||
> $out
|
||||
'';
|
||||
in {
|
||||
packageOverrides = pkgs: {
|
||||
nur = import (builtins.fetchTarball "https://github.com/nix-community/NUR/archive/master.tar.gz") {
|
||||
inherit pkgs;
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
nur.repos.mic92.vaultwarden_ldap
|
||||
];
|
||||
|
||||
services.vaultwarden = {
|
||||
enable = true;
|
||||
dbBackend = "mysql";
|
||||
config = {
|
||||
domain = "https://bitwarden.cloonar.com";
|
||||
signupsAllowed = false;
|
||||
rocketPort = 3011;
|
||||
databaseUrl = "mysql://bitwarden:<${config.sops.secrets.bitwarden-db-password.path}@localhost/bitwarden";
|
||||
enableDbWal = "false";
|
||||
websocketEnabled = true;
|
||||
smtpHost = "smtp.cloonar.com";
|
||||
smtpFrom = "bitwarden@cloonar.com";
|
||||
smtpUsername = "bitwarden@cloonar.com";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.vaultwarden.serviceConfig = {
|
||||
EnvironmentFile = [config.sops.secrets.bitwarden-smtp-password.path];
|
||||
};
|
||||
|
||||
systemd.services.vaultwarden_ldap = {
|
||||
wantedBy = ["multi-user.target"];
|
||||
|
||||
preStart = ''
|
||||
sed \
|
||||
-e "s=@LDAP_PASSWORD@=$(<${config.sops.secrets.bitwarden-ldap-password.path})=" \
|
||||
-e "s=@ADMIN_TOKEN@=$(<${config.sops.secrets.bitwarden-admin-token.path})=" \
|
||||
${ldapConfigFile} \
|
||||
> /run/vaultwarden_ldap/config.toml
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
Restart = "on-failure";
|
||||
RestartSec = "2s";
|
||||
ExecStart = "${config.nur.repos.mic92.vaultwarden_ldap}/bin/vaultwarden_ldap";
|
||||
Environment = "CONFIG_PATH=/run/vaultwarden_ldap/config.toml";
|
||||
|
||||
RuntimeDirectory = ["vaultwarden_ldap"];
|
||||
User = "vaultwarden_ldap";
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
virtualHosts."bitwarden.cloonar.com" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
extraConfig = ''
|
||||
client_max_body_size 128M;
|
||||
'';
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:3011";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
locations."/notifications/hub" = {
|
||||
proxyPass = "http://localhost:3012";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
locations."/notifications/hub/negotiate" = {
|
||||
proxyPass = "http://localhost:3011";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
sops.secrets = {
|
||||
bitwarden-admin-token.owner = "vaultwarden_ldap";
|
||||
bitwarden-ldap-password.owner = "vaultwarden_ldap";
|
||||
bitwarden-db-password.owner = "vaultwarden";
|
||||
bitwarden-smtp-password.owner = "vaultwarden";
|
||||
};
|
||||
|
||||
users.users.vaultwarden_ldap = {
|
||||
isSystemUser = true;
|
||||
group = "vaultwarden_ldap";
|
||||
};
|
||||
|
||||
users.groups.vaultwarden_ldap = {};
|
||||
}
|
||||
126
utils/modules/bitwarden/default.nix
Normal file
126
utils/modules/bitwarden/default.nix
Normal file
@@ -0,0 +1,126 @@
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
ldapConfig = {
|
||||
vaultwarden_url = "https://bitwarden.cloonar.com";
|
||||
vaultwarden_admin_token = "@ADMIN_TOKEN@";
|
||||
ldap_host = "ldap.cloonar.com";
|
||||
ldap_ssl = true;
|
||||
ldap_bind_dn = "cn=bitwarden,ou=system,ou=users,dc=cloonar,dc=com";
|
||||
ldap_bind_password = "@LDAP_PASSWORD@";
|
||||
ldap_search_base_dn = "ou=users,dc=cloonar,dc=com";
|
||||
ldap_search_filter = "(&(objectClass=cloonarUser))";
|
||||
ldap_sync_interval_seconds = 3600;
|
||||
};
|
||||
|
||||
ldapConfigFile =
|
||||
pkgs.runCommand "config.toml"
|
||||
{
|
||||
buildInputs = [pkgs.remarshal];
|
||||
preferLocalBuild = true;
|
||||
} ''
|
||||
remarshal -if json -of toml \
|
||||
< ${pkgs.writeText "config.json" (builtins.toJSON ldapConfig)} \
|
||||
> $out
|
||||
'';
|
||||
in {
|
||||
imports = [
|
||||
../nur.nix
|
||||
];
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
nur.repos.mic92.vaultwarden_ldap
|
||||
];
|
||||
|
||||
services.vaultwarden = {
|
||||
enable = true;
|
||||
dbBackend = "mysql";
|
||||
config = {
|
||||
domain = "https://bitwarden.cloonar.com";
|
||||
signupsAllowed = false;
|
||||
rocketPort = 3011;
|
||||
enableDbWal = "false";
|
||||
websocketEnabled = true;
|
||||
smtpHost = "mail.cloonar.com";
|
||||
smtpFrom = "bitwarden@cloonar.com";
|
||||
smtpUsername = "bitwarden@cloonar.com";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.vaultwarden.serviceConfig = {
|
||||
EnvironmentFile = [config.sops.secrets.bitwarden-smtp-password.path];
|
||||
};
|
||||
|
||||
systemd.services.vaultwarden_ldap = {
|
||||
wantedBy = ["multi-user.target"];
|
||||
|
||||
preStart = ''
|
||||
sed \
|
||||
-e "s=@LDAP_PASSWORD@=$(<${config.sops.secrets.bitwarden-ldap-password.path})=" \
|
||||
-e "s=@ADMIN_TOKEN@=$(<${config.sops.secrets.bitwarden-admin-token.path})=" \
|
||||
${ldapConfigFile} \
|
||||
> /run/vaultwarden_ldap/config.toml
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
Restart = "on-failure";
|
||||
RestartSec = "2s";
|
||||
ExecStart = "${pkgs.nur.repos.mic92.vaultwarden_ldap}/bin/vaultwarden_ldap";
|
||||
Environment = "CONFIG_PATH=/run/vaultwarden_ldap/config.toml";
|
||||
|
||||
RuntimeDirectory = ["vaultwarden_ldap"];
|
||||
User = "vaultwarden_ldap";
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."bitwarden.cloonar.com" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
extraConfig = ''
|
||||
client_max_body_size 128M;
|
||||
'';
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:3011";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
locations."/notifications/hub" = {
|
||||
proxyPass = "http://localhost:3012";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
locations."/notifications/hub/negotiate" = {
|
||||
proxyPass = "http://localhost:3011";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
|
||||
sops.secrets = {
|
||||
bitwarden-admin-token = {
|
||||
owner = "vaultwarden_ldap";
|
||||
sopsFile = ./secrets.yaml;
|
||||
};
|
||||
bitwarden-ldap-password = {
|
||||
owner = "vaultwarden_ldap";
|
||||
sopsFile = ./secrets.yaml;
|
||||
};
|
||||
bitwarden-db-password = {
|
||||
owner = "vaultwarden";
|
||||
sopsFile = ./secrets.yaml;
|
||||
};
|
||||
bitwarden-smtp-password = {
|
||||
owner = "vaultwarden";
|
||||
sopsFile = ./secrets.yaml;
|
||||
};
|
||||
};
|
||||
|
||||
users.users.vaultwarden_ldap = {
|
||||
isSystemUser = true;
|
||||
group = "vaultwarden_ldap";
|
||||
};
|
||||
|
||||
users.groups.vaultwarden_ldap = {};
|
||||
|
||||
services.mysqlBackup.databases = [ "bitwarden" ];
|
||||
}
|
||||
33
utils/modules/bitwarden/secrets.yaml
Normal file
33
utils/modules/bitwarden/secrets.yaml
Normal file
@@ -0,0 +1,33 @@
|
||||
bitwarden-admin-token: ENC[AES256_GCM,data:nCj7kwQHTwezG3hh5J+c2MmUXwlGpdNjeh4A4SK/wgdBroAAghMSTuT6B7sjPgX5PmyBpzspdI3XqVUoBHzL6g==,iv:11C/ScaTqI1VlBSd71TA2cZNAu/wSbOs6rnDTlKlPsI=,tag:8eD0VkJn/KZ49yMe4D/MrA==,type:str]
|
||||
bitwarden-db-password: ENC[AES256_GCM,data:4l3ntOHX4pdiUzfSqOwzObgMRp9eS5fjze6rJu1h3kKr/g/lsESLWiIHUoguixaNmoPU2zy42jEDvhXII6R+1g==,iv:mEMGGGyWerJaAvo7ymNfkR1YgTG1ieB3n40BB6L+UM4=,tag:iRd88BjFMMht9Ku9K34SXQ==,type:str]
|
||||
bitwarden-ldap-password: ENC[AES256_GCM,data:g6tp0NzXk3ZJTGKHSzFxVZs4DhauzPS6SGW99WFX/CO0Wprgp9lh/evI6T56g2YhIv/3jqNSmi+p1FwdOzValw==,iv:mHMlhJx2aKLLkrPy+Z+/6plS/uMiK+xhYk/PF5m7+wQ=,tag:BgRNstiVnN95/pSX0DYfSw==,type:str]
|
||||
bitwarden-smtp-password: ENC[AES256_GCM,data:4ruP8yMeTG5A19Oyvv2MBTj2LwecwwYc8BBU1xDT2i757orCNrQHJd0VLtzynluS9ge4vAU7G8islKwR/IIDGsEq74//CxJIyXyH9XLBfc5Jb2Rs1uz/Nz2uCWOCqm1AZ2/8uxXOPPNVhKcs3wxOLbLnA3Yzh+VFKsKIO753FkKllpFbeZanhfD2/N4fAGU4C5F+0HcrLBLBGC3X/CfQyPUSio1uwWPxRJR94DlRdPq+ir4YXHW48Mw/33lJZ+HqApk1Nf+gmTff7XTib1d44ac4JR8m20D8qOQ2Y9vfqJOxD7/PdgeqRLXN3K1PaSDE7JkWoiE0dM3vJ0q+Pqf47tm/xT4qaJvqI0jLXMwqmUg=,iv:TiZrLMPx9UbUf/4zKmRWTERM8phtyTX7Q3dCFqn+Ew4=,tag:55tuxMBWu6WpT4BllKV+pA==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
azure_kv: []
|
||||
hc_vault: []
|
||||
age:
|
||||
- recipient: age16veg3fmvpfm7a89a9fc8dvvsxmsthlm70nfxqspr6t8vnf9wkcwsvdq38d
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMUmttaXRmcXh2UDRyL1pJ
|
||||
MmxMSzBqUmxlY290K1djQ3ZSYWM1OXhFbEhvCjlmNnd6T2Z2bHNZK3oxRmllNUFI
|
||||
RzNvc3hqMXIwd3dwa3crckxVNmNyQXcKLS0tIHFLSXpUOFpyaUVXa2hJU0pheU5h
|
||||
NlZoeVNYdTQ1c0pUQ1o4NnJxaWFTTFEK0l7vHpXj00fUFno5gjS3apPRWercgng6
|
||||
SOygmyQiP/EWI/G0M6W8gjq76pQamYJWVVJVFwxqg4BxAhdMwxtVXQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1y6lvl5jkwc47p5ae9yz9j9kuwhy7rtttua5xhygrgmr7ehd49svsszyt42
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCNjE2c21zVktrTUJDVWJ2
|
||||
UWdqZHErWkpGVnY5Q0F3QUlBNkprRFJFbHpjCnJvQmZoZ0x2c0dxU0FwbExGaTIz
|
||||
eGFoczZma2dBVEJjQ1ljb24zYWJEQWsKLS0tIDVmWWQyYmQ1RS9oV0p0ZmwyUzJI
|
||||
NkdzbFczM0VteW5ESGFNcmNJdFRNODAK8HRoc2thwAH8pvnMwesRs8OesVGHW/Iu
|
||||
viPtt+w6FNwYt4LXnFlBMdGXfrWE0fWxokM0sm5GglKuFGn1zf3+VA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2023-01-28T21:53:06Z"
|
||||
mac: ENC[AES256_GCM,data:jZq4UzkxyX/UhrmeKO7sFQpTlMB13lyi5/duXA0s2XX3W0U9g+TSZm21WiRGPjKmteJg0w2OhFsNk/y0uvD/oPE1ttLz/YRgiinuCoyufoX51AgQqS0KFxNBkTaDzoaKk3z1j8nEhAY2U0YS4fpOCNAkMsKdVZeTVOitcp/UeIE=,iv:5EzYCqUZri1VmD9wqQGxpypZe4F2h8W3D8a7mYbBBrg=,tag:iEFJBFmRJVw4YP5/V+21dQ==,type:str]
|
||||
pgp: []
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.7.3
|
||||
87
utils/modules/borgbackup.nix
Normal file
87
utils/modules/borgbackup.nix
Normal file
@@ -0,0 +1,87 @@
|
||||
{ pkgs, config, lib, ... }:
|
||||
|
||||
let
|
||||
repo = config.borgbackup.repo;
|
||||
#repo = config.borgrepo;
|
||||
#repo = "u149513-sub3@u149513-sub3.your-backup.de:borg";
|
||||
borgMount = pkgs.writeShellScriptBin "borg-mount" ''
|
||||
export BORG_PASSCOMMAND='cat ${config.sops.secrets.borg-passphrase.path}'
|
||||
borg mount --rsh "ssh -p23 -i ${config.sops.secrets.borg-ssh-key.path}" ${repo}::$1 $2
|
||||
'';
|
||||
borgList = pkgs.writeShellScriptBin "borg-list" ''
|
||||
export BORG_PASSCOMMAND='cat ${config.sops.secrets.borg-passphrase.path}'
|
||||
borg --rsh "ssh -p23 -i ${config.sops.secrets.borg-ssh-key.path}" list ${repo}
|
||||
'';
|
||||
|
||||
borgBackup = pkgs.writeShellScriptBin "borg-backup" ''
|
||||
systemctl restart borgbackup-job-default.service
|
||||
'';
|
||||
|
||||
borgRestore = pkgs.writeShellScriptBin "borg-restore" ''
|
||||
cd /
|
||||
export BORG_PASSCOMMAND='cat ${config.sops.secrets.borg-passphrase.path}'
|
||||
borg --rsh "ssh -p23 -i ${config.sops.secrets.borg-ssh-key.path}" list ${repo}
|
||||
borg extract --list --rsh "ssh -p23 -i ${config.sops.secrets.borg-ssh-key.path}" ${repo}::$1
|
||||
'';
|
||||
in {
|
||||
options = with lib; with types; {
|
||||
borgbackup = mkOption {
|
||||
description = "Options for borg module";
|
||||
type = submodule {
|
||||
options.repo = mkOption {
|
||||
type = types.str;
|
||||
description = "borg repo";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
config = {
|
||||
sops.secrets.borg-passphrase = {};
|
||||
sops.secrets.borg-ssh-key = {};
|
||||
|
||||
environment.systemPackages = [
|
||||
borgMount
|
||||
borgList
|
||||
borgBackup
|
||||
borgRestore
|
||||
];
|
||||
|
||||
services.borgbackup.jobs.default = {
|
||||
paths = [
|
||||
"/home"
|
||||
"/var"
|
||||
"/root"
|
||||
];
|
||||
exclude = [
|
||||
"/var/lib/containerd"
|
||||
# already included in database backup
|
||||
"/var/lib/mysql"
|
||||
"/var/lib/postgresql"
|
||||
"/var/lib/docker/"
|
||||
"/var/log"
|
||||
"/var/cache"
|
||||
"/var/tmp"
|
||||
"/var/log"
|
||||
];
|
||||
environment.BORG_RSH = "ssh -p23 -i ${config.sops.secrets.borg-ssh-key.path}";
|
||||
repo = repo;
|
||||
encryption = {
|
||||
mode = "repokey";
|
||||
passCommand = "cat ${config.sops.secrets.borg-passphrase.path}";
|
||||
};
|
||||
compression = "auto,zstd";
|
||||
startAt = "*-*-* 03:00:00";
|
||||
|
||||
prune.keep = {
|
||||
within = "1d"; # Keep all archives from the last day
|
||||
daily = 7;
|
||||
weekly = 4;
|
||||
monthly = 6;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
38
utils/modules/build-netboot/default.nix
Normal file
38
utils/modules/build-netboot/default.nix
Normal file
@@ -0,0 +1,38 @@
|
||||
let
|
||||
# NixOS 22.11 as of 2023-01-12
|
||||
nixpkgs = builtins.getFlake "github:nixos/nixpkgs/54644f409ab471e87014bb305eac8c50190bcf48";
|
||||
|
||||
sys = nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
({ config, pkgs, lib, modulesPath, ... }: {
|
||||
imports = [
|
||||
(modulesPath + "/installer/netboot/netboot-minimal.nix")
|
||||
];
|
||||
config = {
|
||||
## Some useful options for setting up a new system
|
||||
# services.getty.autologinUser = lib.mkForce "root";
|
||||
# users.users.root.openssh.authorizedKeys.keys = [ ... ];
|
||||
# console.keyMap = "de";
|
||||
# hardware.video.hidpi.enable = true;
|
||||
|
||||
system.stateVersion = config.system.nixos.release;
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
run-pixiecore = let
|
||||
hostPkgs = if sys.pkgs.system == builtins.currentSystem
|
||||
then sys.pkgs
|
||||
else nixpkgs.legacyPackages.${builtins.currentSystem};
|
||||
build = sys.config.system.build;
|
||||
in hostPkgs.writers.writeBash "run-pixiecore" ''
|
||||
exec ${hostPkgs.pixiecore}/bin/pixiecore \
|
||||
boot ${build.kernel}/bzImage ${build.netbootRamdisk}/initrd \
|
||||
--cmdline "init=${build.toplevel}/init loglevel=4" \
|
||||
--debug --dhcp-no-bind \
|
||||
--port 64172 --status-port 64172 "$@"
|
||||
'';
|
||||
in
|
||||
run-pixiecore
|
||||
55
utils/modules/clevis.nix
Normal file
55
utils/modules/clevis.nix
Normal file
@@ -0,0 +1,55 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
uuid = "";
|
||||
cfg = config.services.clevis;
|
||||
in
|
||||
{
|
||||
options.services.clevis = {
|
||||
uuid = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = lib.mdDoc ''
|
||||
UUID of device to decrypt with clevis.
|
||||
'';
|
||||
};
|
||||
};
|
||||
config = {
|
||||
environment.systemPackages = with pkgs; [
|
||||
clevis
|
||||
];
|
||||
|
||||
boot.initrd.extraUtilsCommands = ''
|
||||
# clevis dependencies
|
||||
copy_bin_and_libs ${pkgs.curl}/bin/curl
|
||||
copy_bin_and_libs ${pkgs.bash}/bin/bash
|
||||
copy_bin_and_libs ${pkgs.jose}/bin/jose
|
||||
|
||||
# clevis scripts and binaries
|
||||
for i in ${pkgs.clevis}/bin/* ${pkgs.clevis}/bin/.clevis-wrapped; do
|
||||
copy_bin_and_libs "$i"
|
||||
done
|
||||
'';
|
||||
|
||||
boot.initrd.luks.devices."nixos-enc" = {
|
||||
device = "/dev/disk/by-uuid/${cfg.uuid}";
|
||||
preOpenCommands = with pkgs; ''
|
||||
# what would be a sensible way of automating this? at the very least the versions should not be hard coded
|
||||
ln -s ../.. /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${bash.name}
|
||||
ln -s ../.. /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${clevis.name}
|
||||
ln -s ../.. /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${coreutils.name}
|
||||
|
||||
# this runs in the background so that /crypt-ramfs/device gets set up, which implies crypt-askpass
|
||||
# is ready to receive an input which it will write to /crypt-ramfs/passphrase.
|
||||
# for some reason writing that file directly does not seem to work, which is why the pipe is used.
|
||||
# the clevis_luks_unlock_device function is equivalent to the clevis-luks-pass command but avoid
|
||||
# needing to pass the slot argument.
|
||||
# using clevis-luks-unlock directly can successfully open the luks device but requires the name
|
||||
# argument to be passed and will not be detected by the stage-1 luks root stuff.
|
||||
bash -e -c 'while [ ! -f /crypt-ramfs/device ]; do sleep 1; done; . /bin/clevis-luks-common-functions; clevis_luks_unlock_device "$(cat /crypt-ramfs/device)" | cryptsetup-askpass' &
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
60
utils/modules/deconz/default.nix
Normal file
60
utils/modules/deconz/default.nix
Normal file
@@ -0,0 +1,60 @@
|
||||
{ config, lib, pkgs, stdenv, ... }:
|
||||
let
|
||||
deconz-full = pkgs.callPackage ./pkg/default.nix { };
|
||||
deconz = deconz-full.deCONZ;
|
||||
in
|
||||
{
|
||||
environment.systemPackages = with pkgs; [
|
||||
deconz
|
||||
];
|
||||
|
||||
|
||||
users.users."deconz" = {
|
||||
createHome = true;
|
||||
isSystemUser = true;
|
||||
group = "dialout";
|
||||
home = "/home/deconz";
|
||||
};
|
||||
|
||||
systemd.services.deconz = {
|
||||
enable = true;
|
||||
description = "deconz";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
stopIfChanged = false;
|
||||
serviceConfig = {
|
||||
ExecStart = "${deconz}/bin/deCONZ -platform minimal --http-port=8080 --ws-port=8081 --http-listen=127.0.0.1 --dev=/dev/ttyACM0";
|
||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
||||
Restart = "always";
|
||||
RestartSec = "10s";
|
||||
# StartLimitInterval = "1min";
|
||||
# StateDirectory = "/var/lib/deconz";
|
||||
User = "deconz";
|
||||
# DeviceAllow = "char-ttyUSB rwm";
|
||||
# DeviceAllow = "char-usb_device rwm";
|
||||
# AmbientCapabilities="CAP_NET_BIND_SERVICE CAP_KILL CAP_SYS_BOOT CAP_SYS_TIME";
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."deconz.cloonar.com" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
extraConfig = ''
|
||||
proxy_buffering off;
|
||||
'';
|
||||
locations."/".extraConfig = ''
|
||||
set $p 8080;
|
||||
if ($http_upgrade = "websocket") {
|
||||
set $p 8081;
|
||||
}
|
||||
proxy_pass http://127.0.0.1:$p;
|
||||
proxy_set_header Host $host;
|
||||
proxy_redirect http:// https://;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
'';
|
||||
};
|
||||
}
|
||||
50
utils/modules/deconz/pkg/default.nix
Normal file
50
utils/modules/deconz/pkg/default.nix
Normal file
@@ -0,0 +1,50 @@
|
||||
{ config, pkgs, stdenv, buildFHSUserEnv, fetchurl, dpkg, qt5, sqlite, hicolor-icon-theme, libcap, libpng, libxcrypt-legacy, ... }:
|
||||
#ith import <nixpkgs> {};
|
||||
let
|
||||
version = "2.21.02";
|
||||
name = "deconz-${version}";
|
||||
in
|
||||
rec {
|
||||
deCONZ-deb = stdenv.mkDerivation {
|
||||
#builder = ./builder.sh;
|
||||
inherit name;
|
||||
dpkg = dpkg;
|
||||
src = fetchurl {
|
||||
url = "https://deconz.dresden-elektronik.de/ubuntu/stable/${name}-qt5.deb";
|
||||
sha256 = "2d5ab8af471ffa82fb0fd0c8a2f0bb09e7c0bd9a03ef887abe49c616c63042f0";
|
||||
};
|
||||
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
dontStrip = true;
|
||||
|
||||
buildInputs = [ dpkg sqlite hicolor-icon-theme libcap libpng qt5.qtbase qt5.qtserialport qt5.qtwebsockets qt5.wrapQtAppsHook libxcrypt-legacy ]; # qt5.qtserialport qt5.qtwebsockets ];
|
||||
|
||||
unpackPhase = "dpkg-deb -x $src .";
|
||||
installPhase = ''
|
||||
cp -r usr/* .
|
||||
cp -r ${libxcrypt-legacy}/lib/* share/deCONZ/plugins/
|
||||
cp -r share/deCONZ/plugins/* lib/
|
||||
cp -r . $out
|
||||
'';
|
||||
|
||||
};
|
||||
deCONZ = buildFHSUserEnv {
|
||||
name = "deCONZ";
|
||||
targetPkgs = pkgs: [
|
||||
deCONZ-deb
|
||||
];
|
||||
multiPkgs = pkgs: [
|
||||
dpkg
|
||||
qt5.qtbase
|
||||
qt5.qtserialport
|
||||
qt5.qtwebsockets
|
||||
qt5.wrapQtAppsHook
|
||||
sqlite
|
||||
hicolor-icon-theme
|
||||
libcap
|
||||
libpng
|
||||
];
|
||||
runScript = "deCONZ";
|
||||
};
|
||||
}
|
||||
264
utils/modules/dovecot.nix
Normal file
264
utils/modules/dovecot.nix
Normal file
@@ -0,0 +1,264 @@
|
||||
{ pkgs
|
||||
, config
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
domain = config.networking.domain;
|
||||
# domain = "cloonar.com";
|
||||
|
||||
ldapConfig = pkgs.writeText "dovecot-ldap.conf" ''
|
||||
hosts = ldap.cloonar.com
|
||||
tls = yes
|
||||
dn = "cn=vmail,ou=system,ou=users,dc=cloonar,dc=com"
|
||||
dnpass = "@ldap-password@"
|
||||
auth_bind = no
|
||||
ldap_version = 3
|
||||
base = ou=users,dc=%Dd
|
||||
user_filter = (&(objectClass=mailAccount)(mail=%u))
|
||||
user_attrs = \
|
||||
quota=quota_rule=*:bytes=%$, \
|
||||
=home=/var/vmail/%d/%n/, \
|
||||
=mail=maildir:/var/vmail/%d/%n/Maildir
|
||||
pass_attrs = mail=user,userPassword=password
|
||||
pass_filter = (&(objectClass=mailAccount)(mail=%u))
|
||||
iterate_attrs = =user=%{ldap:mail}
|
||||
iterate_filter = (objectClass=mailAccount)
|
||||
scope = subtree
|
||||
default_pass_scheme = CRYPT
|
||||
'';
|
||||
|
||||
doveSync = pkgs.writeShellScriptBin "dove-sync.sh" ''
|
||||
#!/usr/bin/env bash
|
||||
SERVER=''${1}
|
||||
|
||||
if [ -z "$SERVER" ]; then
|
||||
echo "use as dove-sync.sh host.example.com"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
doveadm user *@cloonar.com | while read user; do
|
||||
doveadm -v sync -u $user $SERVER
|
||||
done
|
||||
|
||||
doveadm user *@optiprot.eu | while read user; do
|
||||
doveadm -v sync -u $user $SERVER
|
||||
done
|
||||
|
||||
doveadm user *@superbros.tv | while read user; do
|
||||
doveadm -v sync -u $user $SERVER
|
||||
done
|
||||
|
||||
doveadm user *@ghetto.at | while read user; do
|
||||
doveadm -v sync -u $user $SERVER
|
||||
done
|
||||
|
||||
doveadm user *@szaku-consulting.at | while read user; do
|
||||
doveadm -v sync -u $user $SERVER
|
||||
done
|
||||
'';
|
||||
|
||||
quotaWarning = pkgs.writeShellScriptBin "quota-warning.sh" ''
|
||||
#!/usr/bin/env bash
|
||||
PERCENT=''${1}
|
||||
USER=''${2}
|
||||
|
||||
cat << EOF | /usr/lib/dovecot/deliver -d ''${USER} -o "plugin/quota=dict:User quota::noenforcing:proxy::quotadict"
|
||||
From: no-reply@$(hostname -f)
|
||||
Subject: Warning: Your mailbox is now ''${PERCENT}% full.
|
||||
|
||||
Your mailbox is now ''${PERCENT}% full, please clean up some mails for further incoming mails.
|
||||
EOF
|
||||
|
||||
if [ ''${PERCENT} -ge 95 ]; then
|
||||
DOMAIN="$(echo ''${USER} | awk -F'@' '{print $2}')"
|
||||
cat << EOF | /usr/lib/dovecot/deliver -d postmaster@''${DOMAIN} -o "plugin/quota=dict:User quota::noenforcing:proxy::quotadict"
|
||||
From: no-reply@$(hostname -f)
|
||||
Subject: Mailbox Quota Warning: ''${PERCENT}% full, ''${USER}
|
||||
|
||||
Mailbox (''${USER}) is now ''${PERCENT}% full, please clean up some mails for
|
||||
further incoming mails.
|
||||
EOF
|
||||
fi
|
||||
'';
|
||||
in
|
||||
{
|
||||
environment.systemPackages = with pkgs; [
|
||||
doveSync
|
||||
];
|
||||
|
||||
services.dovecot2 = {
|
||||
enable = true;
|
||||
enableImap = true;
|
||||
enableLmtp = true;
|
||||
enablePAM = false;
|
||||
mailLocation = "maildir:/var/vmail/%d/%n/Maildir";
|
||||
mailUser = "vmail";
|
||||
mailGroup = "vmail";
|
||||
extraConfig = ''
|
||||
ssl = yes
|
||||
ssl_cert = </var/lib/acme/imap.${domain}/fullchain.pem
|
||||
ssl_key = </var/lib/acme/imap.${domain}/key.pem
|
||||
ssl_min_protocol = TLSv1.2
|
||||
ssl_cipher_list = EECDH+AESGCM:EDH+AESGCM
|
||||
ssl_prefer_server_ciphers = yes
|
||||
ssl_dh=<${config.security.dhparams.params.dovecot2.path}
|
||||
|
||||
mail_plugins = virtual fts fts_lucene quota acl
|
||||
|
||||
service lmtp {
|
||||
user = vmail
|
||||
unix_listener /var/lib/postfix/queue/private/dovecot-lmtp {
|
||||
group = postfix
|
||||
mode = 0600
|
||||
user = postfix
|
||||
}
|
||||
}
|
||||
|
||||
service doveadm {
|
||||
inet_listener {
|
||||
port = 4170
|
||||
ssl = yes
|
||||
}
|
||||
}
|
||||
protocol imap {
|
||||
mail_plugins = $mail_plugins imap_quota imap_acl
|
||||
}
|
||||
protocol lmtp {
|
||||
postmaster_address=postmaster@${domain}
|
||||
hostname=mail.cloonar.com
|
||||
mail_plugins = $mail_plugins sieve
|
||||
}
|
||||
service auth {
|
||||
unix_listener auth-userdb {
|
||||
mode = 0640
|
||||
user = vmail
|
||||
group = vmail
|
||||
}
|
||||
# Postfix smtp-auth
|
||||
unix_listener /var/lib/postfix/queue/private/auth {
|
||||
mode = 0666
|
||||
user = postfix
|
||||
group = postfix
|
||||
}
|
||||
}
|
||||
userdb {
|
||||
args = /run/dovecot2/ldap.conf
|
||||
driver = ldap
|
||||
}
|
||||
passdb {
|
||||
args = /run/dovecot2/ldap.conf
|
||||
driver = ldap
|
||||
}
|
||||
|
||||
service imap-login {
|
||||
client_limit = 1000
|
||||
service_count = 0
|
||||
inet_listener imaps {
|
||||
port = 993
|
||||
}
|
||||
}
|
||||
|
||||
service managesieve-login {
|
||||
inet_listener sieve {
|
||||
port = 4190
|
||||
}
|
||||
}
|
||||
service quota-warning {
|
||||
executable = script ${quotaWarning}/bin/quota-warning.sh
|
||||
unix_listener quota-warning {
|
||||
user = vmail
|
||||
group = vmail
|
||||
mode = 0660
|
||||
}
|
||||
}
|
||||
service quota-status {
|
||||
# '-p <protocol>'. Currently only 'postfix' protocol is supported.
|
||||
executable = quota-status -p postfix
|
||||
client_limit = 1
|
||||
inet_listener {
|
||||
address = 127.0.0.1
|
||||
port = 12340
|
||||
}
|
||||
}
|
||||
|
||||
protocol sieve {
|
||||
managesieve_logout_format = bytes ( in=%i : out=%o )
|
||||
}
|
||||
|
||||
plugin {
|
||||
sieve_dir = /var/vmail/%d/%n/sieve/scripts/
|
||||
sieve = /var/vmail/%d/%n/sieve/active-script.sieve
|
||||
sieve_extensions = +vacation-seconds +editheader
|
||||
sieve_vacation_min_period = 1min
|
||||
|
||||
fts = lucene
|
||||
fts_lucene = whitespace_chars=@.
|
||||
|
||||
quota_warning = storage=100%% quota-warning 100 %u
|
||||
quota_warning2 = storage=95%% quota-warning 95 %u
|
||||
quota_warning3 = storage=90%% quota-warning 90 %u
|
||||
quota_warning4 = storage=85%% quota-warning 85 %u
|
||||
|
||||
quota_grace = 10%%
|
||||
|
||||
quota_status_success = DUNNO
|
||||
quota_status_nouser = DUNNO
|
||||
quota_status_overquota = "552 5.2.2 Mailbox is full"
|
||||
}
|
||||
|
||||
# If you have Dovecot v2.2.8+ you may get a significant performance improvement with fetch-headers:
|
||||
imapc_features = $imapc_features fetch-headers
|
||||
# Read multiple mails in parallel, improves performance
|
||||
mail_prefetch_count = 20
|
||||
'';
|
||||
modules = [
|
||||
pkgs.dovecot_pigeonhole
|
||||
];
|
||||
protocols = [
|
||||
"sieve"
|
||||
];
|
||||
};
|
||||
|
||||
users.users.vmail = {
|
||||
home = "/var/vmail";
|
||||
createHome = true;
|
||||
isSystemUser = true;
|
||||
uid = 1000;
|
||||
shell = "/run/current-system/sw/bin/nologin";
|
||||
};
|
||||
|
||||
security.dhparams = {
|
||||
enable = true;
|
||||
params.dovecot2 = { };
|
||||
};
|
||||
|
||||
sops.secrets.dovecot-ldap-password = {
|
||||
sopsFile = ./openldap/secrets.yaml;
|
||||
};
|
||||
|
||||
systemd.services.dovecot2.preStart = ''
|
||||
sed -e "s/@ldap-password@/$(cat ${config.sops.secrets.dovecot-ldap-password.path})/" ${ldapConfig} > /run/dovecot2/ldap.conf
|
||||
'';
|
||||
|
||||
systemd.services.dovecot2 = {
|
||||
wants = [ "acme-imap.${domain}.service" ];
|
||||
after = [ "acme-imap.${domain}.service" ];
|
||||
};
|
||||
|
||||
users.groups.acme.members = [ "openldap" ];
|
||||
|
||||
/* trigger the actual certificate generation for your hostname */
|
||||
security.acme.certs."imap.${domain}" = {
|
||||
extraDomainNames = [
|
||||
"imap-test.${domain}"
|
||||
"imap-02.${domain}"
|
||||
];
|
||||
postRun = "systemctl restart dovecot2.service";
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
143 # imap
|
||||
993 # imaps
|
||||
4190 # sieve
|
||||
];
|
||||
}
|
||||
34
utils/modules/drone-runner.nix
Normal file
34
utils/modules/drone-runner.nix
Normal file
@@ -0,0 +1,34 @@
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
virtualisation.docker.enable = true;
|
||||
|
||||
systemd.services.drone-runner = {
|
||||
description = "Drone Server (CI CD Service)";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ pkgs.docker ];
|
||||
|
||||
serviceConfig = {
|
||||
# Type = "simple";
|
||||
Name = "drone-runner";
|
||||
User = "drone-server";
|
||||
Group = "drone-server";
|
||||
Restart = "always";
|
||||
ExecStartPre= ''
|
||||
-${pkgs.docker}/bin/docker stop %n \
|
||||
-${pkgs.docker}/bin/docker rm %n \
|
||||
${pkgs.docker}/bin/docker pull drone/drone:1
|
||||
'';
|
||||
ExecStart= ''
|
||||
${pkgs.docker}/bin/docker run --rm --name %n \
|
||||
--volume=/var/run/docker.sock:/var/run/docker.sock \
|
||||
--env=DRONE_RPC_PROTO=https \
|
||||
--env=DRONE_RPC_HOST=drone.cloonar.com \
|
||||
--env=DRONE_RPC_SECRET=super-duper-secret \
|
||||
--env=DRONE_RUNNER_CAPACITY=2 \
|
||||
drone/drone-runner-docker:1
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
57
utils/modules/drone-server.nix
Normal file
57
utils/modules/drone-server.nix
Normal file
@@ -0,0 +1,57 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
virtualisation.docker.enable = true;
|
||||
|
||||
users.users.drone-server = {
|
||||
isSystemUser = true;
|
||||
group = "drone-server";
|
||||
home = "/var/lib/drone-server";
|
||||
createHome = true;
|
||||
};
|
||||
users.groups.drone-server = { };
|
||||
users.groups.docker.members = [ "drone-server" ];
|
||||
|
||||
systemd.services.drone-server = {
|
||||
description = "Drone Server (CI CD Service)";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ pkgs.docker ];
|
||||
|
||||
serviceConfig = {
|
||||
# Type = "simple";
|
||||
Name = "drone-server";
|
||||
User = "drone-server";
|
||||
Group = "drone-server";
|
||||
Restart = "always";
|
||||
ExecStartPre= ''
|
||||
-${pkgs.docker}/bin/docker stop %n \
|
||||
-${pkgs.docker}/bin/docker rm %n \
|
||||
${pkgs.docker}/bin/docker pull drone/drone:1
|
||||
'';
|
||||
ExecStart= ''
|
||||
${pkgs.docker}/bin/docker run --rm --name %n \
|
||||
--env=DRONE_AGENTS_ENABLED=true \
|
||||
--env=DRONE_GOGS_SERVER=https://git.cloonar.com \
|
||||
--env=DRONE_GIT_ALWAYS_AUTH=true \
|
||||
--env=DRONE_RPC_SECRET=super-duper-secret \
|
||||
--env=DRONE_SERVER_HOST=drone.cloonar.com \
|
||||
--env=DRONE_SERVER_PROTO=https \
|
||||
--env=DRONE_USER_CREATE=username:dominik.polakovics,admin:true \
|
||||
-v /var/lib/drone-server:/data \
|
||||
--publish=8080:80 \
|
||||
drone/drone:2
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.enable = true;
|
||||
services.nginx.virtualHosts."drone.cloonar.com" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:8080";
|
||||
};
|
||||
};
|
||||
}
|
||||
49
utils/modules/drone/runner.nix
Normal file
49
utils/modules/drone/runner.nix
Normal file
@@ -0,0 +1,49 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
virtualisation.docker.enable = true;
|
||||
|
||||
users.users.drone-runner = {
|
||||
isSystemUser = true;
|
||||
group = "drone-runner";
|
||||
home = "/var/lib/drone-runner";
|
||||
createHome = true;
|
||||
};
|
||||
users.groups.drone-runner = { };
|
||||
users.groups.docker.members = [ "drone-runner" ];
|
||||
|
||||
systemd.services.drone-runner = {
|
||||
description = "Drone Runner (CI CD Service)";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ pkgs.docker ];
|
||||
|
||||
serviceConfig = {
|
||||
# Type = "simple";
|
||||
Name = "drone-runner";
|
||||
User = "drone-runner";
|
||||
Group = "drone-runner";
|
||||
Restart = "always";
|
||||
ExecStartPre= ''
|
||||
-${pkgs.docker}/bin/docker stop %n \
|
||||
-${pkgs.docker}/bin/docker rm %n \
|
||||
${pkgs.docker}/bin/docker pull drone/drone:1
|
||||
'';
|
||||
ExecStart= ''
|
||||
${pkgs.docker}/bin/docker run --rm --name %n \
|
||||
--volume=/var/run/docker.sock:/var/run/docker.sock \
|
||||
--env-file=/run/secrets/drone-runner \
|
||||
--env=DRONE_RPC_PROTO=https \
|
||||
--env=DRONE_RPC_HOST=drone.cloonar.com \
|
||||
--env=DRONE_RUNNER_CAPACITY=2 \
|
||||
drone/drone-runner-docker:1
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
sops.secrets.drone-runner = {
|
||||
sopsFile = ./secrets.yaml;
|
||||
owner = config.systemd.services.drone-runner.serviceConfig.User;
|
||||
key = "drone";
|
||||
};
|
||||
}
|
||||
30
utils/modules/drone/secrets.yaml
Normal file
30
utils/modules/drone/secrets.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
drone: ENC[AES256_GCM,data:Z1Rjso+5XYfvp2xJDXCQkI88GXl83v2oEkMLmOV/rb0DwRmhxCYzYX6fcdidk271Drf1YaPstVvm2LQB38jlBnJtg98aAGegj2fWfT44IbPIi8qDe93M2gFxFDgosoA2eOS2MjEwyBDp9GEUnKyi2gHR8khnTCvegVIntsusWOW/1tbzymKXavZAJUlX+82d/+6NWUEcnbislxhyph8P1Lgw546q,iv:SllCBHlq8ZCBqOHwMaCUcX6D/VDWsbN7uICZKb/R35w=,tag:mEb4E02VUaYGVjyI30FcXA==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
azure_kv: []
|
||||
hc_vault: []
|
||||
age:
|
||||
- recipient: age16veg3fmvpfm7a89a9fc8dvvsxmsthlm70nfxqspr6t8vnf9wkcwsvdq38d
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0OW1JN0hjYjh4cDlmLyt6
|
||||
dHRlSjN6Y1JWUFdzNWlZZ3c0Z2F4bXBCa1NFCjM3b3pPZVhtbDdob3lsR2xlMmJI
|
||||
bjRRMHFjQ2kwWWJKT1p5VW5NVGJuZ3MKLS0tICtRcTFoSmxyeUhaaVlxQUxRWkJl
|
||||
SXR2M293UFBxNFovRnlTQ1o4SzloaEEK+onGdd/7aEF71ibLoLXE5/SbJQWsKigh
|
||||
h8BhfT1z9P5UYNoGHVv8Ry6LndyrBLEv+PUBuT0XJpEVPjKLm99KbQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age106n5n3rrrss45eqqzz8pq90la3kqdtnw63uw0sfa2mahk5xpe30sxs5x58
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyL3dDczRNMjNQUWVjelR5
|
||||
TG93QUFjVGtMNFplaTErOTJjT2dHbWtWUVNzCjNTV0tUY2hpcnp1SDZ4UTB2aFNI
|
||||
M2JwSkdNS0RFQVlPRUNzRG41aW5aS3cKLS0tIEJtaTRXdTI3NGJxZENJTk9jT1hi
|
||||
N3RLRjdkMmZkSmZWZGlYbXRRUTJOZFEK2bJo7iyE3A5ds7tW5bAHgyfGqgH4cRjY
|
||||
hLzYp083QYbXKAqP1w8a3JFXofv1RWd7tUb61I6R4Rd6hXZUv1a5Qw==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2023-02-10T12:35:53Z"
|
||||
mac: ENC[AES256_GCM,data:44J9abLbHkvjAtIUqXVZlcEAnizgg5yxKwyaZhnqIzzebWEpzqcKP6b72blaD7/jSdAiUo7bk/m4BxKVGHf9XKGxyLastbgYoFtz40rsKg9LOKpEfO2kl3JV5dj7C1f8IgsHWZ8L3Vb6KFKcrK2bzjZ5K5p22hCze4lQbK7CZTE=,iv:TE+6juCOTjTrx5nQhi8W5gaZkMFYrEDtoPrGdSTJSNE=,tag:AVsCIkzPjtfk3uSlsv6Dlg==,type:str]
|
||||
pgp: []
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.7.3
|
||||
64
utils/modules/drone/server.nix
Normal file
64
utils/modules/drone/server.nix
Normal file
@@ -0,0 +1,64 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
virtualisation.docker.enable = true;
|
||||
|
||||
users.users.drone-server = {
|
||||
isSystemUser = true;
|
||||
group = "drone-server";
|
||||
home = "/var/lib/drone-server";
|
||||
createHome = true;
|
||||
};
|
||||
users.groups.drone-server = { };
|
||||
users.groups.docker.members = [ "drone-server" ];
|
||||
|
||||
systemd.services.drone-server = {
|
||||
description = "Drone Server (CI CD Service)";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ pkgs.docker ];
|
||||
|
||||
serviceConfig = {
|
||||
# Type = "simple";
|
||||
Name = "drone-server";
|
||||
User = "drone-server";
|
||||
Group = "drone-server";
|
||||
Restart = "always";
|
||||
ExecStartPre= ''
|
||||
-${pkgs.docker}/bin/docker stop %n \
|
||||
-${pkgs.docker}/bin/docker rm %n \
|
||||
${pkgs.docker}/bin/docker pull drone/drone:1
|
||||
'';
|
||||
ExecStart= ''
|
||||
${pkgs.docker}/bin/docker run --rm --name %n \
|
||||
--env-file=/run/secrets/drone-server \
|
||||
--env=DRONE_AGENTS_ENABLED=true \
|
||||
--env=DRONE_GITEA_SERVER=https://git.cloonar.com \
|
||||
--env=DRONE_GITEA_CLIENT_ID=6a7b8c57-bd71-49c8-b67d-c2de68fda649 \
|
||||
--env=DRONE_GIT_ALWAYS_AUTH=true \
|
||||
--env=DRONE_SERVER_HOST=drone.cloonar.com \
|
||||
--env=DRONE_SERVER_PROTO=https \
|
||||
--env=DRONE_USER_CREATE=username:dominik.polakovics,admin:true \
|
||||
-v /var/lib/drone:/data \
|
||||
--publish=8080:80 \
|
||||
drone/drone:2
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.enable = true;
|
||||
services.nginx.virtualHosts."drone.cloonar.com" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:8080";
|
||||
};
|
||||
};
|
||||
|
||||
sops.secrets.drone-server = {
|
||||
sopsFile = ./secrets.yaml;
|
||||
owner = config.systemd.services.drone-server.serviceConfig.User;
|
||||
key = "drone";
|
||||
};
|
||||
}
|
||||
25
utils/modules/gitea.nix
Normal file
25
utils/modules/gitea.nix
Normal file
@@ -0,0 +1,25 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
domain = "git.cloonar.com";
|
||||
in
|
||||
{
|
||||
services.nginx.virtualHosts."${domain}" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:3001/";
|
||||
};
|
||||
};
|
||||
|
||||
services.gitea = {
|
||||
enable = true;
|
||||
appName = "Cloonar Gitea server"; # Give the site a name
|
||||
domain = domain;
|
||||
rootUrl = "https://${domain}/";
|
||||
httpPort = 3001;
|
||||
settings = {
|
||||
service.DISABLE_REGISTRATION = true;
|
||||
webhook.ALLOWED_HOST_LIST = "drone.cloonar.com";
|
||||
};
|
||||
};
|
||||
}
|
||||
28
utils/modules/gnome.nix
Normal file
28
utils/modules/gnome.nix
Normal file
@@ -0,0 +1,28 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
hardware.pulseaudio.enable = false;
|
||||
|
||||
|
||||
services.xserver = {
|
||||
enable = true;
|
||||
libinput.enable = true;
|
||||
displayManager.gdm.enable = true;
|
||||
displayManager.defaultSession = "sway";
|
||||
desktopManager.gnome = {
|
||||
enable = true;
|
||||
extraGSettingsOverrides = ''
|
||||
[org.gnome.desktop.interface]
|
||||
gtk-theme='Dracula'
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
dracula-theme
|
||||
gnome.gnome-tweaks
|
||||
gnome.dconf-editor
|
||||
gnomeExtensions.vitals
|
||||
gnomeExtensions.forge
|
||||
];
|
||||
}
|
||||
37
utils/modules/gogs.nix
Normal file
37
utils/modules/gogs.nix
Normal file
@@ -0,0 +1,37 @@
|
||||
{ config, ... }:
|
||||
|
||||
{
|
||||
services.gogs = {
|
||||
enable = true;
|
||||
domain = "git.cloonar.com";
|
||||
rootUrl = "http://git.cloonar.com/";
|
||||
httpAddress = "git.cloonar.com";
|
||||
httpPort = 3000;
|
||||
extraConfig = ''
|
||||
[server]
|
||||
EXTERNAL_URL = http://git.cloonar.com/
|
||||
[auth]
|
||||
DISABLE_REGISTRATION = true
|
||||
[security]
|
||||
# specific network address, separated by commas, no port needed
|
||||
LOCAL_NETWORK_ALLOWLIST = drone.cloonar.com git-2.cloonar.com
|
||||
'';
|
||||
};
|
||||
|
||||
services.nginx.enable = true;
|
||||
services.nginx.virtualHosts."git.cloonar.com" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
locations."/" = {
|
||||
proxyPass = "http://git.cloonar.com:3000";
|
||||
proxyWebsockets = true;
|
||||
extraConfig =
|
||||
"proxy_connect_timeout 300;" +
|
||||
"proxy_send_timeout 300;" +
|
||||
"proxy_read_timeout 300;" +
|
||||
"send_timeout 300;"
|
||||
;
|
||||
};
|
||||
};
|
||||
}
|
||||
15
utils/modules/gogs/default.nix
Normal file
15
utils/modules/gogs/default.nix
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
services.gogs = {
|
||||
enable = true;
|
||||
domain = "git.cloonar.com";
|
||||
rootUrl = "http://git.cloonar.com/";
|
||||
httpAddress = "git.cloonar.com";
|
||||
httpPort = 3000;
|
||||
extraConfig = ''
|
||||
[server]
|
||||
EXTERNAL_URL = http://git.cloonar.com/
|
||||
[auth]
|
||||
DISABLE_REGISTRATION = true
|
||||
'';
|
||||
};
|
||||
}
|
||||
103
utils/modules/home-assistant/ac.nix
Normal file
103
utils/modules/home-assistant/ac.nix
Normal file
@@ -0,0 +1,103 @@
|
||||
{
|
||||
services.home-assistant.extraComponents = [
|
||||
"daikin"
|
||||
];
|
||||
|
||||
services.home-assistant.config = {
|
||||
sensor = [
|
||||
{
|
||||
name = "Living Room Window Handle";
|
||||
platform = "enocean";
|
||||
id = [ 129 0 227 53 ];
|
||||
device_class = "windowhandle";
|
||||
}
|
||||
];
|
||||
"automation ac_livingroom" = {
|
||||
alias = "ac_livingroom";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = "sensor.windowhandle_living_room_window_handle";
|
||||
to = [ "open" "tilt" ];
|
||||
};
|
||||
action = {
|
||||
service = "climate.set_hvac_mode";
|
||||
target = {
|
||||
entity_id = "climate.livingroom_ac";
|
||||
};
|
||||
data = {
|
||||
hvac_mode = "off";
|
||||
};
|
||||
};
|
||||
};
|
||||
"automation ac_eco" = {
|
||||
alias = "ac_eco";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = [
|
||||
"climate.livingroom_ac"
|
||||
"climate.bedroom_ac"
|
||||
];
|
||||
to = [
|
||||
"heat"
|
||||
"cold"
|
||||
];
|
||||
};
|
||||
action = {
|
||||
service = "climate.set_preset_mode";
|
||||
target = {
|
||||
entity_id = "{{ trigger.entity_id }}";
|
||||
};
|
||||
data = {
|
||||
preset_mode = "eco";
|
||||
};
|
||||
};
|
||||
};
|
||||
"automation bedroom_ac_on" = {
|
||||
alias = "bedroom ac on";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "time";
|
||||
at = "00:30:00";
|
||||
};
|
||||
action = {
|
||||
choose = [
|
||||
{
|
||||
conditions = [ "{{ states('sensor.bedroom_ac_inside_temperature') > 25 and states('sensor.bedroom_ac_outside_temperature') > 22 }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "climate.set_hvac_mode";
|
||||
target = {
|
||||
entity_id = "climate.bedroom_ac";
|
||||
};
|
||||
data = {
|
||||
hvac_mode = "cold";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
"automation bedroom_ac_off" = {
|
||||
alias = "bedroom ac on";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "template";
|
||||
value_template = ''
|
||||
{{ now().timestamp() | timestamp_custom('%H:%M') == (as_timestamp(strptime(states('sensor.bedtime_alarm'), "%H:%M")) - 1800) | timestamp_custom('%H:%M', false) }}
|
||||
'';
|
||||
};
|
||||
action = {
|
||||
service = "climate.set_hvac_mode";
|
||||
target = {
|
||||
entity_id = "climate.bedroom_ac";
|
||||
};
|
||||
data = {
|
||||
hvac_mode = "off";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
31
utils/modules/home-assistant/aeg.nix
Normal file
31
utils/modules/home-assistant/aeg.nix
Normal file
@@ -0,0 +1,31 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.home-assistant.package = pkgs.home-assistant.override {
|
||||
extraPackages = ps: with ps; [ pyelectroluxconnect ];
|
||||
|
||||
packageOverrides = self: super: {
|
||||
pyelectroluxconnect = super.buildPythonPackage rec {
|
||||
pname = "pyelectroluxconnect";
|
||||
version = "0.3.12";
|
||||
|
||||
src = super.fetchPypi {
|
||||
inherit pname version;
|
||||
sha256 = "sha256-g9UxkWuTIqJe0/CDk3kwU3dSmc+GXlfDMxdzu6CqyY0=";
|
||||
};
|
||||
|
||||
doCheck = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
# services.home-assistant.extraPackages = python3Packages: with python3Packages; [
|
||||
# (callPackage ../../pkgs/pyelectroluxconnect.nix)
|
||||
# ];
|
||||
|
||||
services.home-assistant.config = {
|
||||
electrolux_status = {
|
||||
username = "dominik@superbros.tv";
|
||||
password = "U26tTTYtXdhErWpbRxRRVZy541vFvWyn";
|
||||
region = "emea";
|
||||
};
|
||||
};
|
||||
}
|
||||
91
utils/modules/home-assistant/battery.nix
Normal file
91
utils/modules/home-assistant/battery.nix
Normal file
@@ -0,0 +1,91 @@
|
||||
{
|
||||
services.home-assistant.config = {
|
||||
sensor = [
|
||||
{
|
||||
platform = "template";
|
||||
sensors = {
|
||||
sensors_lowest_battery_level = {
|
||||
friendly_name = "Lowest battery level (Sensors)";
|
||||
entity_id = "sun.sun";
|
||||
device_class = "battery";
|
||||
unit_of_measurement = "%";
|
||||
value_template = ''
|
||||
{% set domains = ['sensor', 'battery'] %}
|
||||
{% set ns = namespace(min_batt=100, entities=[]) %}
|
||||
{%- set exclude_sensors = ['sensor.sensors_lowest_battery_level','sensor.dominiks_iphone_battery_level'] -%}
|
||||
{% for domain in domains %}
|
||||
{% set ns.entities = states[domain] %}
|
||||
{% for sensor in exclude_sensors %}
|
||||
{% set ns.entities = ns.entities | rejectattr('entity_id', 'equalto', sensor) %}
|
||||
{% endfor %}
|
||||
{% set batt_sensors = ns.entities | selectattr('attributes.device_class','equalto','battery') | map(attribute='state') | reject('equalto', 'unknown') | reject('equalto', 'None') | map('int') | reject('equalto', 0) | list %}
|
||||
{% set batt_attrs = ns.entities | selectattr('attributes.battery_level','defined') | map(attribute='attributes.battery_level') | reject('equalto', 'unknown') | reject('equalto', 'None') | map('int') | reject('equalto', 0) | list %}
|
||||
{% set batt_lvls = batt_sensors + batt_attrs %}
|
||||
{% if batt_lvls|length > 0 %}
|
||||
{% set _min = batt_lvls|min %}
|
||||
{% if _min < ns.min_batt %}
|
||||
{% set ns.min_batt = _min %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ ns.min_batt }}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
binary_sensor = [
|
||||
{
|
||||
platform = "template";
|
||||
sensors = {
|
||||
sensor_low_battery = {
|
||||
value_template = "{{ states('sensor.sensors_lowest_battery_level')|int <= 30 }}";
|
||||
friendly_name = "A sensor has low battery";
|
||||
device_class = "problem";
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
alert = {
|
||||
sensor_low_battery = {
|
||||
name = "Sensor has low battery!";
|
||||
message = ''
|
||||
{%- set domains = ['sensor', 'battery'] -%}
|
||||
{%- set threshold = 30 -%}
|
||||
{%- set exclude_entities = ['sensor.sensors_lowest_battery_level','sensor.dominiks_iphone_battery_level'] -%}
|
||||
Sensors are below 50% battery:
|
||||
{%- for domain in domains -%}
|
||||
{%- for item in states[domain] -%}
|
||||
{%- if item.entity_id not in exclude_entities -%}
|
||||
{%- if item.attributes.battery_level is defined -%}
|
||||
{%- set level = item.attributes.battery_level|int -%}
|
||||
{% if level > 0 and level < threshold %}
|
||||
- {{ item.attributes.friendly_name }} ({{ item.attributes['battery_level']|int}}%)
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
{%- if item.attributes.device_class is defined and item.attributes.device_class == 'battery' -%}
|
||||
{%- set level = item.state|int -%}
|
||||
{% if level > 0 and level <= threshold %}
|
||||
- {{ item.attributes.friendly_name }} ({{ item.state|int }}%)
|
||||
{%- endif -%}
|
||||
{%- endif %}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- endfor -%}
|
||||
'';
|
||||
entity_id = "binary_sensor.sensor_low_battery";
|
||||
state = "on";
|
||||
repeat = [
|
||||
5
|
||||
60
|
||||
360
|
||||
];
|
||||
skip_first = true;
|
||||
can_acknowledge = true;
|
||||
notifiers = [
|
||||
"NotificationGroup"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
128
utils/modules/home-assistant/default.nix
Normal file
128
utils/modules/home-assistant/default.nix
Normal file
@@ -0,0 +1,128 @@
|
||||
{ pkgs, ... }: {
|
||||
imports = [
|
||||
./ac.nix
|
||||
# ./aeg.nix
|
||||
./battery.nix
|
||||
./ecovacs.nix
|
||||
./enocean.nix
|
||||
./ldap.nix
|
||||
./light.nix
|
||||
./locks.nix
|
||||
./multimedia.nix
|
||||
./notify.nix
|
||||
./pc.nix
|
||||
./presence.nix
|
||||
./pushover.nix
|
||||
./scene-switch.nix
|
||||
./sleep.nix
|
||||
./snapcast.nix
|
||||
];
|
||||
|
||||
services.home-assistant = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
services.home-assistant.extraComponents = [
|
||||
"mobile_app"
|
||||
"shopping_list"
|
||||
"backup"
|
||||
"denonavr"
|
||||
"androidtv"
|
||||
"rainbird"
|
||||
];
|
||||
|
||||
services.home-assistant.config =
|
||||
let
|
||||
hiddenEntities = [
|
||||
"sensor.last_boot"
|
||||
"sensor.date"
|
||||
];
|
||||
in
|
||||
{
|
||||
homeassistant = {
|
||||
name = "Home";
|
||||
latitude = "!secret home_latitude";
|
||||
longitude = "!secret home_longitude";
|
||||
# elevation = "!secret home_elevation";
|
||||
unit_system = "metric";
|
||||
time_zone = "Europe/Vienna";
|
||||
country = "AT";
|
||||
};
|
||||
automation = "!include automations.yaml";
|
||||
frontend = { };
|
||||
http = {
|
||||
use_x_forwarded_for = true;
|
||||
trusted_proxies = [
|
||||
"127.0.0.1"
|
||||
"::1"
|
||||
];
|
||||
};
|
||||
history.exclude = {
|
||||
entities = hiddenEntities;
|
||||
domains = [
|
||||
"automation"
|
||||
"updater"
|
||||
];
|
||||
};
|
||||
"map" = { };
|
||||
enocean = {
|
||||
device = "/dev/serial/by-id/usb-EnOcean_GmbH_EnOcean_USB_300_DC_FT5OI9YG-if00-port0";
|
||||
};
|
||||
# logbook.exclude.entities = "hiddenEntities";
|
||||
logger = {
|
||||
default = "info";
|
||||
};
|
||||
|
||||
#icloud = {
|
||||
# username = "!secret icloud_email";
|
||||
# password = "!secret icloud_password";
|
||||
# with_family = true;
|
||||
#};
|
||||
network = { };
|
||||
zeroconf = { };
|
||||
system_health = { };
|
||||
default_config = { };
|
||||
system_log = { };
|
||||
sensor = [
|
||||
{
|
||||
platform = "template";
|
||||
sensors.bedtime_alarm = {
|
||||
friendly_name = "Bedtime Alarm";
|
||||
value_template = "09:00";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."home-assistant.cloonar.com" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
extraConfig = ''
|
||||
proxy_buffering off;
|
||||
'';
|
||||
locations."/".extraConfig = ''
|
||||
proxy_pass http://127.0.0.1:8123;
|
||||
proxy_set_header Host $host;
|
||||
proxy_redirect http:// https://;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
'';
|
||||
};
|
||||
|
||||
sops.secrets."home-assistant-secrets.yaml" = {
|
||||
sopsFile = ./secrets.yaml;
|
||||
owner = "hass";
|
||||
path = "/var/lib/hass/secrets.yaml";
|
||||
restartUnits = [ "home-assistant.service" ];
|
||||
};
|
||||
|
||||
users.users.hass.extraGroups = [ "dialout" ];
|
||||
|
||||
networking.firewall = {
|
||||
allowedUDPPorts = [ 5683 ];
|
||||
};
|
||||
|
||||
}
|
||||
5
utils/modules/home-assistant/ecovacs.nix
Normal file
5
utils/modules/home-assistant/ecovacs.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
services.home-assistant.extraComponents = [
|
||||
"ecovacs"
|
||||
];
|
||||
}
|
||||
12
utils/modules/home-assistant/enocean.nix
Normal file
12
utils/modules/home-assistant/enocean.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
services.home-assistant.config = {
|
||||
"binary_sensor pc_0" = [
|
||||
{
|
||||
platform = "enocean";
|
||||
id = [ 254 235 105 198 ];
|
||||
name = "enocean_switch_pc";
|
||||
}
|
||||
];
|
||||
logger.logs."homeassistant.components.enocean" = "debug";
|
||||
};
|
||||
}
|
||||
62
utils/modules/home-assistant/ldap.nix
Normal file
62
utils/modules/home-assistant/ldap.nix
Normal file
@@ -0,0 +1,62 @@
|
||||
{ pkgs
|
||||
, config
|
||||
, lib
|
||||
, ... }:
|
||||
let
|
||||
ldap-auth-sh = pkgs.stdenv.mkDerivation {
|
||||
name = "ldap-auth-sh";
|
||||
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "efficiosoft";
|
||||
repo = "ldap-auth-sh";
|
||||
rev = "93b2c00413942908139e37c7432a12bcb705ac87";
|
||||
sha256 = "1pymp6ki353aqkigr89g7hg5x1mny68m31c3inxf1zr26n5s2kz8";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ pkgs.makeWrapper ];
|
||||
installPhase = ''
|
||||
mkdir -p $out/etc
|
||||
cat > $out/etc/home-assistant.cfg << 'EOF'
|
||||
CLIENT="ldapsearch"
|
||||
SERVER="ldaps://ldap.cloonar.com:636"
|
||||
USERDN="cn=home-assistant,ou=system,ou=users,dc=cloonar,dc=com"
|
||||
PW="$(<${config.sops.secrets.home-assistant-ldap.path})"
|
||||
BASEDN="ou=users,dc=cloonar,dc=com"
|
||||
SCOPE="one"
|
||||
FILTER="(&(objectClass=cloonarUser)(memberOf=cn=HomeAssistant,ou=groups,dc=cloonar,dc=com)(mail=$(ldap_dn_escape "$username")))"
|
||||
USERNAME_PATTERN='^[a-z|A-Z|0-9|_|-|.|@]+$'
|
||||
on_auth_success() {
|
||||
# print the meta entries for use in HA
|
||||
if echo "$output" | grep -qE '^(dn|DN):: '; then
|
||||
# ldapsearch base64 encodes non-ascii
|
||||
output=$(echo "$output" | sed -n -e "s/^\(dn\|DN\)\s*::\s*\(.*\)$/\2/p" | base64 -d)
|
||||
else
|
||||
output=$(echo "$output" | sed -n -e "s/^\(dn\|DN\)\s*:\s*\(.*\)$/\2/p")
|
||||
fi
|
||||
name=$(echo "$output" | sed -nr 's/^cn=([^,]+).*/\1/Ip')
|
||||
[ -z "$name" ] || echo "name=$name"
|
||||
}
|
||||
EOF
|
||||
install -D -m755 ldap-auth.sh $out/bin/ldap-auth.sh
|
||||
wrapProgram $out/bin/ldap-auth.sh \
|
||||
--prefix PATH : ${lib.makeBinPath [pkgs.openldap pkgs.coreutils pkgs.gnused pkgs.gnugrep]} \
|
||||
--add-flags "$out/etc/home-assistant.cfg"
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
services.home-assistant.config.homeassistant.auth_providers = [
|
||||
{
|
||||
type = "command_line";
|
||||
command = "${ldap-auth-sh}/bin/ldap-auth.sh";
|
||||
meta = true;
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
sops.secrets.home-assistant-ldap = {
|
||||
sopsFile = ./secrets.yaml;
|
||||
owner = "hass";
|
||||
};
|
||||
}
|
||||
|
||||
335
utils/modules/home-assistant/light.nix
Normal file
335
utils/modules/home-assistant/light.nix
Normal file
@@ -0,0 +1,335 @@
|
||||
{
|
||||
services.home-assistant.extraComponents = [
|
||||
"deconz"
|
||||
"shelly"
|
||||
"sun"
|
||||
];
|
||||
|
||||
services.home-assistant.config = {
|
||||
homeassistant = {
|
||||
customize_domain = {
|
||||
light = {
|
||||
assumed_state = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
"automation light_sunrise" = {
|
||||
alias = "light_sunrise";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "sun";
|
||||
event = "sunrise";
|
||||
};
|
||||
action = {
|
||||
service = "light.turn_on";
|
||||
target = {
|
||||
entity_id = "{{ states.light | selectattr(\"state\",\"eq\",\"on\") | map(attribute=\"entity_id\") | list }}";
|
||||
};
|
||||
data = {
|
||||
brightness_pct = 254;
|
||||
color_temp = 250;
|
||||
};
|
||||
};
|
||||
};
|
||||
"automation light_sunset" = {
|
||||
alias = "light_sunset";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "sun";
|
||||
event = "sunset";
|
||||
};
|
||||
action = {
|
||||
service = "light.turn_on";
|
||||
target = {
|
||||
entity_id = "{{ states.light | selectattr(\"state\",\"eq\",\"on\") | map(attribute=\"entity_id\") | list }}";
|
||||
};
|
||||
data = {
|
||||
brightness_pct = 30;
|
||||
color_temp = 450;
|
||||
};
|
||||
};
|
||||
};
|
||||
"automation light_on" = {
|
||||
alias = "light_on";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = [
|
||||
"light.bed_room"
|
||||
"light.kitchen"
|
||||
"light.livingroom_lights"
|
||||
"light.hallway_lights"
|
||||
"light.bathroom_light"
|
||||
"light.toilett_lights"
|
||||
"light.storage_lights"
|
||||
];
|
||||
to = "on";
|
||||
};
|
||||
action = [
|
||||
{
|
||||
choose = [
|
||||
{
|
||||
conditions = [ "{{ state_attr('sun.sun', 'elevation') < 5 and trigger.entity_id == 'light.toilett_lights' }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "light.turn_on";
|
||||
target = {
|
||||
entity_id = "{{ trigger.entity_id }}";
|
||||
};
|
||||
data = {
|
||||
brightness_pct = 30;
|
||||
color_temp = 450;
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
conditions = [ "{{ state_attr('sun.sun', 'elevation') < 5 and trigger.entity_id == 'light.hallway_lights' }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "light.turn_on";
|
||||
target = {
|
||||
entity_id = "{{ trigger.entity_id }}";
|
||||
};
|
||||
data = {
|
||||
brightness_pct = 1;
|
||||
color_temp = 450;
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
conditions = [ "{{ state_attr('sun.sun', 'elevation') < 5 and trigger.entity_id == 'light.bathroom_light' }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "light.turn_on";
|
||||
target = {
|
||||
entity_id = "{{ trigger.entity_id }}";
|
||||
};
|
||||
data = {
|
||||
brightness_pct = 30;
|
||||
color_temp = 450;
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
conditions = [ "{{ state_attr('sun.sun', 'elevation') < 5 and trigger.entity_id == 'light.livingroom_lights' }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "light.turn_on";
|
||||
target = {
|
||||
entity_id = "{{ trigger.entity_id }}";
|
||||
};
|
||||
data = {
|
||||
brightness_pct = 5;
|
||||
color_temp = 450;
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
conditions = [ "{{ state_attr('sun.sun', 'elevation') < 5 and state_attr(trigger.entity_id, 'is_deconz_group') != None }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "light.turn_on";
|
||||
target = {
|
||||
entity_id = "{{ trigger.entity_id }}";
|
||||
};
|
||||
data = {
|
||||
brightness_pct = 30;
|
||||
color_temp = 450;
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
conditions = [ "{{ state_attr('sun.sun', 'elevation') > 4 }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "light.turn_on";
|
||||
target = {
|
||||
entity_id = "{{ trigger.entity_id }}";
|
||||
};
|
||||
data = {
|
||||
brightness_pct = 100;
|
||||
color_temp = 250;
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
"automation bathroom light small" = {
|
||||
alias = "bathroom light small";
|
||||
mode = "restart";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = [
|
||||
"light.bathroom_switch_channel_1"
|
||||
];
|
||||
from = "on";
|
||||
to = "off";
|
||||
};
|
||||
action = [
|
||||
{
|
||||
service = "switch.turn_off";
|
||||
target = {
|
||||
entity_id = "switch.bathroom_small";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
"automation bathroom light" = {
|
||||
alias = "bathroom light";
|
||||
mode = "restart";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = [
|
||||
"light.bathroom_switch_channel_1"
|
||||
];
|
||||
from = "off";
|
||||
to = "on";
|
||||
};
|
||||
action = [
|
||||
{
|
||||
delay = 3600;
|
||||
}
|
||||
{
|
||||
service = "light.turn_off";
|
||||
target = {
|
||||
entity_id = "light.bathroom_switch_channel_1";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
"automation bed_led" = {
|
||||
alias = "bed_led";
|
||||
mode = "restart";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = [
|
||||
"light.bedroom_led"
|
||||
];
|
||||
from = "off";
|
||||
to = "on";
|
||||
};
|
||||
action = [
|
||||
{
|
||||
delay = 10800;
|
||||
}
|
||||
{
|
||||
service = "light.turn_off";
|
||||
target = {
|
||||
entity_id = "{{ trigger.entity_id }}";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
"automation hallway_motion" = {
|
||||
alias = "Hallway Motion";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = "binary_sensor.hallway_motion_motion";
|
||||
};
|
||||
action = {
|
||||
service_template = "light.turn_{{ trigger.to_state.state }}";
|
||||
target = {
|
||||
entity_id = "light.hallway_lights";
|
||||
};
|
||||
};
|
||||
};
|
||||
"automation bed_button_1" = {
|
||||
alias = "bed_button_1";
|
||||
trigger = {
|
||||
platform = "event";
|
||||
event_type = "shelly.click";
|
||||
event_data = {
|
||||
device = "shellybutton1-E8DB84AA196D";
|
||||
};
|
||||
};
|
||||
action = [
|
||||
{
|
||||
choose = [
|
||||
{
|
||||
conditions = [ "{{ trigger.event.data.click_type == \"single\" }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "light.toggle";
|
||||
entity_id = "light.bed_reading_1";
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
conditions = [ "{{ trigger.event.data.click_type == \"double\" }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "light.toggle";
|
||||
entity_id = "light.bedroom_lights";
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
conditions = [ "{{ trigger.event.data.click_type == \"triple\" }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "light.toggle";
|
||||
entity_id = "light.bedroom_bed";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
"automation bed_button_2" = {
|
||||
alias = "bed_button_2";
|
||||
trigger = {
|
||||
platform = "event";
|
||||
event_type = "shelly.click";
|
||||
event_data = {
|
||||
device = "shellybutton1-E8DB84AA136D";
|
||||
};
|
||||
};
|
||||
action = [
|
||||
{
|
||||
choose = [
|
||||
{
|
||||
conditions = [ "{{ trigger.event.data.click_type == \"single\" }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "light.toggle";
|
||||
entity_id = "light.bed_reading_2";
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
conditions = [ "{{ trigger.event.data.click_type == \"double\" }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "light.toggle";
|
||||
entity_id = "light.bedroom_lights";
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
conditions = [ "{{ trigger.event.data.click_type == \"triple\" }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "light.toggle";
|
||||
entity_id = "light.bedroom_bed";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
117
utils/modules/home-assistant/locks.nix
Normal file
117
utils/modules/home-assistant/locks.nix
Normal file
@@ -0,0 +1,117 @@
|
||||
{
|
||||
services.home-assistant.extraComponents = [
|
||||
"nuki"
|
||||
];
|
||||
|
||||
services.home-assistant.config = {
|
||||
"automation house_door" = {
|
||||
alias = "house_door";
|
||||
mode = "restart";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = [
|
||||
"person.dominik"
|
||||
];
|
||||
from = "not_home";
|
||||
to = "home";
|
||||
};
|
||||
action = [
|
||||
{
|
||||
service = "lock.unlock";
|
||||
target = {
|
||||
entity_id = "lock.house_door";
|
||||
};
|
||||
}
|
||||
{
|
||||
delay = "00:05:00";
|
||||
}
|
||||
{
|
||||
service = "lock.lock";
|
||||
target = {
|
||||
entity_id = "lock.house_door";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
"automation house_door_ring" = {
|
||||
alias = "house_door_ring";
|
||||
trigger = {
|
||||
platform = "event";
|
||||
event_type = "nuki_event";
|
||||
event_data = {
|
||||
type = "ring";
|
||||
};
|
||||
};
|
||||
action = [
|
||||
{
|
||||
choose = [
|
||||
{
|
||||
conditions = [ "{{ state.house_door == \"unlocked\" }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "lock.lock";
|
||||
target = {
|
||||
entity_id = "lock.house_door";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
binary_sensor = [
|
||||
{
|
||||
platform = "template";
|
||||
sensors = {
|
||||
lock_critical_battery = {
|
||||
value_template = ''
|
||||
{% set domains = ['lock'] %}
|
||||
{% set ns = namespace(crit=battery_critical, entities=[]) %}
|
||||
{% for domain in domains %}
|
||||
{% set batt_critical = states[domain] | selectattr('attributes.battery_critical','defined') | map(attribute='attributes.battery_critical') | reject('equalto', 'unknown') | reject('equalto', 'None') | map('int') | reject('equalto', 0) | list %}
|
||||
{% if batt_critical|length > 0 %}
|
||||
{% set ns.battery_critical = true %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ ns.battery_critical }}
|
||||
'';
|
||||
friendly_name = "A lock has critical battery";
|
||||
device_class = "problem";
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
alert = {
|
||||
battery_critical = {
|
||||
name = "Lock has low battery!";
|
||||
message = ''
|
||||
{%- set domains = ['lock'] -%}
|
||||
Lock battery is critical:
|
||||
{%- for domain in domains -%}
|
||||
{%- for item in states[domain] -%}
|
||||
{%- if item.attributes.battery_critical is defined -%}
|
||||
{% if item.attributes.battery_critical %}
|
||||
- {{ item.attributes.friendly_name }}
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- endfor -%}
|
||||
'';
|
||||
entity_id = "binary_sensor.lock_critical_battery";
|
||||
state = "on";
|
||||
repeat = [
|
||||
5
|
||||
60
|
||||
360
|
||||
];
|
||||
skip_first = true;
|
||||
can_acknowledge = true;
|
||||
notifiers = [
|
||||
"NotificationGroup"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
253
utils/modules/home-assistant/multimedia.nix
Normal file
253
utils/modules/home-assistant/multimedia.nix
Normal file
@@ -0,0 +1,253 @@
|
||||
{
|
||||
services.home-assistant.config = {
|
||||
binary_sensor = [
|
||||
{
|
||||
name = "ps5_living";
|
||||
platform = "command_line";
|
||||
command = "python /var/lib/hass/ps5.py -q -b 10.42.96.176";
|
||||
device_class = "connectivity";
|
||||
scan_interval = 5;
|
||||
}
|
||||
{
|
||||
platform = "template";
|
||||
sensors = {
|
||||
multimedia_device_on = {
|
||||
friendly_name = "Any multimedia device on";
|
||||
device_class = "connectivity";
|
||||
value_template = ''
|
||||
{% if is_state('binary_sensor.ps5_living', 'on') or states('media_player.fire_tv_firetv_living_cloonar_com') != 'off' or states('device_tracker.xbox') == 'home' %}
|
||||
on
|
||||
{% else %}
|
||||
off
|
||||
{% endif %}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
# "automation tv scene" = {
|
||||
# alias = "auto tv scene";
|
||||
# hide_entity = true;
|
||||
# trigger = {
|
||||
# platform = "event";
|
||||
# event_type = "button_pressed";
|
||||
# event_data = {
|
||||
# id = [ 254 235 105 198 ];
|
||||
# };
|
||||
# };
|
||||
# action = {
|
||||
# service_template = "switch.turn_on";
|
||||
# data_template = {
|
||||
# entity_id = "switch.computer";
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
# "automation beamer switch" = {
|
||||
# alias = "auto beamer scene";
|
||||
# hide_entity = true;
|
||||
# trigger = {
|
||||
# platform = "state";
|
||||
# entity_id = "sensor.computer_power";
|
||||
# };
|
||||
# condition = {
|
||||
# condition = "and";
|
||||
# conditions = [
|
||||
# {
|
||||
# condition = "numeric_state";
|
||||
# entity_id = "sensor.computer_power";
|
||||
# below = 15;
|
||||
# }
|
||||
# "{{ (as_timestamp(now()) - as_timestamp(states.switch.computer.last_changed)) > 300 }}"
|
||||
# ];
|
||||
# };
|
||||
# action = {
|
||||
# service = "switch.turn_off";
|
||||
# target = {
|
||||
# entity_id = [ "switch.computer" ];
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
"automation xbox on" = {
|
||||
alias = "xbox on";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = "device-tracker.xbox";
|
||||
to = "home";
|
||||
};
|
||||
action = [
|
||||
{
|
||||
service = "denonavr.get_command";
|
||||
target = {
|
||||
entity_id = "media_player.marantz_sr6015";
|
||||
};
|
||||
data = {
|
||||
command = "/goform/formiPhoneAppDirect.xml?SIGAME";
|
||||
};
|
||||
}
|
||||
{
|
||||
delay = 5;
|
||||
}
|
||||
{
|
||||
service = "denonavr.get_command";
|
||||
target = {
|
||||
entity_id = "media_player.marantz_sr6015";
|
||||
};
|
||||
data = {
|
||||
command = "/goform/formiPhoneAppDirect.xml?PWSTANDBY";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
"automation firetv on" = {
|
||||
alias = "firetv on";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = "media_player.fire_tv_firetv_living_cloonar_com";
|
||||
from = "off";
|
||||
};
|
||||
action = [
|
||||
{
|
||||
service = "denonavr.get_command";
|
||||
target = {
|
||||
entity_id = "media_player.marantz_sr6015";
|
||||
};
|
||||
data = {
|
||||
command = "/goform/formiPhoneAppDirect.xml?SIMPLAY";
|
||||
};
|
||||
}
|
||||
{
|
||||
delay = 5;
|
||||
}
|
||||
{
|
||||
service = "denonavr.get_command";
|
||||
target = {
|
||||
entity_id = "media_player.marantz_sr6015";
|
||||
};
|
||||
data = {
|
||||
command = "/goform/formiPhoneAppDirect.xml?PWSTANDBY";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
"automation ps5 on" = {
|
||||
alias = "ps5 on";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = "binary_sensor.ps5_living";
|
||||
to = "on";
|
||||
};
|
||||
action = [
|
||||
{
|
||||
service = "denonavr.get_command";
|
||||
target = {
|
||||
entity_id = "media_player.marantz_sr6015";
|
||||
};
|
||||
data = {
|
||||
command = "/goform/formiPhoneAppDirect.xml?SIBD";
|
||||
};
|
||||
}
|
||||
{
|
||||
delay = 5;
|
||||
}
|
||||
{
|
||||
service = "denonavr.get_command";
|
||||
target = {
|
||||
entity_id = "media_player.marantz_sr6015";
|
||||
};
|
||||
data = {
|
||||
command = "/goform/formiPhoneAppDirect.xml?PWSTANDBY";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
"automation all multimedia off" = {
|
||||
alias = "all multimedia off";
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = "binary_sensor.multimedia_device_on";
|
||||
to = "off";
|
||||
};
|
||||
action = [
|
||||
{
|
||||
service = "androidtv.adb_command";
|
||||
target = {
|
||||
device_id = "a5e50f268f3a2dbd0741fb8e9ff7f931";
|
||||
};
|
||||
data = {
|
||||
command = "POWER";
|
||||
};
|
||||
}
|
||||
{
|
||||
service = "denonavr.get_command";
|
||||
target = {
|
||||
entity_id = "media_player.marantz_sr6015";
|
||||
};
|
||||
data = {
|
||||
command = "/goform/formiPhoneAppDirect.xml?PWSTANDBY";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
"automation all_multimedia_on" = {
|
||||
alias = "all multimedia on";
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = "binary_sensor.multimedia_device_on";
|
||||
to = "on";
|
||||
};
|
||||
condition = {
|
||||
condition = "or";
|
||||
conditions = [
|
||||
{
|
||||
condition = "state";
|
||||
entity_id = "media_player.android_tv_metz_cloonar_com";
|
||||
state = "off";
|
||||
}
|
||||
{
|
||||
condition = "state";
|
||||
entity_id = "media_player.android_tv_metz_cloonar_com";
|
||||
state = "unavailable";
|
||||
}
|
||||
];
|
||||
};
|
||||
action = [
|
||||
{
|
||||
service = "androidtv.adb_command";
|
||||
target = {
|
||||
device_id = "a5e50f268f3a2dbd0741fb8e9ff7f931";
|
||||
};
|
||||
data = {
|
||||
command = "POWER";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
# "automation multimedia input" = {
|
||||
# hide_entity = true;
|
||||
# trigger = {
|
||||
# platform = "state";
|
||||
# entity_id = "sensor.computer_power";
|
||||
# };
|
||||
# condition = {
|
||||
# condition = "and";
|
||||
# conditions = [
|
||||
# {
|
||||
# condition = "numeric_state";
|
||||
# entity_id = "sensor.computer_power";
|
||||
# below = 15;
|
||||
# }
|
||||
# "{{ (as_timestamp(now()) - as_timestamp(states.switch.computer.last_changed)) > 300 }}"
|
||||
# ];
|
||||
# };
|
||||
# action = {
|
||||
# service = "switch.turn_off";
|
||||
# target = {
|
||||
# entity_id = [ "switch.computer" ];
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
};
|
||||
}
|
||||
65
utils/modules/home-assistant/music.nix
Normal file
65
utils/modules/home-assistant/music.nix
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
services.home-assistant.extraComponents = [
|
||||
"nuki"
|
||||
];
|
||||
|
||||
services.home-assistant.config = {
|
||||
"automation house_door" = {
|
||||
alias = "house_door";
|
||||
mode = "restart";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = [
|
||||
"person.dominik"
|
||||
];
|
||||
from = "not_home";
|
||||
to = "home";
|
||||
};
|
||||
action = [
|
||||
{
|
||||
service = "lock.unlock";
|
||||
target = {
|
||||
entity_id = "lock.house_door";
|
||||
};
|
||||
}
|
||||
{
|
||||
delay = "00:05:00";
|
||||
}
|
||||
{
|
||||
service = "lock.lock";
|
||||
target = {
|
||||
entity_id = "lock.house_door";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
"automation house_door_ring" = {
|
||||
alias = "house_door_ring";
|
||||
trigger = {
|
||||
platform = "event";
|
||||
event_type = "nuki_event";
|
||||
event_data = {
|
||||
type = "ring";
|
||||
};
|
||||
};
|
||||
action = [
|
||||
{
|
||||
choose = [
|
||||
{
|
||||
conditions = [ "{{ state.house_door == \"unlocked\" }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "lock.lock";
|
||||
target = {
|
||||
entity_id = "lock.house_door";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
15
utils/modules/home-assistant/notify.nix
Normal file
15
utils/modules/home-assistant/notify.nix
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
services.home-assistant.config = {
|
||||
notify = [
|
||||
{
|
||||
name = "NotificationGroup";
|
||||
platform = "group";
|
||||
services = [
|
||||
{
|
||||
service = "pushover_dominik";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
46
utils/modules/home-assistant/pc.nix
Normal file
46
utils/modules/home-assistant/pc.nix
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
services.home-assistant.config = {
|
||||
"automation pc_switch" = {
|
||||
alias = "switch pc";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "event";
|
||||
event_type = "button_pressed";
|
||||
event_data = {
|
||||
id = [ 254 235 105 198 ];
|
||||
};
|
||||
};
|
||||
action = {
|
||||
service_template = "switch.turn_on";
|
||||
data_template = {
|
||||
entity_id = "switch.computer";
|
||||
};
|
||||
};
|
||||
};
|
||||
"automation pc power" = {
|
||||
alias = "auto pc power off";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = "sensor.computer_power";
|
||||
};
|
||||
condition = {
|
||||
condition = "and";
|
||||
conditions = [
|
||||
{
|
||||
condition = "numeric_state";
|
||||
entity_id = "sensor.computer_power";
|
||||
below = 15;
|
||||
}
|
||||
"{{ (as_timestamp(now()) - as_timestamp(states.switch.computer.last_changed)) > 300 }}"
|
||||
];
|
||||
};
|
||||
action = {
|
||||
service = "switch.turn_off";
|
||||
target = {
|
||||
entity_id = [ "switch.computer" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
23
utils/modules/home-assistant/presence.nix
Normal file
23
utils/modules/home-assistant/presence.nix
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
services.home-assistant.extraComponents = [
|
||||
"mqtt_room"
|
||||
"opnsense"
|
||||
];
|
||||
services.home-assistant.config = {
|
||||
opnsense = {
|
||||
url = "https://fw.cloonar.com/api";
|
||||
api_secret = "!secret opnsense_api_secret";
|
||||
api_key = "!secret opnsense_api_key";
|
||||
};
|
||||
sensor = [
|
||||
{
|
||||
platform = "mqtt_room";
|
||||
name = "Dominiks iPhone BLE";
|
||||
device_id = "roomAssistant:d2a41d13-16bf-41fb-af4b-c520bdc7b68a";
|
||||
# device_id = "0a666fe0ccd0d587414fec9b9946168f";
|
||||
state_topic = "espresense/rooms";
|
||||
away_timeout = 30;
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
37
utils/modules/home-assistant/ps5.nix
Normal file
37
utils/modules/home-assistant/ps5.nix
Normal file
@@ -0,0 +1,37 @@
|
||||
{ config, ... }:
|
||||
{
|
||||
config.sops.secrets.ps5-mqtt-env = {
|
||||
sopsFile = ./secrets.yaml;
|
||||
restartUnits = [ "podman-ps5Mqtt.service" ];
|
||||
};
|
||||
|
||||
config.virtualisation.oci-containers.containers = {
|
||||
ps5Mqtt = {
|
||||
image = "ghcr.io/funkeyflo/ps5-mqtt/amd64:latest ";
|
||||
# ports = ["127.0.0.1:8645:8645"];
|
||||
volumes = [
|
||||
"/var/lib/ps5-mqtt:/config"
|
||||
];
|
||||
# entrypoint = "/config/run.sh";
|
||||
entrypoint = "/usr/bin/node";
|
||||
cmd = [
|
||||
"app/server/dist/index.js"
|
||||
];
|
||||
# entrypoint = "/bin/bash";
|
||||
# cmd = [
|
||||
# "-c \"echo $MQTT_HOST\""
|
||||
# ];
|
||||
environmentFiles = [
|
||||
config.sops.secrets.ps5-mqtt-env.path
|
||||
];
|
||||
extraOptions = [
|
||||
"--network=host"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
config.networking.firewall = {
|
||||
enable = true;
|
||||
allowedTCPPorts = [ 8645 ];
|
||||
};
|
||||
}
|
||||
16
utils/modules/home-assistant/pushover.nix
Normal file
16
utils/modules/home-assistant/pushover.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
services.home-assistant.extraComponents = [
|
||||
"pushover"
|
||||
];
|
||||
|
||||
# services.home-assistant.config = {
|
||||
# notify = [
|
||||
# {
|
||||
# name = "pushover_dominik";
|
||||
# platform = "pushover";
|
||||
# api_key = "!secret pushover_dominik_api_key";
|
||||
# user_key = "!secret pushover_dominik_user_key";
|
||||
# }
|
||||
# ];
|
||||
# };
|
||||
}
|
||||
21
utils/modules/home-assistant/scene-switch.nix
Normal file
21
utils/modules/home-assistant/scene-switch.nix
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
services.home-assistant.config = {
|
||||
"automation scene_switch" = {
|
||||
alias = "switch scene";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "event";
|
||||
event_type = "button_pressed";
|
||||
event_data = {
|
||||
id = [ 254 242 234 134 ];
|
||||
};
|
||||
};
|
||||
action = {
|
||||
service_template = "switch.turn_on";
|
||||
data_template = {
|
||||
entity_id = "switch.computer";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
32
utils/modules/home-assistant/secrets.yaml
Normal file
32
utils/modules/home-assistant/secrets.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
home-assistant-ldap: ENC[AES256_GCM,data:De7kuRji+flc0juqE3z1MyNo938Y18jhYtxHkvBX1AsmcJO6a37qJ6o9eCVyhcN/uyaS8cySucqKErh3SlCOZw==,iv:DD4Bp7yU0TCQ/Zeildmrt1HSUbuJgQ0L2UUSmMi6Obo=,tag:t1Hz0GiXzodVK64e0Xuf6g==,type:str]
|
||||
home-assistant-secrets.yaml: ENC[AES256_GCM,data:owCBlfPXA66zxGaMwo6mViSZS7f3WPXOTtWiWFR8R/9Cqv7YvIaY7cqYX1OYFfEJyMyq6YLhVV9Zi0/K40VtUmhgR324x/knQbKkZGxv6gwqdIZ/zaZgQIu29xtY4DQnK24/5942HtisSnQnJxgbpchnjJCAQqri2/68LjGh8GoJVhF34Zji0MHBLAxR1y5JApOb5GUpc0ftMu4j6cbU/qxiZbRkzbrjlgAjBFjARYmsaWiilXg5jT2pf0Fz6bOHslcO+b3qePgIb/cJPP9aVYy76QA0oZ03f3Qu0w+IsjBKuXGaWKVBWBDyK1E37Y/Xif8w3H3cPqkAI6qxCPXi7djYfEpOz2M1L+5GTJGJz8fmvYzVJqU+hpZeI/7qJdiQ4/98YfuDU6nTEwWumcsPKsafJzdSeVfFYcE2x1H+QJDfJ3sgWJkfLDOrRxaXIwoXeSBSYAXPxjdomBzcdgKvo8MBH47pDbR4hK+y8+0LnoPafIyh8+FeAFzbn6/9ScWzF/MOyxFnap3edd12k5yWN+Yc4xacye3RR1h/mp1+DQF9xZ1xMTE70nwNdtIsGU0cV8qUvPgknZB/0US2oZ19fdxVuAN2rneEkK/nIGoKVw==,iv:x/F8CnsxROweCosvX1yAMHzwtI34kGauPvWF8yu2Yf8=,tag:WbzjtVhEPgUhL8g07kHjdA==,type:str]
|
||||
ps5-mqtt-env: ENC[AES256_GCM,data:g079HmYjMQ/Dr/vHSuxnLDwyOG3bSmzGtUfQLXJgKFUoC+5dAyUwYu8WRD1hskER2v8yIz2oHx8dQXLuWsmKYRErk6Sybpe0+FOcqOvAXgzv1ow95sjClkrS+rwjHcoHb1nts5lP5bGkY0e4Z6Dfn5AoeQ4pEA1TOzANvPDqDZUBh+L4hUDkDSWg7sAH3pHK0BqZHwiDNrvE9ac8MFHJmrPVEr4dqhRwAip+YMAdGCwp0ofdm2amUL7aHTaCQhjgsAW306C8ksMwuFE+dAvsqJGZ1N5T2nxP9LYVWcc8ZsKV8VklZ/QS6ScBGz4Oi4YpPDvkt+ErY929t0vISjKengnDHhu/+WYaBxeVbre5G29hK+jrnmUHFBa6pjwCSFVJq8mRIn6KorGwltxObyFBxddf+kiAMDbvnqW3E6sZtW+mF+48hTD8ygjSE8D8h7IoyYYTh0nPY4DzkfMR2OXqpz+bh+dpjnh3UQktJ1HXh902A2ljmxUEMGWtcOc2fDTxEMheTqdvg2z7Ek/FIwq/curVbdHIrzeIXDis7LIRk4G8b4mA6nHG4KrzCF00LAV7Ph9Nx1wAgrxvBTq4bqnO2VP44vtDsQ/O+Dr+wZSlP3EL4PsAJznfa7YcvStvV1Nn6FrVY04W,iv:1vttyQqYffChK12Wy5KTZEZ00pESsMefXHbulKsDSqU=,tag:pzgw0jJqICaro2U2FfQEiA==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
azure_kv: []
|
||||
hc_vault: []
|
||||
age:
|
||||
- recipient: age16veg3fmvpfm7a89a9fc8dvvsxmsthlm70nfxqspr6t8vnf9wkcwsvdq38d
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBieVNmLy9zK1hXWHdGRHF3
|
||||
WXd5b0pjR0pBaFkvVSt5ZVNyaUlCL0R1c2lnCkRCY1RmZnY1UVFuWURUMElHcFU1
|
||||
WHgrZE5ZY3FQUVp2VkhIcHh3WDV4aUUKLS0tIGFRZFNsKzU4ZDhPQ0NLbmtPSEJB
|
||||
YW8zNjhYWGNRcy9VbEZoaWplakVNWkUK48LBhFusDMZj2momMwRXdU7bLiGvzvqX
|
||||
QwdxorLMP2/GW6x5xpFj1khLCwxYDOys4xGvmE89hYZa++OSYU+Ejw==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1ezq2j34qngky22enhnslx6hzh4ekwk8dtmn6c9us0uqxqpn7hgpsspjz58
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwY0pGaUU3alJrYmhQM2Y4
|
||||
TTMrbGsrRThlTUN1R3RCbFZFeVR1KzVDMWg4CnlQTzBzdTNPMTFvTUVYRXFEbUVP
|
||||
YWFvRTJqZjcxZHhtRkJrajNuUWoyYzgKLS0tIEhVcFI4N0E4VEVOZDIxREJ4bkNi
|
||||
UjRhRVpkTHF5a3p2bjhiVDZwMWRWMkEKpsHLWcPGQWpBo4Z8h7XFOP0bCct83BPj
|
||||
d/QDjarzugd6jamWVXKidZwADxfP59Pvo9JmLlFL5isgZ1TL3ZHL+g==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2023-04-26T13:33:07Z"
|
||||
mac: ENC[AES256_GCM,data:i/2+Qr0ihMaDPF22pyo7Qy3SYEr0Fr5dfRJSZ9xMu/5TFSm3GXNhd2KZVXjl6isbPbD22/siuI2MZeSB/iTFcRadtswmGnb6Lgsi8K/LULKvwXHf5t/Py/z59CpXBSgfUQQ6BuodNc25DRpCX8HEhFfd3Ajgyavc8vHVpnwG8eQ=,iv:Xu3WsyIqDbtReP9pBsiEf17pAbdVrY/y6wM2dleguFQ=,tag:gh6m7MUzMx2/lsZ5XExwyw==,type:str]
|
||||
pgp: []
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.7.3
|
||||
16
utils/modules/home-assistant/shelly.nix
Normal file
16
utils/modules/home-assistant/shelly.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
services.home-assistant.config.shelly = {
|
||||
FindAndroid = {
|
||||
speech.text = "Send notification";
|
||||
action = {
|
||||
service = "notify.pushover";
|
||||
data = {
|
||||
message = "Phonefinderalert";
|
||||
target = "android";
|
||||
data.sound = "echo";
|
||||
data.priority = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
59
utils/modules/home-assistant/sleep.nix
Normal file
59
utils/modules/home-assistant/sleep.nix
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
services.home-assistant.config = {
|
||||
"automation wakeup" = {
|
||||
alias = "wakeup";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "template";
|
||||
value_template = ''
|
||||
{{ now().timestamp() | timestamp_custom('%H:%M') == (as_timestamp(strptime(states('sensor.bedtime_alarm'), "%H:%M")) - 1800) | timestamp_custom('%H:%M', false) }}
|
||||
'';
|
||||
};
|
||||
action = {
|
||||
service_template = "switch.turn_on";
|
||||
data_template = {
|
||||
entity_id = "switch.coffee_switch";
|
||||
};
|
||||
};
|
||||
};
|
||||
"automation sleep" = {
|
||||
alias = "sleep";
|
||||
hide_entity = true;
|
||||
trigger = [
|
||||
{
|
||||
platform = "event";
|
||||
event_type = "shelly.click";
|
||||
event_data = {
|
||||
device = "shellybutton1-E8DB84AA196D";
|
||||
};
|
||||
}
|
||||
{
|
||||
platform = "event";
|
||||
event_type = "shelly.click";
|
||||
event_data = {
|
||||
device = "shellybutton1-E8DB84AA136D";
|
||||
};
|
||||
}
|
||||
];
|
||||
action = [
|
||||
{
|
||||
choose = [
|
||||
{
|
||||
conditions = [ "{{ trigger.event.data.click_type == \"long\" }}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "light.turn_off";
|
||||
entity_id = "all";
|
||||
}
|
||||
{
|
||||
service = "light.turn_on";
|
||||
entity_id = "light.bedroom_bed";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
66
utils/modules/home-assistant/snapcast.nix
Normal file
66
utils/modules/home-assistant/snapcast.nix
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
services.home-assistant = {
|
||||
extraComponents = [ "snapcast" ];
|
||||
config = {
|
||||
# "media_player" = {
|
||||
# platform = "snapcast";
|
||||
# host = "snapcast.cloonar.com";
|
||||
# };
|
||||
"automation toilett_music" = {
|
||||
alias = "toilett music";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = "light.toilett_switch";
|
||||
};
|
||||
action = {
|
||||
choose = [
|
||||
{
|
||||
conditions = [ "{{trigger.to_state.state == 'on'}}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "media_player.volume_mute";
|
||||
target = {
|
||||
entity_id = "media_player.snapcast_client_e4_5f_01_3c_fb_c3";
|
||||
};
|
||||
data = {
|
||||
is_volume_muted = false;
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
conditions = [ "{{trigger.to_state.state == 'off'}}" ];
|
||||
sequence = [
|
||||
{
|
||||
service = "media_player.volume_mute";
|
||||
target = {
|
||||
entity_id = "media_player.snapcast_client_e4_5f_01_3c_fb_c3";
|
||||
};
|
||||
data = {
|
||||
is_volume_muted = true;
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
"automation piano" = {
|
||||
alias = "piano";
|
||||
hide_entity = true;
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = "media_player.snapcast_client_e4_5f_01_96_c1_1e";
|
||||
attribute = "is_volume_muted";
|
||||
};
|
||||
action = {
|
||||
service = "switch.turn_on";
|
||||
target = {
|
||||
entity_id = "switch.piano_switch_power";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
90
utils/modules/howdy.nix
Normal file
90
utils/modules/howdy.nix
Normal file
@@ -0,0 +1,90 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.howdy;
|
||||
ircfg = config.services.ir-toggle;
|
||||
|
||||
# `dark_threshold` is required for X1 Carbon 7th to work
|
||||
configINI = pkgs.runCommand "config.ini" { } ''
|
||||
cat ${cfg.package}/lib/security/howdy/config.ini > $out
|
||||
substituteInPlace $out --replace 'device_path = none' 'device_path = ${cfg.device}'
|
||||
substituteInPlace $out --replace 'dark_threshold = 50' 'dark_threshold = ${
|
||||
toString cfg.dark-threshold
|
||||
}'
|
||||
substituteInPlace $out --replace 'certainty = 3.5' 'certainty = ${
|
||||
toString cfg.certainty
|
||||
}'
|
||||
'';
|
||||
pam-rule = pkgs.lib.mkDefault (pkgs.lib.mkBefore
|
||||
"auth sufficient ${pkgs.pam_python}/lib/security/pam_python.so ${config.services.howdy.package}/lib/security/howdy/pam.py");
|
||||
in {
|
||||
options = {
|
||||
services.ir-toggle = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable Chicony IR Emitter toggler.
|
||||
'';
|
||||
};
|
||||
};
|
||||
services.howdy = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable howdy and PAM module for face recognition.
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.howdy;
|
||||
defaultText = "pkgs.howdy";
|
||||
description = ''
|
||||
Howdy package to use.
|
||||
'';
|
||||
};
|
||||
|
||||
device = mkOption {
|
||||
type = types.path;
|
||||
default = "/dev/video0";
|
||||
description = ''
|
||||
Device file connected to the IR sensor.
|
||||
'';
|
||||
};
|
||||
|
||||
certainty = mkOption {
|
||||
type = types.int;
|
||||
default = 3.5;
|
||||
description = ''
|
||||
The certainty of the detected face belonging to the user of the account. On a scale from 1 to 10, values above 5 are not recommended.
|
||||
'';
|
||||
};
|
||||
|
||||
dark-threshold = mkOption {
|
||||
type = types.int;
|
||||
default = 50;
|
||||
description = ''
|
||||
Because of flashing IR emitters, some frames can be completely unlit. Skip the frame if the lowest 1/8 of the histogram is above this percentage of the total. The lower this setting is, the more dark frames are ignored.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
environment.systemPackages = [ cfg.package pkgs.ir_toggle ];
|
||||
environment.etc."howdy/config.ini".source = configINI;
|
||||
security.pam.services = {
|
||||
sudo.text = pam-rule; # Sudo
|
||||
login.text = pam-rule; # User login
|
||||
polkit-1.text = pam-rule; # PolKit
|
||||
i3lock.text = pam-rule; # i3lock
|
||||
};
|
||||
powerManagement.resumeCommands =
|
||||
"${pkgs.ir_toggle}/bin/chicony-ir-toggle on";
|
||||
services.udev.packages = [ pkgs.ir_toggle ];
|
||||
};
|
||||
}
|
||||
45
utils/modules/howdy/config.nix
Normal file
45
utils/modules/howdy/config.nix
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
core = {
|
||||
detection_notice = false;
|
||||
timeout_notice = true;
|
||||
no_confirmation = false;
|
||||
suppress_unknown = false;
|
||||
abort_if_ssh = true;
|
||||
abort_if_lid_closed = true;
|
||||
disabled = false;
|
||||
use_cnn = false;
|
||||
workaround = "off";
|
||||
};
|
||||
|
||||
video = {
|
||||
certainty = 3.5;
|
||||
timeout = 4;
|
||||
device_path = "/dev/video2";
|
||||
warn_no_device = true;
|
||||
max_height = 320;
|
||||
frame_width = -1;
|
||||
frame_height = -1;
|
||||
dark_threshold = 60;
|
||||
recording_plugin = "opencv";
|
||||
device_format = "v4l2";
|
||||
force_mjpeg = false;
|
||||
exposure = -1;
|
||||
rotate = 0;
|
||||
};
|
||||
|
||||
snapshots = {
|
||||
save_failed = false;
|
||||
save_successful = false;
|
||||
};
|
||||
|
||||
rubberstamps = {
|
||||
enabled = false;
|
||||
stamp_rules = "nod 5s failsafe min_distance=12";
|
||||
};
|
||||
|
||||
debug = {
|
||||
end_report = false;
|
||||
verbose_stamps = false;
|
||||
gtk_stdout = false;
|
||||
};
|
||||
}
|
||||
123
utils/modules/howdy/default.nix
Normal file
123
utils/modules/howdy/default.nix
Normal file
@@ -0,0 +1,123 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
pam-rule = pkgs.lib.mkDefault (pkgs.lib.mkBefore
|
||||
''
|
||||
auth sufficient pam_unix.so try_first_pass nullok
|
||||
auth sufficient ${config.services.howdy.package}/lib/security/pam_howdy.so
|
||||
'');
|
||||
pam-sudo-rule = pkgs.lib.mkDefault (pkgs.lib.mkBefore
|
||||
''
|
||||
auth sufficient ${config.services.howdy.package}/lib/security/pam_howdy.so
|
||||
'');
|
||||
cfg = config.services.howdy;
|
||||
irCfg = config.services.linux-enable-ir-emitter;
|
||||
settingsType = pkgs.formats.ini { };
|
||||
in {
|
||||
options = {
|
||||
services.howdy = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable howdy and PAM module for face recognition.
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.howdy;
|
||||
defaultText = "pkgs.howdy";
|
||||
description = ''
|
||||
Howdy package to use.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
inherit (settingsType) type;
|
||||
default = import ./config.nix;
|
||||
description = mdDoc ''
|
||||
Howdy configuration file. Refer to
|
||||
<https://github.com/boltgolt/howdy/blob/beta/howdy/src/config.ini>
|
||||
for options.
|
||||
'';
|
||||
};
|
||||
};
|
||||
services.linux-enable-ir-emitter = {
|
||||
enable = mkEnableOption (mdDoc "") // {
|
||||
description = mdDoc ''
|
||||
Whether to enable IR emitter hardware. Designed to be used with the
|
||||
Howdy facial authentication. After enabling the service, configure
|
||||
the emitter with `sudo linux-enable-ir-emitter configure`.
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkPackageOptionMD pkgs "linux-enable-ir-emitter" {} // {
|
||||
description = mdDoc ''
|
||||
Package to use for the Linux Enable IR Emitter service.
|
||||
'';
|
||||
};
|
||||
|
||||
device = mkOption {
|
||||
type = types.str;
|
||||
default = "video2";
|
||||
description = mdDoc ''
|
||||
IR camera device to depend on. For example, for `/dev/video2`
|
||||
the value would be `video2`. Find this with the command
|
||||
{command}`realpath /dev/v4l/by-path/<generated-driver-name>`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# environment.systemPackages = [ cfg.package pkgs.ir_toggle ];
|
||||
# environment.etc."howdy/config.ini".source = configINI;
|
||||
# security.pam.services = {
|
||||
# sudo.text = pam-rule; # Sudo
|
||||
# login.text = pam-rule; # User login
|
||||
# polkit-1.text = pam-rule; # PolKit
|
||||
# i3lock.text = pam-rule; # i3lock
|
||||
# };
|
||||
# powerManagement.resumeCommands =
|
||||
# "${pkgs.ir_toggle}/bin/chicony-ir-toggle on";
|
||||
# services.udev.packages = [ pkgs.ir_toggle ];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
environment.systemPackages = [ cfg.package irCfg.package ];
|
||||
|
||||
security.pam.services = {
|
||||
sudo.text = pam-sudo-rule; # Sudo
|
||||
login.text = pam-rule; # User login
|
||||
polkit-1.text = pam-rule; # PolKit
|
||||
swaylock.text = pam-rule; # i3lock
|
||||
# gdm-password.text = pam-rule; # i3lock
|
||||
};
|
||||
|
||||
systemd.services.linux-enable-ir-emitter = rec {
|
||||
description = "Enable the infrared emitter";
|
||||
script = "${getExe irCfg.package} run";
|
||||
|
||||
wantedBy = [
|
||||
"multi-user.target"
|
||||
"suspend.target"
|
||||
"hybrid-sleep.target"
|
||||
"hibernate.target"
|
||||
"suspend-then-hibernate.target"
|
||||
];
|
||||
after = wantedBy ++ [ "dev-${irCfg.device}.device" ];
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /var/lib/linux-enable-ir-emitter 0755 root root - -"
|
||||
];
|
||||
environment.etc."linux-enable-ir-emitter".source = "/var/lib/linux-enable-ir-emitter";
|
||||
environment.etc."howdy/config.ini".source = settingsType.generate "howdy-config.ini" cfg.settings;
|
||||
};
|
||||
}
|
||||
22
utils/modules/i3.nix
Normal file
22
utils/modules/i3.nix
Normal file
@@ -0,0 +1,22 @@
|
||||
{ config, pkgs, callPackage, ... }:
|
||||
|
||||
{
|
||||
environment.pathsToLink = [ "/libexec" ]; # links /libexec from derivations to /run/current-system/sw
|
||||
services.xserver = {
|
||||
enable = true;
|
||||
|
||||
desktopManager = {
|
||||
xterm.enable = false;
|
||||
};
|
||||
|
||||
windowManager.i3 = {
|
||||
enable = true;
|
||||
extraPackages = with pkgs; [
|
||||
dmenu #application launcher most people use
|
||||
i3status # gives you the default i3 status bar
|
||||
i3lock #default i3 screen locker
|
||||
i3blocks #if you are planning on using i3blocks over i3status
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
21
utils/modules/influxdb.nix
Normal file
21
utils/modules/influxdb.nix
Normal file
@@ -0,0 +1,21 @@
|
||||
{ config, ... }: {
|
||||
services.influxdb = {
|
||||
enable = true;
|
||||
extraConfig = {
|
||||
http = {
|
||||
auth-enabled = true;
|
||||
log-enabled = false;
|
||||
https-enabled = true;
|
||||
https-certificate = "/var/lib/acme/influxdb.cloonar.com/fullchain.pem";
|
||||
https-private-key = "/var/lib/acme/influxdb.cloonar.com/key.pem";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 8086 ];
|
||||
|
||||
security.acme.certs."influxdb.cloonar.com" = {
|
||||
postRun = "systemctl restart influxdb.service";
|
||||
group = "influxdb";
|
||||
};
|
||||
}
|
||||
16
utils/modules/lego/lego.nix
Normal file
16
utils/modules/lego/lego.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{ config, ... }:
|
||||
|
||||
{
|
||||
sops.secrets.lego-credentials = {
|
||||
sopsFile = ./secrets.yaml;
|
||||
};
|
||||
|
||||
security.acme.acceptTerms = true;
|
||||
security.acme.defaults.email = "admin+acme@cloonar.com";
|
||||
security.acme.defaults = {
|
||||
dnsProvider = "hetzner";
|
||||
credentialsFile = config.sops.secrets.lego-credentials.path;
|
||||
# We don't need to wait for propagation since this is a local DNS server
|
||||
dnsPropagationCheck = true;
|
||||
};
|
||||
}
|
||||
84
utils/modules/lego/secrets.yaml
Normal file
84
utils/modules/lego/secrets.yaml
Normal file
@@ -0,0 +1,84 @@
|
||||
lego-credentials: ENC[AES256_GCM,data:cn7n1jOammEdvzYzBKJ086c1bHc77GN74uncg35ClaTBvb5w3F0lQazJqBJoIf365Q==,iv:FLrr7WwGgzjuENOEi/Sf8Ti6wcQLPnBkJ+/DxyCUM54=,tag:yQnDsDz+btx3MQu/4w2ixg==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
azure_kv: []
|
||||
hc_vault: []
|
||||
age:
|
||||
- recipient: age16veg3fmvpfm7a89a9fc8dvvsxmsthlm70nfxqspr6t8vnf9wkcwsvdq38d
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBocUx0b1VtSlF4SVpvMXpr
|
||||
NjZSSHdkaDVoeDRCTC9LRFI1bkJRQTMyUFdJCjJvN2NyY1JLMkVtUTF2eGN3Lzh5
|
||||
R3M4NUk2WUpFMTM4MHQxM2k0dkdxUWcKLS0tIFkrMUVSaHVCaEYydERacFBtQVVt
|
||||
dXFENTFldVFWN3RQWTBKZHVtc0tza1kKeKGChclZahfDACUJxPsTn+4XomqifXP4
|
||||
VH+BxqmwkhgryRDoRrVy+vQnyK95WaDo3S/UIR2zgUR+cezt1DzR2A==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age106n5n3rrrss45eqqzz8pq90la3kqdtnw63uw0sfa2mahk5xpe30sxs5x58
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnckpCQVZaOE9NT084d0Zk
|
||||
TUtXN3EvcFZoOCs1aFloK2RSTVFyT2RWUzBVCjdCQzNGaWpqejhNdUtnZTl6RHpY
|
||||
b2dvMjZIV2ZGYkwyNVpxaHRPUmt3bmsKLS0tIHJReVpvTzBqYS9PVThmRzZzZUtI
|
||||
WjZmMXIxOWFScGlNSFdwbXdQcXB3d1UKHAkThsJ2unza8Yz/l0umryT8li74LKre
|
||||
dQuP41RQOQBHisUUZhWeYkM+wJzayXr426IK19zAHPuNeutqcewYcA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1y6lvl5jkwc47p5ae9yz9j9kuwhy7rtttua5xhygrgmr7ehd49svsszyt42
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaSGhiSkFKbHpGcjljZ3Uw
|
||||
ZWZ5MS82Wk9YRnZlQVk2V2laMzRkK3dBdWg4CjJ5Wkd0bnNXbVpMYVUxSVR1Nnpn
|
||||
dkFnbTV4eTYwWmdzWU9PZlozNytBWk0KLS0tIGVTL1RFbzBBM25nbFVtOEVQMmVm
|
||||
bmQvemhIeU8wTGswTEN2ZjA2RjdaTW8KlorFf+agQuSwbN3Fkr5bUC2Ca6Sz8hHy
|
||||
Faq+uNlMWHCrvE1DBP34D41LxCLDaDMYIJyUG7A4MZE2WUrJZ9c0vQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1ezq2j34qngky22enhnslx6hzh4ekwk8dtmn6c9us0uqxqpn7hgpsspjz58
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnT2VQd2VKeTFsQ3BPbXNq
|
||||
cWRTREx0UE54RmNDSlBwK082azRZalQ0aUhVCk1HV0Y3RnFYbS83NXcvY3IwSGVG
|
||||
ZElxcm1ETlFvVkhjR3RVNnNJQmR2dzAKLS0tIGpoYytWL25nQkFSMm5hQ29yYUd3
|
||||
UEp1cndyMG9Ba0RnT3NRdHAzRzBjdDAKIHXX0rnPkEz6Smw3sH8RgDdS92yOoFxz
|
||||
6uFUrqbxAW1+6EpgSPCi4GioAZyFayHdeuXQ5J9vApCDhHdsd6jMzw==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1jyeppc8yl2twnv8fwcewutd5gjewnxl59lmhev6ygds9qel8zf8syt7zz4
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBRVEyK3M2aXdwV3RTMGJy
|
||||
NlBUaWFKemJDRHB3ck5xVG1BWW1CUjc1OEdZCnUzSktiUkRmcTNwOWZXTFhnUCtD
|
||||
bHFCZ1ZhKytGc1hoOVQ0SFFyUkpmOHMKLS0tIGNWV3Vrd2J2TTYrUUhaSW0yak5W
|
||||
UTRGd0FaZUk1RVFqS3NXWHZ6SFQ4MTAKsIWMYxczPfDg7G/H5Rcm7sD/2zPXWJfl
|
||||
c2PiNSeZAfuCqAU/a9/2rz0kk3LdAW7d+foBOPeMkWnKs2pFJxNMXw==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1azmxsw5llmp2nnsv3yc2l8paelmq9rfepxd8jvmswgsmax0qyyxqdnsc7t
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBTUTZKRGdzSHgybnB6ZExx
|
||||
UVRCNTROS3QyOFBYSFc5blFEQythTndRSHhrCjJxcTNqejUxQWxRZzhhZVhNcjlR
|
||||
MFY4LzdicGUwMm13R1k2ZUdDc0VrY2MKLS0tIFVyNGlJU3NyQnkzZEg4SEM1T1NZ
|
||||
RHNUd053UUJyMnprbi9DR0JnSEQ5YjQKeXRdvnQRtkLs6yqVKlul4wp4PXQTpktZ
|
||||
cUUWEaajUmXoEeHjFkfNqtsJkVG6ixnzs9tu/GeOCbTCZ9eFokUg2g==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1zkzpnfeakyvg3fqtyay32sushjx2hqe28y6hs6ss7plemzqjqa5s6s5yu3
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGNHJFa0ltM0JiQ1hOa0pQ
|
||||
K3FndzhxaTBwZWgzNWg4RXBQdDV0WlZNZ1g4CkVhUlA2d0JjanorSlpyYVBUaEli
|
||||
Mnl2VmJTNG9DcnZsSXZpUFZXTDZQRVUKLS0tIEtDZ2J3L0RtV1BybEJDZ0k2bGZV
|
||||
YWY5QjlZZ1J2OEw2U0luZHNWQVFmRjQKZ9A54c5AXSm2aNasBinaWPDIo/xDXFqZ
|
||||
7+ZTJ82QiWBXpaLIpmPim3e9JHVzZ8NKdN0Y7imsYdR2gXRsxyv1SQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age14uarclad0ty5supc8ep09793xrnwkv8a4h9j0fq8d8lc92n2dadqkf64vw
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1K1RSTVZOYmFxalFxc1g1
|
||||
OHpaUXNLOHF2WnQ1VUxLUENwclJoQXl2b20wCnJnOUs0cXlMTDRXdktJZ2x6bjNJ
|
||||
UWJjYkZwR2ZKNnpsaVN0bzBWODZNL3MKLS0tIEUraytIc1d6dVVqa0VaSWJpcWRn
|
||||
UWswVG5PaTdDZHlybGxpZ2tKb1liOWsKOuMm2+kofwGqC95KhfEecjwzjNCHPRRk
|
||||
/61zp39+U6PeqP0gTbcy959aSDhfucrZKhBKP2VsTgP0BLDfZR2K4Q==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2022-11-09T07:12:13Z"
|
||||
mac: ENC[AES256_GCM,data:gqsD5gTtE5ZqWzWKAAIscecvIsGSC9j4Cnbik6Yk7Jf7Z5/NIxbkInzDsLmlU3ObbLZAhGAlOAKIrUVy37rCcEZ+I04ICXK1dmUdsVud6E4SvTdDjh9qlXTbEkcDCY2YqXlTuQl6IZyveaPuF6fRe1FMh8JEpDv/foZTl8+AuQQ=,iv:+nV6YW9m1B0qo7xbB1lw9dgiQ877GQ6OxMqjk7lei10=,tag:NmeSwBWRKpqlwZxYYC7trg==,type:str]
|
||||
pgp: []
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.7.3
|
||||
59
utils/modules/mopidy.nix
Normal file
59
utils/modules/mopidy.nix
Normal file
@@ -0,0 +1,59 @@
|
||||
{ pkgs, lib, ... }:
|
||||
let
|
||||
mopidy-autoplay = pkgs.python3Packages.buildPythonApplication rec {
|
||||
pname = "Mopidy-Autoplay";
|
||||
version = "0.2.3";
|
||||
|
||||
src = pkgs.python3Packages.fetchPypi {
|
||||
inherit pname version;
|
||||
sha256 = "sha256-E2Q+Cn2LWSbfoT/gFzUfChwl67Mv17uKmX2woFz/3YM=";
|
||||
};
|
||||
|
||||
propagatedBuildInputs = [
|
||||
pkgs.mopidy
|
||||
] ++ (with pkgs.python3Packages; [
|
||||
configobj
|
||||
]);
|
||||
|
||||
# no tests implemented
|
||||
doCheck = false;
|
||||
|
||||
meta = with lib; {
|
||||
homepage = "https://codeberg.org/sph/mopidy-autoplay";
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
services.mopidy = {
|
||||
enable = true;
|
||||
extensionPackages = [ pkgs.mopidy-iris pkgs.mopidy-tunein mopidy-autoplay ];
|
||||
configuration = ''
|
||||
[audio]
|
||||
output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! filesink location=/run/snapserver/mopidy
|
||||
|
||||
[file]
|
||||
enabled = false
|
||||
|
||||
[autoplay]
|
||||
enabled = true
|
||||
'';
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."mopidy.cloonar.com" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
extraConfig = ''
|
||||
proxy_buffering off;
|
||||
'';
|
||||
locations."/".extraConfig = ''
|
||||
proxy_pass http://127.0.0.1:6680;
|
||||
proxy_set_header Host $host;
|
||||
proxy_redirect http:// https://;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
'';
|
||||
};
|
||||
}
|
||||
28
utils/modules/mosquitto.nix
Normal file
28
utils/modules/mosquitto.nix
Normal file
@@ -0,0 +1,28 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
services.mosquitto = {
|
||||
enable = true;
|
||||
|
||||
listeners = [
|
||||
{
|
||||
users."espresense" = {
|
||||
password = "insecure-password";
|
||||
acl = [ "readwrite #" ];
|
||||
};
|
||||
users."home-assistant" = {
|
||||
hashedPassword = "$7$101$7uaagoQWQ3ICJ/wg$5cWZs4ae4DjToe44bOzpDopPv1kRaaVD+zF6BE64yDJH2/MBqXfD6f2/o9M/65ArhV92DAK+txXRYsEcZLl45A==";
|
||||
acl = [ "readwrite #" ];
|
||||
};
|
||||
users."ps5-mqtt" = {
|
||||
password = "insecure-password";
|
||||
acl = [ "readwrite #" ];
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
networking.firewall = {
|
||||
allowedTCPPorts = [ 1883 ];
|
||||
};
|
||||
}
|
||||
78
utils/modules/mysql.nix
Normal file
78
utils/modules/mysql.nix
Normal file
@@ -0,0 +1,78 @@
|
||||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
mysqlCreateDatabase = pkgs.writeShellScriptBin "mysql-create-database" ''
|
||||
#!/usr/bin/env bash
|
||||
if [ $# -lt 2 ]
|
||||
then
|
||||
echo "Usage: $0 <database> <host>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ $EUID -eq 0 ]
|
||||
then
|
||||
echo "Must be root!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DB="$1"
|
||||
HOST="$2"
|
||||
PASSWORD="$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 64 | xargs)"
|
||||
|
||||
cat <<EOF | mysql --host localhost --user root
|
||||
create database $DB;
|
||||
grant usage on $DB.* to '$DB'@'$HOST' identified by '$PASSWORD';
|
||||
grant all privileges on $DB.* to '$DB'@'$HOST';
|
||||
EOF
|
||||
|
||||
echo
|
||||
echo "Password for user $DB is:"
|
||||
echo
|
||||
echo $PASSWORD
|
||||
echo
|
||||
'';
|
||||
mysqlDeleteDatabase = pkgs.writeShellScriptBin "mysql-delete-database" ''
|
||||
#!/usr/bin/env bash
|
||||
if [ $# -lt 1 ]
|
||||
then
|
||||
echo "Usage: $0 <database>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ $EUID -eq 0 ]
|
||||
then
|
||||
echo "Must be root!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DB="$1"
|
||||
PASSWORD="$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 64 | xargs)"
|
||||
|
||||
cat <<EOF | mysql --host localhost --user root
|
||||
drop database $DB;
|
||||
drop user '$DB';
|
||||
EOF
|
||||
|
||||
echo
|
||||
echo "Dropped database $DB!"
|
||||
echo
|
||||
'';
|
||||
in {
|
||||
environment.systemPackages = [
|
||||
mysqlCreateDatabase
|
||||
mysqlDeleteDatabase
|
||||
];
|
||||
|
||||
services.mysql = {
|
||||
enable = true;
|
||||
package = pkgs.mariadb;
|
||||
settings = {
|
||||
mysqld = {
|
||||
max_allowed_packet = "64M";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.mysqlBackup.enable = true;
|
||||
services.mysqlBackup.databases = [ "mysql" ];
|
||||
}
|
||||
13
utils/modules/mysql/default.nix
Normal file
13
utils/modules/mysql/default.nix
Normal file
@@ -0,0 +1,13 @@
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
mysql-scripts = pkgs.callPackage ./pkgs/mysql-scripts.nix {};
|
||||
in {
|
||||
environment.systemPackages = [
|
||||
mysql-scripts
|
||||
];
|
||||
|
||||
services.mysql = {
|
||||
enable = true;
|
||||
package = pkgs.mariadb;
|
||||
};
|
||||
}
|
||||
14
utils/modules/mysql/pkgs/mysql-scripts.nix
Normal file
14
utils/modules/mysql/pkgs/mysql-scripts.nix
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
stdenv,
|
||||
lib,
|
||||
bash,
|
||||
}:
|
||||
stdenv.mkDerivation {
|
||||
name = "mysql-scripts";
|
||||
src = ./scripts;
|
||||
buildInputs = [ bash ];
|
||||
#nativeBuildInputs = [lib.makeWrapper];
|
||||
installPhase = ''
|
||||
install -D --target $out/bin *
|
||||
'';
|
||||
}
|
||||
28
utils/modules/mysql/pkgs/scripts/create-database.sh
Normal file
28
utils/modules/mysql/pkgs/scripts/create-database.sh
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ $# -lt 1 ]
|
||||
then
|
||||
echo "Usage: $0 <database>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ $EUID -eq 0 ]
|
||||
then
|
||||
echo "Must be root!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DB="$1"
|
||||
PASSWORD="$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 64 | xargs)"
|
||||
|
||||
cat <<EOF | mysql --host localhost --user root
|
||||
create database $DB;
|
||||
grant usage on $DB.* to '$DB'@'%' identified by '$PASSWORD';
|
||||
grant all privileges on $DB.* to '$DB'@'%';
|
||||
EOF
|
||||
|
||||
echo
|
||||
echo "Password for user $DB is:"
|
||||
echo
|
||||
echo $PASSWORD
|
||||
echo
|
||||
25
utils/modules/mysql/pkgs/scripts/delete-database.sh
Normal file
25
utils/modules/mysql/pkgs/scripts/delete-database.sh
Normal file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ $# -lt 1 ]
|
||||
then
|
||||
echo "Usage: $0 <database>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ $EUID -eq 0 ]
|
||||
then
|
||||
echo "Must be root!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DB="$1"
|
||||
PASSWORD="$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 64 | xargs)"
|
||||
|
||||
cat <<EOF | mysql --host localhost --user root
|
||||
drop database $DB;
|
||||
drop user '$DB';
|
||||
EOF
|
||||
|
||||
echo
|
||||
echo "Dropped database $DB!"
|
||||
echo
|
||||
30
utils/modules/netdata.nix
Normal file
30
utils/modules/netdata.nix
Normal file
@@ -0,0 +1,30 @@
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
environment.systemPackages = with pkgs; [
|
||||
python39
|
||||
];
|
||||
|
||||
services.netdata.configDir."python.d.conf" = pkgs.writeText "python.d.conf" ''
|
||||
postfix: yes
|
||||
'';
|
||||
|
||||
services.netdata = {
|
||||
enable = true;
|
||||
|
||||
python.enable = true;
|
||||
|
||||
config = {
|
||||
global = {
|
||||
# uncomment to reduce memory to 32 MB
|
||||
"page cache size" = 32;
|
||||
|
||||
# update interval
|
||||
"update every" = 15;
|
||||
};
|
||||
ml = {
|
||||
# enable machine learning
|
||||
"enabled" = "yes";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
32
utils/modules/nginx.nix
Normal file
32
utils/modules/nginx.nix
Normal file
@@ -0,0 +1,32 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
environment.systemPackages = with pkgs; [
|
||||
imagemagick
|
||||
ghostscript
|
||||
];
|
||||
|
||||
systemd.services.nginx.serviceConfig.ProtectHome = "read-only";
|
||||
|
||||
systemd.services.nginx_setup = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
before = [ "nginx.service" ];
|
||||
script = ''
|
||||
mkdir -p /var/www
|
||||
chown nginx:nginx /var/www
|
||||
chmod 755 /var/www
|
||||
'';
|
||||
serviceConfig.Type = "oneshot";
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
|
||||
sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL";
|
||||
};
|
||||
}
|
||||
135
utils/modules/nginx/cloonar.dev.nix
Normal file
135
utils/modules/nginx/cloonar.dev.nix
Normal file
@@ -0,0 +1,135 @@
|
||||
{ pkgs, lib, config, ... }:
|
||||
let
|
||||
domain = "cloonar.dev";
|
||||
dataDir = "/var/www/${domain}";
|
||||
in {
|
||||
systemd.services."phpfpm-${domain}".serviceConfig.ProtectHome = lib.mkForce false;
|
||||
|
||||
services.phpfpm.pools."${domain}" = {
|
||||
user = domain;
|
||||
settings = {
|
||||
"listen.owner" = config.services.nginx.user;
|
||||
"pm" = "dynamic";
|
||||
"pm.max_children" = 32;
|
||||
"pm.max_requests" = 500;
|
||||
"pm.start_servers" = 2;
|
||||
"pm.min_spare_servers" = 2;
|
||||
"pm.max_spare_servers" = 5;
|
||||
"php_admin_value[error_log]" = "stderr";
|
||||
"php_admin_flag[log_errors]" = true;
|
||||
"catch_workers_output" = true;
|
||||
"access.log" = "/var/log/$pool.access.log";
|
||||
};
|
||||
phpPackage = pkgs.php81;
|
||||
phpEnv."PATH" = lib.makeBinPath [ pkgs.php81 ];
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."cloonar.dev" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
root = "${dataDir}";
|
||||
|
||||
locations."/favicon.ico".extraConfig = ''
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
'';
|
||||
|
||||
# TYPO3 - Rule for versioned static files, configured through:
|
||||
# - $GLOBALS['TYPO3_CONF_VARS']['BE']['versionNumberInFilename']
|
||||
# - $GLOBALS['TYPO3_CONF_VARS']['FE']['versionNumberInFilename']
|
||||
|
||||
extraConfig = ''
|
||||
if (!-e $request_filename) {
|
||||
rewrite ^/(.+)\.(\d+)\.(php|js|css|png|jpg|gif|gzip)$ /$1.$3 last;
|
||||
}
|
||||
'';
|
||||
|
||||
# TYPO3 - Block access to composer files
|
||||
locations."~* composer\.(?:json|lock)".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
|
||||
# TYPO3 - Block access to flexform files
|
||||
locations."~* flexform[^.]*\.xml".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
# TYPO3 - Block access to language files
|
||||
locations."~* locallang[^.]*\.(?:xml|xlf)$".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
# TYPO3 - Block access to static typoscript files
|
||||
locations."~* ext_conf_template\.txt|ext_typoscript_constants\.txt|ext_typoscript_setup\.txt".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
# TYPO3 - Block access to miscellaneous protected files
|
||||
locations."~* /.*\.(?:bak|co?nf|cfg|ya?ml|ts|typoscript|tsconfig|dist|fla|in[ci]|log|sh|sql|sqlite)$".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
# TYPO3 - Block access to recycler and temporary directories
|
||||
locations."~ _(?:recycler|temp)_/".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
# TYPO3 - Block access to configuration files stored in fileadmin
|
||||
locations."~ fileadmin/(?:templates)/.*\.(?:txt|ts|typoscript)$".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
|
||||
# TYPO3 - Block access to libraries, source and temporary compiled data
|
||||
locations."~ ^(?:vendor|typo3_src|typo3temp/var)".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
|
||||
# TYPO3 - Block access to protected extension directories
|
||||
locations."~ (?:typo3conf/ext|typo3/sysext|typo3/ext)/[^/]+/(?:Configuration|Resources/Private|Tests?|Documentation|docs?)/".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
locations."/".extraConfig = ''
|
||||
index index.php index.html;
|
||||
try_files $uri $uri/ /index.php$is_args$args;
|
||||
'';
|
||||
|
||||
# TYPO3 Backend URLs
|
||||
locations."/typo3".extraConfig = ''
|
||||
rewrite ^ /typo3/;
|
||||
'';
|
||||
|
||||
locations."/typo3/".extraConfig = ''
|
||||
try_files $uri /typo3/index.php$is_args$args;
|
||||
'';
|
||||
|
||||
locations."~ [^/]\.php(/|$)".extraConfig = ''
|
||||
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
|
||||
if (!-f $document_root$fastcgi_script_name) {
|
||||
return 404;
|
||||
}
|
||||
include ${pkgs.nginx}/conf/fastcgi_params;
|
||||
include ${pkgs.nginx}/conf/fastcgi.conf;
|
||||
fastcgi_buffer_size 32k;
|
||||
fastcgi_buffers 8 16k;
|
||||
fastcgi_connect_timeout 240s;
|
||||
fastcgi_read_timeout 240s;
|
||||
fastcgi_send_timeout 240s;
|
||||
fastcgi_pass unix:${config.services.phpfpm.pools."${domain}".socket};
|
||||
fastcgi_index index.php;
|
||||
'';
|
||||
};
|
||||
users.users."${domain}" = {
|
||||
isSystemUser = true;
|
||||
createHome = true;
|
||||
home = dataDir;
|
||||
homeMode= "770";
|
||||
#home = "/home/${domain}";
|
||||
group = "nginx";
|
||||
};
|
||||
users.groups.${domain} = {};
|
||||
}
|
||||
55
utils/modules/nginx/default.nix
Normal file
55
utils/modules/nginx/default.nix
Normal file
@@ -0,0 +1,55 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
|
||||
imports = [
|
||||
./cloonar.dev.nix
|
||||
];
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
imagemagick
|
||||
ghostscript
|
||||
];
|
||||
|
||||
systemd.services.nginx.serviceConfig.ProtectHome = "read-only";
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
|
||||
sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL";
|
||||
|
||||
commonHttpConfig = ''
|
||||
# Add HSTS header with preloading to HTTPS requests.
|
||||
# Adding this header to HTTP requests is discouraged
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=31536000; includeSubdomains; preload";
|
||||
}
|
||||
add_header Strict-Transport-Security $hsts_header;
|
||||
|
||||
# Enable CSP for your services.
|
||||
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
|
||||
|
||||
# Minimize information leaked to other domains
|
||||
add_header 'Referrer-Policy' 'origin-when-cross-origin';
|
||||
|
||||
# Disable embedding as a frame
|
||||
add_header X-Frame-Options DENY;
|
||||
|
||||
# Prevent injection of code in other mime types (XSS Attacks)
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
|
||||
# Enable XSS protection of the browser.
|
||||
# May be unnecessary when CSP is configured properly (see above)
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
|
||||
# This might create errors
|
||||
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
|
||||
'';
|
||||
};
|
||||
|
||||
}
|
||||
48
utils/modules/nginx/defaults.nix
Normal file
48
utils/modules/nginx/defaults.nix
Normal file
@@ -0,0 +1,48 @@
|
||||
{ config, ... }:
|
||||
|
||||
{
|
||||
|
||||
imports = [
|
||||
./cloonar.dev.nix
|
||||
];
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
|
||||
sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL";
|
||||
|
||||
commonHttpConfig = ''
|
||||
# Add HSTS header with preloading to HTTPS requests.
|
||||
# Adding this header to HTTP requests is discouraged
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=31536000; includeSubdomains; preload";
|
||||
}
|
||||
add_header Strict-Transport-Security $hsts_header;
|
||||
|
||||
# Enable CSP for your services.
|
||||
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
|
||||
|
||||
# Minimize information leaked to other domains
|
||||
add_header 'Referrer-Policy' 'origin-when-cross-origin';
|
||||
|
||||
# Disable embedding as a frame
|
||||
add_header X-Frame-Options DENY;
|
||||
|
||||
# Prevent injection of code in other mime types (XSS Attacks)
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
|
||||
# Enable XSS protection of the browser.
|
||||
# May be unnecessary when CSP is configured properly (see above)
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
|
||||
# This might create errors
|
||||
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
|
||||
'';
|
||||
};
|
||||
|
||||
}
|
||||
7
utils/modules/nur.nix
Normal file
7
utils/modules/nur.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
nixpkgs.config.packageOverrides = pkgs: {
|
||||
nur = import (builtins.fetchTarball "https://github.com/nix-community/NUR/archive/master.tar.gz") {
|
||||
inherit pkgs;
|
||||
};
|
||||
};
|
||||
}
|
||||
221
utils/modules/nvim/config/bufferline.lua
Normal file
221
utils/modules/nvim/config/bufferline.lua
Normal file
@@ -0,0 +1,221 @@
|
||||
local function is_ft(b, ft)
|
||||
return vim.bo[b].filetype == ft
|
||||
end
|
||||
|
||||
local function diagnostics_indicator(num, _, diagnostics, _)
|
||||
local result = {}
|
||||
local symbols = {
|
||||
error = Icons.diagnostics.Error,
|
||||
warning = Icons.diagnostics.Warning,
|
||||
info = Icons.diagnostics.Information,
|
||||
}
|
||||
for name, count in pairs(diagnostics) do
|
||||
if symbols[name] and count > 0 then
|
||||
table.insert(result, symbols[name] .. " " .. count)
|
||||
end
|
||||
end
|
||||
result = table.concat(result, " ")
|
||||
return #result > 0 and result or ""
|
||||
end
|
||||
|
||||
local function custom_filter(buf, buf_nums)
|
||||
local logs = vim.tbl_filter(function(b)
|
||||
return is_ft(b, "log")
|
||||
end, buf_nums)
|
||||
if vim.tbl_isempty(logs) then
|
||||
return true
|
||||
end
|
||||
local tab_num = vim.fn.tabpagenr()
|
||||
local last_tab = vim.fn.tabpagenr "$"
|
||||
local is_log = is_ft(buf, "log")
|
||||
if last_tab == 1 then
|
||||
return true
|
||||
end
|
||||
-- only show log buffers in secondary tabs
|
||||
return (tab_num == last_tab and is_log) or (tab_num ~= last_tab and not is_log)
|
||||
end
|
||||
|
||||
|
||||
local config = {
|
||||
active = true,
|
||||
on_config_done = nil,
|
||||
keymap = {
|
||||
normal_mode = {},
|
||||
},
|
||||
highlights = {
|
||||
background = {
|
||||
italic = true,
|
||||
},
|
||||
buffer_selected = {
|
||||
bold = true,
|
||||
},
|
||||
},
|
||||
options = {
|
||||
mode = "buffers", -- set to "tabs" to only show tabpages instead
|
||||
numbers = "none", -- can be "none" | "ordinal" | "buffer_id" | "both" | function
|
||||
close_command = function(bufnr) -- can be a string | function, see "Mouse actions"
|
||||
buf_kill("bd", bufnr, false)
|
||||
end,
|
||||
right_mouse_command = "vert sbuffer %d", -- can be a string | function, see "Mouse actions"
|
||||
left_mouse_command = "buffer %d", -- can be a string | function, see "Mouse actions"
|
||||
middle_mouse_command = nil, -- can be a string | function, see "Mouse actions"
|
||||
indicator = {
|
||||
icon = Icons.ui.BoldLineLeft, -- this should be omitted if indicator style is not 'icon'
|
||||
style = "icon", -- can also be 'underline'|'none',
|
||||
},
|
||||
buffer_close_icon = Icons.ui.Close,
|
||||
modified_icon = Icons.ui.Circle,
|
||||
close_icon = Icons.ui.BoldClose,
|
||||
left_trunc_marker = Icons.ui.ArrowCircleLeft,
|
||||
right_trunc_marker = Icons.ui.ArrowCircleRight,
|
||||
--- name_formatter can be used to change the buffer's label in the bufferline.
|
||||
--- Please note some names can/will break the
|
||||
--- bufferline so use this at your discretion knowing that it has
|
||||
--- some limitations that will *NOT* be fixed.
|
||||
name_formatter = function(buf) -- buf contains a "name", "path" and "bufnr"
|
||||
-- remove extension from markdown files for example
|
||||
if buf.name:match "%.md" then
|
||||
return vim.fn.fnamemodify(buf.name, ":t:r")
|
||||
end
|
||||
end,
|
||||
max_name_length = 18,
|
||||
max_prefix_length = 15, -- prefix used when a buffer is de-duplicated
|
||||
truncate_names = true, -- whether or not tab names should be truncated
|
||||
tab_size = 18,
|
||||
diagnostics = "nvim_lsp",
|
||||
diagnostics_update_in_insert = false,
|
||||
diagnostics_indicator = diagnostics_indicator,
|
||||
-- NOTE: this will be called a lot so don't do any heavy processing here
|
||||
custom_filter = custom_filter,
|
||||
offsets = {
|
||||
{
|
||||
filetype = "undotree",
|
||||
text = "Undotree",
|
||||
highlight = "PanelHeading",
|
||||
padding = 1,
|
||||
},
|
||||
{
|
||||
filetype = "NvimTree",
|
||||
text = "Explorer",
|
||||
highlight = "PanelHeading",
|
||||
padding = 1,
|
||||
},
|
||||
{
|
||||
filetype = "DiffviewFiles",
|
||||
text = "Diff View",
|
||||
highlight = "PanelHeading",
|
||||
padding = 1,
|
||||
},
|
||||
{
|
||||
filetype = "flutterToolsOutline",
|
||||
text = "Flutter Outline",
|
||||
highlight = "PanelHeading",
|
||||
},
|
||||
{
|
||||
filetype = "packer",
|
||||
text = "Packer",
|
||||
highlight = "PanelHeading",
|
||||
padding = 1,
|
||||
},
|
||||
},
|
||||
color_icons = true, -- whether or not to add the filetype icon highlights
|
||||
show_buffer_icons = true, -- disable filetype icons for buffers
|
||||
show_buffer_close_icons = true,
|
||||
show_close_icon = false,
|
||||
show_tab_indicators = true,
|
||||
persist_buffer_sort = true, -- whether or not custom sorted buffers should persist
|
||||
-- can also be a table containing 2 custom separators
|
||||
-- [focused and unfocused]. eg: { '|', '|' }
|
||||
separator_style = "thin",
|
||||
enforce_regular_tabs = false,
|
||||
always_show_bufferline = false,
|
||||
hover = {
|
||||
enabled = false, -- requires nvim 0.8+
|
||||
delay = 200,
|
||||
reveal = { "close" },
|
||||
},
|
||||
sort_by = "id",
|
||||
},
|
||||
}
|
||||
|
||||
--require('keymappings').load(config.keymap)
|
||||
|
||||
require("bufferline").setup({
|
||||
options = config.options,
|
||||
highlights = config.highlights,
|
||||
})
|
||||
|
||||
--stylua: ignore
|
||||
|
||||
-- Common kill function for bdelete and bwipeout
|
||||
-- credits: based on bbye and nvim-bufdel
|
||||
---@param kill_command? string defaults to "bd"
|
||||
---@param bufnr? number defaults to the current buffer
|
||||
---@param force? boolean defaults to false
|
||||
function buf_kill(kill_command, bufnr, force)
|
||||
kill_command = kill_command or "bd"
|
||||
|
||||
local bo = vim.bo
|
||||
local api = vim.api
|
||||
local fmt = string.format
|
||||
local fnamemodify = vim.fn.fnamemodify
|
||||
|
||||
if bufnr == 0 or bufnr == nil then
|
||||
bufnr = api.nvim_get_current_buf()
|
||||
end
|
||||
|
||||
local bufname = api.nvim_buf_get_name(bufnr)
|
||||
|
||||
if not force then
|
||||
local warning
|
||||
if bo[bufnr].modified then
|
||||
warning = fmt([[No write since last change for (%s)]], fnamemodify(bufname, ":t"))
|
||||
elseif api.nvim_buf_get_option(bufnr, "buftype") == "terminal" then
|
||||
warning = fmt([[Terminal %s will be killed]], bufname)
|
||||
end
|
||||
if warning then
|
||||
vim.ui.input({
|
||||
prompt = string.format([[%s. Close it anyway? [y]es or [n]o (default: no): ]], warning),
|
||||
}, function(choice)
|
||||
if choice:match "ye?s?" then force = true end
|
||||
end)
|
||||
if not force then return end
|
||||
end
|
||||
end
|
||||
|
||||
-- Get list of windows IDs with the buffer to close
|
||||
local windows = vim.tbl_filter(function(win)
|
||||
return api.nvim_win_get_buf(win) == bufnr
|
||||
end, api.nvim_list_wins())
|
||||
|
||||
if force then
|
||||
kill_command = kill_command .. "!"
|
||||
end
|
||||
|
||||
-- Get list of active buffers
|
||||
local buffers = vim.tbl_filter(function(buf)
|
||||
return api.nvim_buf_is_valid(buf) and bo[buf].buflisted
|
||||
end, api.nvim_list_bufs())
|
||||
|
||||
-- If there is only one buffer (which has to be the current one), vim will
|
||||
-- create a new buffer on :bd.
|
||||
-- For more than one buffer, pick the previous buffer (wrapping around if necessary)
|
||||
if #buffers > 1 and #windows > 0 then
|
||||
for i, v in ipairs(buffers) do
|
||||
if v == bufnr then
|
||||
local prev_buf_idx = i == 1 and (#buffers - 1) or (i - 1)
|
||||
local prev_buffer = buffers[prev_buf_idx]
|
||||
for _, win in ipairs(windows) do
|
||||
api.nvim_win_set_buf(win, prev_buffer)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if buffer still exists, to ensure the target buffer wasn't killed
|
||||
-- due to options like bufhidden=wipe.
|
||||
if api.nvim_buf_is_valid(bufnr) and bo[bufnr].buflisted then
|
||||
vim.cmd(string.format("%s %d", kill_command, bufnr))
|
||||
end
|
||||
end
|
||||
|
||||
155
utils/modules/nvim/config/icons.lua
Normal file
155
utils/modules/nvim/config/icons.lua
Normal file
@@ -0,0 +1,155 @@
|
||||
Icons = {
|
||||
kind = {
|
||||
Array = "",
|
||||
Boolean = "蘒",
|
||||
Class = "",
|
||||
Color = "",
|
||||
Constant = "",
|
||||
Constructor = "",
|
||||
Enum = "",
|
||||
EnumMember = "",
|
||||
Event = "",
|
||||
Field = "",
|
||||
File = "",
|
||||
Folder = "",
|
||||
Function = "",
|
||||
Interface = "",
|
||||
Key = "",
|
||||
Keyword = "",
|
||||
Method = "",
|
||||
Module = "",
|
||||
Namespace = "",
|
||||
Null = "ﳠ",
|
||||
Number = "",
|
||||
Object = "",
|
||||
Operator = "",
|
||||
Package = "",
|
||||
Property = "",
|
||||
Reference = "",
|
||||
Snippet = "",
|
||||
String = "",
|
||||
Struct = "",
|
||||
Text = "",
|
||||
TypeParameter = "",
|
||||
Unit = "",
|
||||
Value = "",
|
||||
Variable = "",
|
||||
},
|
||||
git = {
|
||||
LineAdded = "",
|
||||
LineModified = "",
|
||||
LineRemoved = "",
|
||||
FileDeleted = "",
|
||||
FileIgnored = "◌",
|
||||
FileRenamed = "➜",
|
||||
FileStaged = "S",
|
||||
FileUnmerged = "",
|
||||
FileUnstaged = "",
|
||||
FileUntracked = "U",
|
||||
Diff = "",
|
||||
Repo = "",
|
||||
Octoface = "",
|
||||
Branch = "",
|
||||
},
|
||||
ui = {
|
||||
ArrowCircleDown = "",
|
||||
ArrowCircleLeft = "",
|
||||
ArrowCircleRight = "",
|
||||
ArrowCircleUp = "",
|
||||
BoldArrowDown = "",
|
||||
BoldArrowLeft = "",
|
||||
BoldArrowRight = "",
|
||||
BoldArrowUp = "",
|
||||
BoldClose = "",
|
||||
BoldDividerLeft = "",
|
||||
BoldDividerRight = "",
|
||||
BoldLineLeft = "▎",
|
||||
BookMark = "",
|
||||
BoxChecked = "",
|
||||
Bug = "",
|
||||
Stacks = " ",
|
||||
Scopes = "",
|
||||
Watches = "",
|
||||
DebugConsole = " ",
|
||||
Calendar = "",
|
||||
Check = "",
|
||||
ChevronRight = ">",
|
||||
ChevronShortDown = "",
|
||||
ChevronShortLeft = "",
|
||||
ChevronShortRight = "",
|
||||
ChevronShortUp = "",
|
||||
Circle = "",
|
||||
Close = "",
|
||||
CloudDownload = "",
|
||||
Code = "",
|
||||
Comment = "",
|
||||
Dashboard = "",
|
||||
DividerLeft = "",
|
||||
DividerRight = "",
|
||||
DoubleChevronRight = "»",
|
||||
Ellipsis = "…",
|
||||
EmptyFolder = "",
|
||||
EmptyFolderOpen = "",
|
||||
File = "",
|
||||
FileSymlink = "",
|
||||
Files = "",
|
||||
FindFile = "",
|
||||
FindText = "",
|
||||
Fire = "",
|
||||
Folder = "",
|
||||
FolderOpen = "",
|
||||
FolderSymlink = "",
|
||||
Forward = "",
|
||||
Gear = "",
|
||||
History = "",
|
||||
Lightbulb = "",
|
||||
LineLeft = "▏",
|
||||
LineMiddle = "│",
|
||||
List = "",
|
||||
Lock = "",
|
||||
NewFile = "",
|
||||
Note = "",
|
||||
Package = "",
|
||||
Pencil = "",
|
||||
Plus = "",
|
||||
Project = "",
|
||||
Search = "",
|
||||
SignIn = "",
|
||||
SignOut = "",
|
||||
Tab = "",
|
||||
Table = "",
|
||||
Target = "",
|
||||
Telescope = "",
|
||||
Text = "",
|
||||
Tree = "",
|
||||
Triangle = "契",
|
||||
TriangleShortArrowDown = "",
|
||||
TriangleShortArrowLeft = "",
|
||||
TriangleShortArrowRight = "",
|
||||
TriangleShortArrowUp = "",
|
||||
},
|
||||
diagnostics = {
|
||||
BoldError = "",
|
||||
Error = "",
|
||||
BoldWarning = "",
|
||||
Warning = "",
|
||||
BoldInformation = "",
|
||||
Information = "",
|
||||
BoldQuestion = "",
|
||||
Question = "",
|
||||
BoldHint = "",
|
||||
Hint = "",
|
||||
Debug = "",
|
||||
Trace = "✎",
|
||||
},
|
||||
misc = {
|
||||
Robot = "ﮧ",
|
||||
Squirrel = "",
|
||||
Tag = "",
|
||||
Watch = "",
|
||||
Smiley = "ﲃ",
|
||||
Package = "",
|
||||
CircuitBoard = "",
|
||||
},
|
||||
}
|
||||
|
||||
58
utils/modules/nvim/config/init.lua
Normal file
58
utils/modules/nvim/config/init.lua
Normal file
@@ -0,0 +1,58 @@
|
||||
-- vim.opt.expandtab = true
|
||||
-- vim.opt.hidden = true
|
||||
-- vim.opt.incsearch = true
|
||||
-- vim.opt.mouse = "a"
|
||||
-- vim.opt.number = true
|
||||
-- vim.opt.shiftwidth = 2
|
||||
-- vim.opt.splitbelow = true
|
||||
-- vim.opt.splitright = true
|
||||
-- vim.opt.signcolumn = "yes:3"
|
||||
-- vim.opt.tabstop = 2
|
||||
-- vim.opt.timeoutlen = 0
|
||||
-- vim.wo.wrap = false
|
||||
-- vim.opt.exrc = true
|
||||
-- vim.cmd("syntax on")
|
||||
|
||||
vim.opt.backup = false -- creates a backup file
|
||||
vim.opt.clipboard = "unnamedplus" -- allows neovim to access the system clipboard
|
||||
vim.opt.cmdheight = 2 -- more space in the neovim command line for displaying messages
|
||||
vim.opt.colorcolumn = "99999" -- fixes indentline for now
|
||||
vim.opt.completeopt = { "menuone", "noselect" }
|
||||
vim.opt.conceallevel = 0 -- so that `` is visible in markdown files
|
||||
vim.opt.fileencoding = "utf-8" -- the encoding written to a file
|
||||
vim.opt.foldmethod = "manual" -- folding set to "expr" for treesitter based folding
|
||||
vim.opt.foldexpr = "" -- set to "nvim_treesitter#foldexpr()" for treesitter based folding
|
||||
vim.opt.guifont = "monospace:h17" -- the font used in graphical neovim applications
|
||||
vim.opt.hidden = true -- required to keep multiple buffers and open multiple buffers
|
||||
vim.opt.hlsearch = true -- highlight all matches on previous search pattern
|
||||
vim.opt.ignorecase = true -- ignore case in search patterns
|
||||
vim.opt.mouse = "a" -- allow the mouse to be used in neovim
|
||||
vim.opt.pumheight = 10 -- pop up menu height
|
||||
vim.opt.showmode = false -- we don't need to see things like -- INSERT -- anymore
|
||||
vim.opt.showtabline = 2 -- always show tabs
|
||||
vim.opt.smartcase = true -- smart case
|
||||
vim.opt.smartindent = true -- make indenting smarter again
|
||||
vim.opt.splitbelow = true -- force all horizontal splits to go below current window
|
||||
vim.opt.splitright = true -- force all vertical splits to go to the right of current window
|
||||
vim.opt.swapfile = false -- creates a swapfile
|
||||
vim.opt.termguicolors = true -- set term gui colors (most terminals support this)
|
||||
vim.opt.timeoutlen = 100 -- time to wait for a mapped sequence to complete (in milliseconds)
|
||||
vim.opt.title = true -- set the title of window to the value of the titlestring
|
||||
vim.opt.titlestring = "%<%F%=%l/%L - nvim" -- what the title of the window will be set to
|
||||
vim.opt.undodir = vim.fn.stdpath "cache" .. "/undo"
|
||||
vim.opt.undofile = true -- enable persistent undo
|
||||
vim.opt.updatetime = 300 -- faster completion
|
||||
vim.opt.writebackup = false -- if a file is being edited by another program (or was written to file while editing with another program) it is not allowed to be edited
|
||||
vim.opt.expandtab = true -- convert tabs to spaces
|
||||
vim.opt.shiftwidth = 2 -- the number of spaces inserted for each indentation
|
||||
vim.opt.tabstop = 2 -- insert 2 spaces for a tab
|
||||
vim.opt.cursorline = true -- highlight the current line
|
||||
vim.opt.number = true -- set numbered lines
|
||||
vim.opt.relativenumber = false -- set relative numbered lines
|
||||
vim.opt.numberwidth = 4 -- set number column width to 2 {default 4}
|
||||
vim.opt.signcolumn = "yes" -- always show the sign column otherwise it would shift the text each time
|
||||
vim.opt.wrap = false -- display lines as one long line
|
||||
vim.opt.spell = false
|
||||
vim.opt.spelllang = "en"
|
||||
vim.opt.scrolloff = 8 -- is one of my fav
|
||||
vim.opt.sidescrolloff = 8
|
||||
145
utils/modules/nvim/config/keymappings.lua
Normal file
145
utils/modules/nvim/config/keymappings.lua
Normal file
@@ -0,0 +1,145 @@
|
||||
local generic_opts_any = { noremap = true, silent = true }
|
||||
|
||||
local generic_opts = {
|
||||
insert_mode = generic_opts_any,
|
||||
normal_mode = generic_opts_any,
|
||||
visual_mode = generic_opts_any,
|
||||
visual_block_mode = generic_opts_any,
|
||||
command_mode = generic_opts_any,
|
||||
term_mode = { silent = true },
|
||||
}
|
||||
|
||||
local mode_adapters = {
|
||||
insert_mode = "i",
|
||||
normal_mode = "n",
|
||||
term_mode = "t",
|
||||
visual_mode = "v",
|
||||
visual_block_mode = "x",
|
||||
command_mode = "c",
|
||||
}
|
||||
|
||||
---@class Keys
|
||||
---@field insert_mode table
|
||||
---@field normal_mode table
|
||||
---@field terminal_mode table
|
||||
---@field visual_mode table
|
||||
---@field visual_block_mode table
|
||||
---@field command_mode table
|
||||
|
||||
local defaults = {
|
||||
insert_mode = {
|
||||
-- Move current line / block with Alt-j/k ala vscode.
|
||||
["<A-j>"] = "<Esc>:m .+1<CR>==gi",
|
||||
-- Move current line / block with Alt-j/k ala vscode.
|
||||
["<A-k>"] = "<Esc>:m .-2<CR>==gi",
|
||||
-- navigation
|
||||
["<A-Up>"] = "<C-\\><C-N><C-w>k",
|
||||
["<A-Down>"] = "<C-\\><C-N><C-w>j",
|
||||
["<A-Left>"] = "<C-\\><C-N><C-w>h",
|
||||
["<A-Right>"] = "<C-\\><C-N><C-w>l",
|
||||
},
|
||||
|
||||
normal_mode = {
|
||||
-- Better window movement
|
||||
["<C-h>"] = "<C-w>h",
|
||||
["<C-j>"] = "<C-w>j",
|
||||
["<C-k>"] = "<C-w>k",
|
||||
["<C-l>"] = "<C-w>l",
|
||||
|
||||
-- Resize with arrows
|
||||
["<C-Up>"] = ":resize -2<CR>",
|
||||
["<C-Down>"] = ":resize +2<CR>",
|
||||
["<C-Left>"] = ":vertical resize -2<CR>",
|
||||
["<C-Right>"] = ":vertical resize +2<CR>",
|
||||
|
||||
-- Move current line / block with Alt-j/k a la vscode.
|
||||
["<A-j>"] = ":m .+1<CR>==",
|
||||
["<A-k>"] = ":m .-2<CR>==",
|
||||
|
||||
-- QuickFix
|
||||
["]q"] = ":cnext<CR>",
|
||||
["[q"] = ":cprev<CR>",
|
||||
["<C-q>"] = ":call QuickFixToggle()<CR>",
|
||||
},
|
||||
|
||||
term_mode = {
|
||||
-- Terminal window navigation
|
||||
["<C-h>"] = "<C-\\><C-N><C-w>h",
|
||||
["<C-j>"] = "<C-\\><C-N><C-w>j",
|
||||
["<C-k>"] = "<C-\\><C-N><C-w>k",
|
||||
["<C-l>"] = "<C-\\><C-N><C-w>l",
|
||||
},
|
||||
|
||||
visual_mode = {
|
||||
-- Better indenting
|
||||
["<"] = "<gv",
|
||||
[">"] = ">gv",
|
||||
|
||||
-- ["p"] = '"0p',
|
||||
-- ["P"] = '"0P',
|
||||
},
|
||||
|
||||
visual_block_mode = {
|
||||
-- Move current line / block with Alt-j/k ala vscode.
|
||||
["<A-j>"] = ":m '>+1<CR>gv-gv",
|
||||
["<A-k>"] = ":m '<-2<CR>gv-gv",
|
||||
},
|
||||
|
||||
command_mode = {
|
||||
-- navigate tab completion with <c-j> and <c-k>
|
||||
-- runs conditionally
|
||||
["<C-j>"] = { 'pumvisible() ? "\\<C-n>" : "\\<C-j>"', { expr = true, noremap = true } },
|
||||
["<C-k>"] = { 'pumvisible() ? "\\<C-p>" : "\\<C-k>"', { expr = true, noremap = true } },
|
||||
},
|
||||
}
|
||||
|
||||
if vim.fn.has "mac" == 1 then
|
||||
defaults.normal_mode["<A-Up>"] = defaults.normal_mode["<C-Up>"]
|
||||
defaults.normal_mode["<A-Down>"] = defaults.normal_mode["<C-Down>"]
|
||||
defaults.normal_mode["<A-Left>"] = defaults.normal_mode["<C-Left>"]
|
||||
defaults.normal_mode["<A-Right>"] = defaults.normal_mode["<C-Right>"]
|
||||
Log:debug "Activated mac keymappings"
|
||||
end
|
||||
|
||||
function set_keymaps(mode, key, val)
|
||||
local opt = generic_opts[mode] or generic_opts_any
|
||||
if type(val) == "table" then
|
||||
opt = val[2]
|
||||
val = val[1]
|
||||
end
|
||||
if val then
|
||||
vim.keymap.set(mode, key, val, opt)
|
||||
else
|
||||
pcall(vim.api.nvim_del_keymap, mode, key)
|
||||
end
|
||||
end
|
||||
|
||||
function load_mode(mode, keymaps)
|
||||
mode = mode_adapters[mode] or mode
|
||||
for k, v in pairs(keymaps) do
|
||||
set_keymaps(mode, k, v)
|
||||
end
|
||||
end
|
||||
|
||||
function load(keymaps)
|
||||
keymaps = keymaps or {}
|
||||
for mode, mapping in pairs(keymaps) do
|
||||
load_mode(mode, mapping)
|
||||
end
|
||||
end
|
||||
|
||||
function load_defaults()
|
||||
load(get_defaults())
|
||||
keys = keys or {}
|
||||
for idx, _ in pairs(defaults) do
|
||||
if not keys[idx] then
|
||||
keys[idx] = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function get_defaults()
|
||||
return defaults
|
||||
end
|
||||
|
||||
load_defaults()
|
||||
50
utils/modules/nvim/config/lspconfig.lua
Normal file
50
utils/modules/nvim/config/lspconfig.lua
Normal file
@@ -0,0 +1,50 @@
|
||||
local status, lspc = pcall(require, 'lspconfig')
|
||||
if (not status) then return end
|
||||
|
||||
lspc.clangd.setup{}
|
||||
|
||||
local buf_map = function(bufnr, mode, lhs, rhs, opts)
|
||||
vim.api.nvim_buf_set_keymap(bufnr, mode, lhs, rhs, opts or {
|
||||
silent = true,
|
||||
})
|
||||
end
|
||||
|
||||
local protocol = require('vim.lsp.protocol')
|
||||
|
||||
local on_attach = function(client, buffnr)
|
||||
if client.server.capabilities.documentFormattingProvider then
|
||||
vimapi.nvim_create_autocmd("BufWritePre", {
|
||||
group = vim.api.nvim_create_augroup("format", { clear = true }),
|
||||
buffer = buffnr,
|
||||
callback = function() vim.lsp.buf.formatting_seq_sync() end
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
local capabilities = vim.lsp.protocol.make_client_capabilities()
|
||||
capabilities.textDocument.completion.completionItem.snippetSupport = true
|
||||
capabilities = require('cmp_nvim_lsp').default_capabilities(capabilities)
|
||||
|
||||
local servers = { 'tsserver', 'sumneko_lua', 'cssls', 'yamlls', 'intelephense' }
|
||||
for _, lsp in pairs(servers) do
|
||||
require('lspconfig')[lsp].setup {
|
||||
-- on_attach = on_attach,
|
||||
capabilities = capabilities,
|
||||
}
|
||||
end
|
||||
|
||||
lspc.sumneko_lua.setup({
|
||||
settings = {
|
||||
Lua = {
|
||||
diagnostics = {
|
||||
globals = { 'vim' }
|
||||
},
|
||||
workspace = {
|
||||
library = vim.api.nvim_get_runtime_file("", true),
|
||||
checkThirdParty = false
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
-- lspc.intelephense.setup()
|
||||
73
utils/modules/nvim/config/nvim-cmp.lua
Normal file
73
utils/modules/nvim/config/nvim-cmp.lua
Normal file
@@ -0,0 +1,73 @@
|
||||
local has_words_before = function()
|
||||
local line, col = unpack(vim.api.nvim_win_get_cursor(0))
|
||||
return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil
|
||||
end
|
||||
|
||||
local feedkey = function(key, mode)
|
||||
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(key, true, true, true), mode, true)
|
||||
end
|
||||
|
||||
local cmp = require("cmp")
|
||||
local lspkind = require("lspkind")
|
||||
|
||||
cmp.setup({
|
||||
sources = {
|
||||
{ name = "nvim_lsp" },
|
||||
{ name = "cmp_tabnine" },
|
||||
{ name = "treesitter" },
|
||||
{ name = "buffer" },
|
||||
{ name = "path" },
|
||||
{ name = "vsnip" },
|
||||
-- { name = "copilot" },
|
||||
},
|
||||
|
||||
snippet = {
|
||||
expand = function(args)
|
||||
vim.fn["vsnip#anonymous"](args.body)
|
||||
end,
|
||||
},
|
||||
|
||||
formatting = {
|
||||
format = lspkind.cmp_format({
|
||||
with_text = true,
|
||||
menu = {
|
||||
buffer = "[Buf]",
|
||||
nvim_lsp = "[LSP]",
|
||||
nvim_lua = "[Lua]",
|
||||
latex_symbols = "[Latex]",
|
||||
treesitter = "[TS]",
|
||||
cmp_tabnine = "[TN]",
|
||||
vsnip = "[Snip]",
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
mapping = {
|
||||
["<CR>"] = cmp.mapping.confirm({ select = true }),
|
||||
["<Tab>"] = cmp.mapping(function(fallback)
|
||||
if cmp.visible() then
|
||||
cmp.select_next_item()
|
||||
elseif vim.fn["vsnip#available"](1) == 1 then
|
||||
feedkey("<Plug>(vsnip-expand-or-jump)", "")
|
||||
elseif has_words_before() then
|
||||
cmp.complete()
|
||||
else
|
||||
fallback()
|
||||
end
|
||||
end, {
|
||||
"i",
|
||||
"s",
|
||||
}),
|
||||
|
||||
["<S-Tab>"] = cmp.mapping(function()
|
||||
if cmp.visible() then
|
||||
cmp.select_prev_item()
|
||||
elseif vim.fn["vsnip#jumpable"](-1) == 1 then
|
||||
feedkey("<Plug>(vsnip-jump-prev)", "")
|
||||
end
|
||||
end, {
|
||||
"i",
|
||||
"s",
|
||||
}),
|
||||
},
|
||||
})
|
||||
41
utils/modules/nvim/config/project.lua
Normal file
41
utils/modules/nvim/config/project.lua
Normal file
@@ -0,0 +1,41 @@
|
||||
config = {
|
||||
---@usage set to false to disable project.nvim.
|
||||
--- This is on by default since it's currently the expected behavior.
|
||||
active = true,
|
||||
|
||||
on_config_done = nil,
|
||||
|
||||
---@usage set to true to disable setting the current-woriking directory
|
||||
--- Manual mode doesn't automatically change your root directory, so you have
|
||||
--- the option to manually do so using `:ProjectRoot` command.
|
||||
manual_mode = false,
|
||||
|
||||
---@usage Methods of detecting the root directory
|
||||
--- Allowed values: **"lsp"** uses the native neovim lsp
|
||||
--- **"pattern"** uses vim-rooter like glob pattern matching. Here
|
||||
--- order matters: if one is not detected, the other is used as fallback. You
|
||||
--- can also delete or rearangne the detection methods.
|
||||
-- detection_methods = { "lsp", "pattern" }, -- NOTE: lsp detection will get annoying with multiple langs in one project
|
||||
detection_methods = { "pattern" },
|
||||
|
||||
---@usage patterns used to detect root dir, when **"pattern"** is in detection_methods
|
||||
patterns = { ".git", "_darcs", ".hg", ".bzr", ".svn", "Makefile", "package.json", "pom.xml" },
|
||||
|
||||
---@ Show hidden files in telescope when searching for files in a project
|
||||
show_hidden = false,
|
||||
|
||||
---@usage When set to false, you will get a message when project.nvim changes your directory.
|
||||
-- When set to false, you will get a message when project.nvim changes your directory.
|
||||
silent_chdir = true,
|
||||
|
||||
---@usage list of lsp client names to ignore when using **lsp** detection. eg: { "efm", ... }
|
||||
ignore_lsp = {},
|
||||
}
|
||||
|
||||
local status_ok, project = pcall(require, "project_nvim")
|
||||
if not status_ok then
|
||||
return
|
||||
end
|
||||
|
||||
project.setup(config)
|
||||
|
||||
148
utils/modules/nvim/config/telescope.lua
Normal file
148
utils/modules/nvim/config/telescope.lua
Normal file
@@ -0,0 +1,148 @@
|
||||
local function get_pickers(actions)
|
||||
return {
|
||||
find_files = {
|
||||
theme = "dropdown",
|
||||
hidden = true,
|
||||
previewer = false,
|
||||
},
|
||||
live_grep = {
|
||||
--@usage don't include the filename in the search results
|
||||
only_sort_text = true,
|
||||
theme = "dropdown",
|
||||
},
|
||||
grep_string = {
|
||||
only_sort_text = true,
|
||||
theme = "dropdown",
|
||||
},
|
||||
buffers = {
|
||||
theme = "dropdown",
|
||||
previewer = false,
|
||||
initial_mode = "normal",
|
||||
mappings = {
|
||||
i = {
|
||||
["<C-d>"] = actions.delete_buffer,
|
||||
},
|
||||
n = {
|
||||
["dd"] = actions.delete_buffer,
|
||||
},
|
||||
},
|
||||
},
|
||||
planets = {
|
||||
show_pluto = true,
|
||||
show_moon = true,
|
||||
},
|
||||
git_files = {
|
||||
theme = "dropdown",
|
||||
hidden = true,
|
||||
previewer = false,
|
||||
show_untracked = true,
|
||||
},
|
||||
lsp_references = {
|
||||
theme = "dropdown",
|
||||
initial_mode = "normal",
|
||||
},
|
||||
lsp_definitions = {
|
||||
theme = "dropdown",
|
||||
initial_mode = "normal",
|
||||
},
|
||||
lsp_declarations = {
|
||||
theme = "dropdown",
|
||||
initial_mode = "normal",
|
||||
},
|
||||
lsp_implementations = {
|
||||
theme = "dropdown",
|
||||
initial_mode = "normal",
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
local ok, actions = pcall(require, "telescope.actions")
|
||||
if not ok then
|
||||
return
|
||||
end
|
||||
|
||||
local config = {
|
||||
prompt_prefix = " ",
|
||||
selection_caret = " ",
|
||||
entry_prefix = " ",
|
||||
initial_mode = "insert",
|
||||
selection_strategy = "reset",
|
||||
sorting_strategy = "descending",
|
||||
layout_strategy = "horizontal",
|
||||
layout_config = {
|
||||
width = 0.75,
|
||||
preview_cutoff = 120,
|
||||
horizontal = {
|
||||
preview_width = function(_, cols, _)
|
||||
if cols < 120 then
|
||||
return math.floor(cols * 0.8)
|
||||
end
|
||||
return math.floor(cols * 0.8)
|
||||
end,
|
||||
mirror = false,
|
||||
},
|
||||
vertical = { mirror = false },
|
||||
},
|
||||
vimgrep_arguments = {
|
||||
"rg",
|
||||
"--color=never",
|
||||
"--no-heading",
|
||||
"--with-filename",
|
||||
"--line-number",
|
||||
"--column",
|
||||
"--smart-case",
|
||||
"--hidden",
|
||||
"--glob=!.git/",
|
||||
},
|
||||
---@usage Mappings are fully customizable. Many familiar mapping patterns are setup as defaults.
|
||||
mappings = {
|
||||
i = {
|
||||
["<C-n>"] = actions.move_selection_next,
|
||||
["<C-p>"] = actions.move_selection_previous,
|
||||
["<C-c>"] = actions.close,
|
||||
["<C-j>"] = actions.cycle_history_next,
|
||||
["<C-k>"] = actions.cycle_history_prev,
|
||||
["<C-q>"] = actions.smart_send_to_qflist + actions.open_qflist,
|
||||
["<CR>"] = actions.select_default,
|
||||
},
|
||||
n = {
|
||||
["<C-n>"] = actions.move_selection_next,
|
||||
["<C-p>"] = actions.move_selection_previous,
|
||||
["<C-q>"] = actions.smart_send_to_qflist + actions.open_qflist,
|
||||
},
|
||||
},
|
||||
pickers = get_pickers(actions),
|
||||
file_ignore_patterns = {},
|
||||
path_display = { "smart" },
|
||||
winblend = 0,
|
||||
border = {},
|
||||
borderchars = { "─", "│", "─", "│", "╭", "╮", "╯", "╰" },
|
||||
color_devicons = true,
|
||||
set_env = { ["COLORTERM"] = "truecolor" }, -- default = nil,
|
||||
extensions = {
|
||||
fzf = {
|
||||
fuzzy = true, -- false will only do exact matching
|
||||
override_generic_sorter = true, -- override the generic sorter
|
||||
override_file_sorter = true, -- override the file sorter
|
||||
case_mode = "smart_case", -- or "ignore_case" or "respect_case"
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
local previewers = require "telescope.previewers"
|
||||
local sorters = require "telescope.sorters"
|
||||
|
||||
config = vim.tbl_extend("keep", {
|
||||
file_previewer = previewers.vim_buffer_cat.new,
|
||||
grep_previewer = previewers.vim_buffer_vimgrep.new,
|
||||
qflist_previewer = previewers.vim_buffer_qflist.new,
|
||||
file_sorter = sorters.get_fuzzy_file,
|
||||
generic_sorter = sorters.get_generic_fuzzy_sorter,
|
||||
}, config)
|
||||
|
||||
local telescope = require "telescope"
|
||||
telescope.setup(config)
|
||||
|
||||
require("telescope").load_extension "projects"
|
||||
require("telescope").load_extension "fzf"
|
||||
133
utils/modules/nvim/config/terminal.lua
Normal file
133
utils/modules/nvim/config/terminal.lua
Normal file
@@ -0,0 +1,133 @@
|
||||
local config = {
|
||||
active = true,
|
||||
on_config_done = nil,
|
||||
-- size can be a number or function which is passed the current terminal
|
||||
size = 20,
|
||||
open_mapping = [[<c-t>]],
|
||||
hide_numbers = true, -- hide the number column in toggleterm buffers
|
||||
shade_filetypes = {},
|
||||
shade_terminals = true,
|
||||
shading_factor = 2, -- the degree by which to darken to terminal colour, default: 1 for dark backgrounds, 3 for light
|
||||
start_in_insert = true,
|
||||
insert_mappings = true, -- whether or not the open mapping applies in insert mode
|
||||
persist_size = false,
|
||||
-- direction = 'vertical' | 'horizontal' | 'window' | 'float',
|
||||
direction = "float",
|
||||
close_on_exit = true, -- close the terminal window when the process exits
|
||||
shell = vim.o.shell, -- change the default shell
|
||||
-- This field is only relevant if direction is set to 'float'
|
||||
float_opts = {
|
||||
-- The border key is *almost* the same as 'nvim_win_open'
|
||||
-- see :h nvim_win_open for details on borders however
|
||||
-- the 'curved' border is a custom border type
|
||||
-- not natively supported but implemented in this plugin.
|
||||
-- border = 'single' | 'double' | 'shadow' | 'curved' | ... other options supported by win open
|
||||
border = "curved",
|
||||
-- width = <value>,
|
||||
-- height = <value>,
|
||||
winblend = 0,
|
||||
highlights = {
|
||||
border = "Normal",
|
||||
background = "Normal",
|
||||
},
|
||||
},
|
||||
-- Add executables on the config.lua
|
||||
-- { exec, keymap, name}
|
||||
-- lvim.builtin.terminal.execs = {{}} to overwrite
|
||||
-- lvim.builtin.terminal.execs[#lvim.builtin.terminal.execs+1] = {"gdb", "tg", "GNU Debugger"}
|
||||
-- TODO: pls add mappings in which key and refactor this
|
||||
execs = {
|
||||
{ vim.o.shell, "<M-1>", "Horizontal Terminal", "horizontal", 0.3 },
|
||||
{ vim.o.shell, "<M-2>", "Vertical Terminal", "vertical", 0.4 },
|
||||
{ vim.o.shell, "<M-3>", "Float Terminal", "float", nil },
|
||||
},
|
||||
}
|
||||
|
||||
--- Get current buffer size
|
||||
---@return {width: number, height: number}
|
||||
local function get_buf_size()
|
||||
local cbuf = vim.api.nvim_get_current_buf()
|
||||
local bufinfo = vim.tbl_filter(function(buf)
|
||||
return buf.bufnr == cbuf
|
||||
end, vim.fn.getwininfo(vim.api.nvim_get_current_win()))[1]
|
||||
if bufinfo == nil then
|
||||
return { width = -1, height = -1 }
|
||||
end
|
||||
return { width = bufinfo.width, height = bufinfo.height }
|
||||
end
|
||||
|
||||
--- Get the dynamic terminal size in cells
|
||||
---@param direction number
|
||||
---@param size integer
|
||||
---@return integer
|
||||
local function get_dynamic_terminal_size(direction, size)
|
||||
size = size or config.size
|
||||
if direction ~= "float" and tostring(size):find(".", 1, true) then
|
||||
size = math.min(size, 1.0)
|
||||
local buf_sizes = get_buf_size()
|
||||
local buf_size = direction == "horizontal" and buf_sizes.height or buf_sizes.width
|
||||
return buf_size * size
|
||||
else
|
||||
return size
|
||||
end
|
||||
end
|
||||
|
||||
Add_exec = function(opts)
|
||||
local binary = opts.cmd:match "(%S+)"
|
||||
if vim.fn.executable(binary) ~= 1 then
|
||||
Log:debug("Skipping configuring executable " .. binary .. ". Please make sure it is installed properly.")
|
||||
return
|
||||
end
|
||||
|
||||
vim.keymap.set({ "n", "t" }, opts.keymap, function()
|
||||
M._exec_toggle { cmd = opts.cmd, count = opts.count, direction = opts.direction, size = opts.size() }
|
||||
end, { desc = opts.label, noremap = true, silent = true })
|
||||
end
|
||||
|
||||
local terminal = require "toggleterm"
|
||||
terminal.setup(config)
|
||||
|
||||
for i, exec in pairs(config.execs) do
|
||||
local direction = exec[4] or config.direction
|
||||
|
||||
local opts = {
|
||||
cmd = exec[1],
|
||||
keymap = exec[2],
|
||||
label = exec[3],
|
||||
-- NOTE: unable to consistently bind id/count <= 9, see #2146
|
||||
count = i + 100,
|
||||
direction = direction,
|
||||
size = function()
|
||||
return get_dynamic_terminal_size(direction, exec[5])
|
||||
end,
|
||||
}
|
||||
|
||||
Add_exec(opts)
|
||||
end
|
||||
|
||||
_exec_toggle = function(opts)
|
||||
local Terminal = require("toggleterm.terminal").Terminal
|
||||
local term = Terminal:new { cmd = opts.cmd, count = opts.count, direction = opts.direction }
|
||||
term:toggle(opts.size, opts.direction)
|
||||
end
|
||||
|
||||
Lazygit_toggle = function()
|
||||
local Terminal = require("toggleterm.terminal").Terminal
|
||||
local lazygit = Terminal:new {
|
||||
cmd = "lazygit",
|
||||
hidden = true,
|
||||
direction = "float",
|
||||
float_opts = {
|
||||
border = "none",
|
||||
width = 100000,
|
||||
height = 100000,
|
||||
},
|
||||
on_open = function(_)
|
||||
vim.cmd "startinsert!"
|
||||
end,
|
||||
on_close = function(_) end,
|
||||
count = 99,
|
||||
}
|
||||
lazygit:toggle()
|
||||
end
|
||||
|
||||
18
utils/modules/nvim/config/theming.lua
Normal file
18
utils/modules/nvim/config/theming.lua
Normal file
@@ -0,0 +1,18 @@
|
||||
-- set colorscheme
|
||||
vim.cmd 'set termguicolors'
|
||||
|
||||
require("catppuccin").setup()
|
||||
|
||||
vim.cmd [[colorscheme dracula]]
|
||||
|
||||
-- enable colorizer
|
||||
require'colorizer'.setup()
|
||||
|
||||
-- set sign
|
||||
vim.cmd 'sign define DiagnosticSignError text= linehl= texthl=DiagnosticSignError numhl='
|
||||
vim.cmd 'sign define DiagnosticSignHint text= linehl= texthl=DiagnosticSignHint numhl='
|
||||
vim.cmd 'sign define DiagnosticSignInfo text= linehl= texthl=DiagnosticSignInfo numhl='
|
||||
vim.cmd 'sign define DiagnosticSignWarn text= linehl= texthl=DiagnosticSignWarn numhl='
|
||||
|
||||
-- set lightline theme to horizon
|
||||
vim.g.lightline = { colorscheme = "dracula" }
|
||||
14
utils/modules/nvim/config/treesitter-textobjects.lua
Normal file
14
utils/modules/nvim/config/treesitter-textobjects.lua
Normal file
@@ -0,0 +1,14 @@
|
||||
require'nvim-treesitter.configs'.setup {
|
||||
textobjects = {
|
||||
select = {
|
||||
enable = true,
|
||||
keymaps = {
|
||||
-- You can use the capture groups defined in textobjects.scm
|
||||
["af"] = "@function.outer",
|
||||
["if"] = "@function.inner",
|
||||
["ac"] = "@class.outer",
|
||||
["ic"] = "@class.inner",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
30
utils/modules/nvim/config/treesitter.lua
Normal file
30
utils/modules/nvim/config/treesitter.lua
Normal file
@@ -0,0 +1,30 @@
|
||||
require("nvim-treesitter.configs").setup({
|
||||
highlight = {
|
||||
enable = true,
|
||||
disable = {},
|
||||
},
|
||||
rainbow = {
|
||||
enable = true,
|
||||
extended_mode = true,
|
||||
},
|
||||
autotag = {
|
||||
enable = true,
|
||||
},
|
||||
context_commentstring = {
|
||||
enable = true,
|
||||
},
|
||||
incremental_selection = {
|
||||
enable = true,
|
||||
keymaps = {
|
||||
init_selection = "gnn",
|
||||
node_incremental = "grn",
|
||||
scope_incremental = "grc",
|
||||
node_decremental = "grm",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
-- breaks highlight
|
||||
-- vim.cmd([[set foldmethod=expr]])
|
||||
-- vim.cmd([[set foldlevel=10]])
|
||||
-- vim.cmd([[set foldexpr=nvim_treesitter#foldexpr()]])
|
||||
26
utils/modules/nvim/config/utils.lua
Normal file
26
utils/modules/nvim/config/utils.lua
Normal file
@@ -0,0 +1,26 @@
|
||||
-- null-ls
|
||||
local nb = require('null-ls').builtins
|
||||
|
||||
require('null-ls').setup({
|
||||
sources = {
|
||||
nb.formatting.alejandra,
|
||||
nb.code_actions.statix,
|
||||
nb.diagnostics.cppcheck,
|
||||
nb.diagnostics.deadnix,
|
||||
nb.diagnostics.statix,
|
||||
nb.diagnostics.eslint,
|
||||
nb.completion.spell,
|
||||
},
|
||||
})
|
||||
|
||||
require("gitsigns").setup()
|
||||
|
||||
-- autopairs
|
||||
require('nvim-autopairs').setup{}
|
||||
|
||||
-- copy to system clipboard
|
||||
vim.api.nvim_set_keymap( 'v', '<Leader>y', '"+y', {noremap = true})
|
||||
vim.api.nvim_set_keymap( 'n', '<Leader>y', ':%+y<CR>', {noremap = true})
|
||||
|
||||
-- paste from system clipboard
|
||||
vim.api.nvim_set_keymap( 'n', '<Leader>p', '"+p', {noremap = true})
|
||||
147
utils/modules/nvim/config/which-key.lua
Normal file
147
utils/modules/nvim/config/which-key.lua
Normal file
@@ -0,0 +1,147 @@
|
||||
vim.g.mapleader = " "
|
||||
|
||||
local function smart_quit()
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local modified = vim.api.nvim_buf_get_option(bufnr, "modified")
|
||||
if modified then
|
||||
vim.ui.input({
|
||||
prompt = "You have unsaved changes. Quit anyway? (y/n) ",
|
||||
}, function(input)
|
||||
if input == "y" then
|
||||
vim.cmd "q!"
|
||||
end
|
||||
end)
|
||||
else
|
||||
vim.cmd "q!"
|
||||
end
|
||||
end
|
||||
|
||||
local function find_project_files()
|
||||
local _, builtin = pcall(require, "telescope.builtin")
|
||||
local ok = pcall(builtin.git_files)
|
||||
|
||||
if not ok then
|
||||
builtin.find_files()
|
||||
end
|
||||
end
|
||||
|
||||
local wk = require("which-key")
|
||||
|
||||
wk.setup({})
|
||||
|
||||
wk.register({
|
||||
["<leader>"] = {
|
||||
|
||||
[";"] = { "<cmd>Alpha<CR>", "Dashboard" },
|
||||
["w"] = { "<cmd>w!<CR>", "Save" },
|
||||
["q"] = { "<cmd>smart_quit()<CR>", "Quit" },
|
||||
["/"] = { "<Plug>(comment_toggle_linewise_current)", "Comment toggle current line" },
|
||||
["c"] = { "<cmd>BufferKill<CR>", "Close Buffer" },
|
||||
["f"] = { find_project_files, "Find File" },
|
||||
["h"] = { "<cmd>nohlsearch<CR>", "No Highlight" },
|
||||
b = {
|
||||
name = "Buffers",
|
||||
j = { "<cmd>BufferLinePick<cr>", "Jump" },
|
||||
f = { "<cmd>Telescope buffers<cr>", "Find" },
|
||||
b = { "<cmd>BufferLineCyclePrev<cr>", "Previous" },
|
||||
n = { "<cmd>BufferLineCycleNext<cr>", "Next" },
|
||||
-- w = { "<cmd>BufferWipeout<cr>", "Wipeout" }, -- TODO: implement this for bufferline
|
||||
e = {
|
||||
"<cmd>BufferLinePickClose<cr>",
|
||||
"Pick which buffer to close",
|
||||
},
|
||||
h = { "<cmd>BufferLineCloseLeft<cr>", "Close all to the left" },
|
||||
l = {
|
||||
"<cmd>BufferLineCloseRight<cr>",
|
||||
"Close all to the right",
|
||||
},
|
||||
D = {
|
||||
"<cmd>BufferLineSortByDirectory<cr>",
|
||||
"Sort by directory",
|
||||
},
|
||||
L = {
|
||||
"<cmd>BufferLineSortByExtension<cr>",
|
||||
"Sort by language",
|
||||
},
|
||||
},
|
||||
-- " Available Debug Adapters:
|
||||
-- " https://microsoft.github.io/debug-adapter-protocol/implementors/adapters/
|
||||
-- " Adapter configuration and installation instructions:
|
||||
-- " https://github.com/mfussenegger/nvim-dap/wiki/Debug-Adapter-installation
|
||||
-- " Debug Adapter protocol:
|
||||
-- " https://microsoft.github.io/debug-adapter-protocol/
|
||||
-- " Debugging
|
||||
g = {
|
||||
name = "Git",
|
||||
g = { Lazygit_toggle, "Lazygit" },
|
||||
j = { "<cmd>lua require 'gitsigns'.next_hunk({navigation_message = false})<cr>", "Next Hunk" },
|
||||
k = { "<cmd>lua require 'gitsigns'.prev_hunk({navigation_message = false})<cr>", "Prev Hunk" },
|
||||
l = { "<cmd>lua require 'gitsigns'.blame_line()<cr>", "Blame" },
|
||||
p = { "<cmd>lua require 'gitsigns'.preview_hunk()<cr>", "Preview Hunk" },
|
||||
r = { "<cmd>lua require 'gitsigns'.reset_hunk()<cr>", "Reset Hunk" },
|
||||
R = { "<cmd>lua require 'gitsigns'.reset_buffer()<cr>", "Reset Buffer" },
|
||||
s = { "<cmd>lua require 'gitsigns'.stage_hunk()<cr>", "Stage Hunk" },
|
||||
u = {
|
||||
"<cmd>lua require 'gitsigns'.undo_stage_hunk()<cr>",
|
||||
"Undo Stage Hunk",
|
||||
},
|
||||
o = { "<cmd>Telescope git_status<cr>", "Open changed file" },
|
||||
b = { "<cmd>Telescope git_branches<cr>", "Checkout branch" },
|
||||
c = { "<cmd>Telescope git_commits<cr>", "Checkout commit" },
|
||||
C = {
|
||||
"<cmd>Telescope git_bcommits<cr>",
|
||||
"Checkout commit(for current file)",
|
||||
},
|
||||
d = {
|
||||
"<cmd>Gitsigns diffthis HEAD<cr>",
|
||||
"Git Diff",
|
||||
},
|
||||
},
|
||||
l = {
|
||||
name = "LSP",
|
||||
a = { "<cmd>lua vim.lsp.buf.code_action()<cr>", "Code Action" },
|
||||
d = { "<cmd>Telescope diagnostics bufnr=0 theme=get_ivy<cr>", "Buffer Diagnostics" },
|
||||
w = { "<cmd>Telescope diagnostics<cr>", "Diagnostics" },
|
||||
-- f = { require("lvim.lsp.utils").format, "Format" },
|
||||
i = { "<cmd>LspInfo<cr>", "Info" },
|
||||
I = { "<cmd>Mason<cr>", "Mason Info" },
|
||||
j = {
|
||||
vim.diagnostic.goto_next,
|
||||
"Next Diagnostic",
|
||||
},
|
||||
k = {
|
||||
vim.diagnostic.goto_prev,
|
||||
"Prev Diagnostic",
|
||||
},
|
||||
l = { vim.lsp.codelens.run, "CodeLens Action" },
|
||||
q = { vim.diagnostic.setloclist, "Quickfix" },
|
||||
r = { vim.lsp.buf.rename, "Rename" },
|
||||
s = { "<cmd>Telescope lsp_document_symbols<cr>", "Document Symbols" },
|
||||
S = {
|
||||
"<cmd>Telescope lsp_dynamic_workspace_symbols<cr>",
|
||||
"Workspace Symbols",
|
||||
},
|
||||
e = { "<cmd>Telescope quickfix<cr>", "Telescope Quickfix" },
|
||||
},
|
||||
|
||||
|
||||
a = { "<cmd>lua require('telescope.builtin').lsp_code_actions()<cr>", "Code Actions" },
|
||||
d = { "<cmd>lua require('telescope.builtin').lsp_document_diagnostics()<cr>", "LSP Diagnostics" },
|
||||
k = { "<cmd>lua vim.lsp.buf.signature_help()<cr>", "Signature Help" },
|
||||
P = { "<cmd>lua require'telescope'.extensions.projects.projects{}<cr>", "Signature Help" },
|
||||
}
|
||||
})
|
||||
|
||||
wk.register(
|
||||
{
|
||||
["/"] = { "<Plug>(comment_toggle_linewise_visual)", "Comment toggle linewise (visual)" },
|
||||
},
|
||||
{
|
||||
mode = "v", -- VISUAL mode
|
||||
prefix = "<leader>",
|
||||
buffer = nil, -- Global mappings. Specify a buffer number for buffer local mappings
|
||||
silent = true, -- use `silent` when creating keymaps
|
||||
noremap = true, -- use `noremap` when creating keymaps
|
||||
nowait = true, -- use `nowait` when creating keymaps
|
||||
}
|
||||
)
|
||||
83
utils/modules/nvim/default.nix
Normal file
83
utils/modules/nvim/default.nix
Normal file
@@ -0,0 +1,83 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
environment.variables = { EDITOR = "vim"; };
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
nodePackages.typescript-language-server
|
||||
sumneko-lua-language-server
|
||||
nodePackages.intelephense
|
||||
nodePackages.vscode-css-languageserver-bin
|
||||
nodePackages.yaml-language-server
|
||||
gopls
|
||||
lazygit
|
||||
(neovim.override {
|
||||
vimAlias = true;
|
||||
configure = {
|
||||
packages.myPlugins = with pkgs.vimPlugins; {
|
||||
start = [
|
||||
bufferline-nvim
|
||||
catppuccin-nvim
|
||||
cmp-buffer
|
||||
cmp-nvim-lsp
|
||||
cmp-path
|
||||
cmp-spell
|
||||
cmp-treesitter
|
||||
cmp-vsnip
|
||||
comment-nvim
|
||||
dracula-vim
|
||||
friendly-snippets
|
||||
gitsigns-nvim
|
||||
lightline-vim
|
||||
lspkind-nvim
|
||||
neogit
|
||||
null-ls-nvim
|
||||
nvim-autopairs
|
||||
nvim-cmp
|
||||
nvim-colorizer-lua
|
||||
nvim-lspconfig
|
||||
nvim-tree-lua
|
||||
nvim-ts-rainbow
|
||||
pkgs.vimPlugins.nvim-treesitter.withAllGrammars
|
||||
# (nvim-treesitter.withPlugins (_: pkgs.tree-sitter.allGrammars))
|
||||
plenary-nvim
|
||||
project-nvim
|
||||
telescope-fzf-native-nvim
|
||||
telescope-nvim
|
||||
toggleterm-nvim
|
||||
vim-floaterm
|
||||
vim-sneak
|
||||
vim-vsnip
|
||||
which-key-nvim
|
||||
];
|
||||
opt = [];
|
||||
};
|
||||
customRC = let
|
||||
luaRequire = module:
|
||||
builtins.readFile (builtins.toString
|
||||
./config
|
||||
+ "/${module}.lua");
|
||||
luaConfig = builtins.concatStringsSep "\n" (map luaRequire [
|
||||
"init"
|
||||
"keymappings"
|
||||
"icons"
|
||||
"lspconfig"
|
||||
"nvim-cmp"
|
||||
"theming"
|
||||
"project"
|
||||
"telescope"
|
||||
"terminal"
|
||||
"treesitter"
|
||||
"treesitter-textobjects"
|
||||
"utils"
|
||||
"bufferline"
|
||||
"which-key"
|
||||
]);
|
||||
in ''
|
||||
lua << EOF
|
||||
${luaConfig}
|
||||
EOF
|
||||
'';
|
||||
};
|
||||
}
|
||||
)];
|
||||
}
|
||||
325
utils/modules/openldap.nix
Normal file
325
utils/modules/openldap.nix
Normal file
@@ -0,0 +1,325 @@
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
services.openldap = {
|
||||
enable = true;
|
||||
|
||||
settings.attrs.olcLogLevel = "0";
|
||||
|
||||
settings.attrs.olcTLSCACertificateFile = config.sops.secrets.openldap-ca.path;
|
||||
settings.attrs.olcTLSCertificateFile = config.sops.secrets.openldap-cert.path;
|
||||
settings.attrs.olcTLSCertificateKeyFile = config.sops.secrets.openldap-key.path;
|
||||
|
||||
settings.children = {
|
||||
"cn=schema".includes = [
|
||||
"${pkgs.openldap}/etc/schema/core.ldif"
|
||||
"${pkgs.openldap}/etc/schema/cosine.ldif"
|
||||
"${pkgs.openldap}/etc/schema/inetorgperson.ldif"
|
||||
"${pkgs.openldap}/etc/schema/nis.ldif"
|
||||
];
|
||||
|
||||
"olcDatabase={1}mdb".attrs = {
|
||||
objectClass = ["olcDatabaseConfig" "olcMdbConfig"];
|
||||
olcDatabase = "{1}mdb";
|
||||
olcDbDirectory = "/var/lib/openldap/data";
|
||||
olcRootPW.path = config.sops.secrets.openldap-rootpw.path;
|
||||
olcRootDN = "cn=admin,dc=cloonar,dc=com";
|
||||
olcSuffix = "dc=cloonar,dc=com";
|
||||
olcAccess = [
|
||||
''
|
||||
{0}to attrs=userPassword
|
||||
by self write by anonymous auth
|
||||
by dn.base="cn=dovecot,dc=cloonar,dc=com" read
|
||||
by dn.base="cn=gogs,ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
read by * none
|
||||
''
|
||||
''
|
||||
{1}to attrs=loginShell
|
||||
by self write
|
||||
by * read
|
||||
''
|
||||
''
|
||||
{2}to dn.subtree="ou=system,ou=users,dc=cloonar,dc=com"
|
||||
by dn.base="cn=dovecot,dc=mail,dc=cloonar,dc=com" read
|
||||
by dn.subtree="ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
by * none
|
||||
''
|
||||
''
|
||||
{3}to dn.subtree="ou=jabber,ou=users,dc=cloonar,dc=com"
|
||||
by dn.base="cn=prosody,ou=system,ou=users,dc=eve" write
|
||||
by * read
|
||||
''
|
||||
''
|
||||
{4}to * by * read
|
||||
''
|
||||
];
|
||||
};
|
||||
"olcOverlay=syncprov,olcDatabase={1}mdb".attrs = {
|
||||
objectClass = ["olcOverlayConfig" "olcSyncProvConfig"];
|
||||
olcOverlay = "syncprov";
|
||||
olcSpSessionLog = "100";
|
||||
};
|
||||
"olcDatabase={2}monitor".attrs = {
|
||||
olcDatabase = "{2}monitor";
|
||||
objectClass = ["olcDatabaseConfig" "olcMonitorConfig"];
|
||||
olcAccess = [
|
||||
''
|
||||
{0}to *
|
||||
by dn.exact="cn=netdata,ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
by * none
|
||||
''
|
||||
];
|
||||
};
|
||||
|
||||
"cn={1}bitwarden,cn=schema" = {
|
||||
attrs = {
|
||||
cn = "{1}bitwarden";
|
||||
objectClass = "olcSchemaConfig";
|
||||
olcObjectClasses = [
|
||||
''
|
||||
(1.3.6.1.4.1.28298.1.2.4 NAME 'bitwarden'
|
||||
SUP uidObject AUXILIARY
|
||||
DESC 'Added to an account to allow bitwarden access'
|
||||
MUST (mail $ userPassword))
|
||||
''
|
||||
]
|
||||
};
|
||||
};
|
||||
# "cn={1}squid,cn=schema".attrs = {
|
||||
# cn = "{1}squid";
|
||||
# objectClass = "olcSchemaConfig";
|
||||
# olcObjectClasses = [
|
||||
# ''
|
||||
# (1.3.6.1.4.1.16548.1.2.4 NAME 'proxyUser'
|
||||
# SUP top AUXILIARY
|
||||
# DESC 'Account to allow a user to use the Squid proxy'
|
||||
# MUST ( mail $ userPassword ))
|
||||
# ''
|
||||
# ];
|
||||
# };
|
||||
# "cn={1}grafana,cn=schema".attrs = {
|
||||
# cn = "{1}grafana";
|
||||
# objectClass = "olcSchemaConfig";
|
||||
# olcObjectClasses = [
|
||||
# ''
|
||||
# (1.3.6.1.4.1.28293.1.2.5 NAME 'grafana'
|
||||
# SUP uidObject AUXILIARY
|
||||
# DESC 'Added to an account to allow grafana access'
|
||||
# MUST (mail))
|
||||
# ''
|
||||
# ];
|
||||
# };
|
||||
"cn={2}postfix,cn=schema".attrs = {
|
||||
cn = "{2}postfix";
|
||||
objectClass = "olcSchemaConfig";
|
||||
olcAttributeTypes = [
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.1.1 NAME 'postfixTransport'
|
||||
DESC 'A string directing postfix which transport to use'
|
||||
EQUALITY caseExactIA5Match
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{20} SINGLE-VALUE)''
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.1.5 NAME 'mailbox'
|
||||
DESC 'The absolute path to the mailbox for a mail account in a non-default location'
|
||||
EQUALITY caseExactIA5Match
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE)
|
||||
''
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.1.6 NAME 'quota'
|
||||
DESC 'A string that represents the quota on a mailbox'
|
||||
EQUALITY caseExactIA5Match
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE)
|
||||
''
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.1.8 NAME 'maildrop'
|
||||
DESC 'RFC822 Mailbox - mail alias'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256})
|
||||
''
|
||||
];
|
||||
olcObjectClasses = [
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.2.1 NAME 'mailAccount'
|
||||
SUP top AUXILIARY
|
||||
DESC 'Mail account objects'
|
||||
MUST ( mail $ userPassword )
|
||||
MAY ( cn $ description $ quota))
|
||||
''
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.2.2 NAME 'mailAlias'
|
||||
SUP top STRUCTURAL
|
||||
DESC 'Mail aliasing/forwarding entry'
|
||||
MUST ( mail $ maildrop )
|
||||
MAY ( cn $ description ))
|
||||
''
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.2.3 NAME 'mailDomain'
|
||||
SUP domain STRUCTURAL
|
||||
DESC 'Virtual Domain entry to be used with postfix transport maps'
|
||||
MUST ( dc )
|
||||
MAY ( postfixTransport $ description ))
|
||||
''
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.2.4 NAME 'mailPostmaster'
|
||||
SUP top AUXILIARY
|
||||
DESC 'Added to a mailAlias to create a postmaster entry'
|
||||
MUST roleOccupant)
|
||||
''
|
||||
];
|
||||
};
|
||||
"cn={1}openssh,cn=schema".attrs = {
|
||||
cn = "{1}openssh";
|
||||
objectClass = "olcSchemaConfig";
|
||||
olcAttributeTypes = [
|
||||
''
|
||||
(1.3.6.1.4.1.24552.500.1.1.1.13
|
||||
NAME 'sshPublicKey'
|
||||
DESC 'MANDATORY: OpenSSH Public key'
|
||||
EQUALITY octetStringMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
|
||||
''
|
||||
];
|
||||
olcObjectClasses = [
|
||||
''
|
||||
(1.3.6.1.4.1.24552.500.1.1.2.0
|
||||
NAME 'ldapPublicKey'
|
||||
SUP top AUXILIARY
|
||||
DESC 'MANDATORY: OpenSSH LPK objectclass'
|
||||
MUST ( sshPublicKey $ uid ))
|
||||
''
|
||||
];
|
||||
};
|
||||
"cn={1}nginx,cn=schema".attrs = {
|
||||
cn = "{1}nginx";
|
||||
objectClass = "olcSchemaConfig";
|
||||
olcObjectClasses = [
|
||||
''
|
||||
(1.3.6.1.4.1.28295.1.2.4 NAME 'nginx'
|
||||
SUP top AUXILIARY
|
||||
DESC 'Added to an account to allow nginx access'
|
||||
MUST ( mail $ userPassword ))
|
||||
''
|
||||
];
|
||||
};
|
||||
|
||||
"cn={1}nextcloud,cn=schema".attrs = {
|
||||
cn = "{1}nextcloud";
|
||||
objectClass = "olcSchemaConfig";
|
||||
olcAttributeTypes = [
|
||||
''
|
||||
(1.3.6.1.4.1.39430.1.1.1
|
||||
NAME 'ownCloudQuota'
|
||||
DESC 'User Quota (e.g. 15 GB)'
|
||||
SYNTAX '1.3.6.1.4.1.1466.115.121.1.15')
|
||||
''
|
||||
];
|
||||
olcObjectClasses = [
|
||||
''
|
||||
(1.3.6.1.4.1.39430.1.2.1
|
||||
NAME 'ownCloud'
|
||||
DESC 'ownCloud LDAP Schema'
|
||||
AUXILIARY
|
||||
MUST ( mail $ userPassword )
|
||||
MAY ( ownCloudQuota ))
|
||||
''
|
||||
];
|
||||
};
|
||||
"cn={1}gogs,cn=schema".attrs = {
|
||||
cn = "{1}gitlab";
|
||||
objectClass = "olcSchemaConfig";
|
||||
olcObjectClasses = [
|
||||
''
|
||||
( 1.3.6.1.4.1.28293.1.2.4 NAME 'gitlab'
|
||||
SUP uidObject AUXILIARY
|
||||
DESC 'Added to an account to allow gitlab access'
|
||||
MUST (mail))
|
||||
''
|
||||
];
|
||||
};
|
||||
"cn={1}iobroker,cn=schema".attrs = {
|
||||
cn = "{1}homeAssistant";
|
||||
objectClass = "olcSchemaConfig";
|
||||
olcObjectClasses = [
|
||||
''
|
||||
(1.3.6.1.4.1.28297.1.2.4 NAME 'homeAssistant'
|
||||
SUP uidObject AUXILIARY
|
||||
DESC 'Added to an account to allow home-assistant access'
|
||||
MUST (mail) )
|
||||
''
|
||||
];
|
||||
};
|
||||
# "cn={1}ttrss,cn=schema".attrs = {
|
||||
# cn = "{1}ttrss";
|
||||
# objectClass = "olcSchemaConfig";
|
||||
# olcObjectClasses = [
|
||||
# ''
|
||||
# ( 1.3.6.1.4.1.28294.1.2.4 NAME 'ttrss'
|
||||
# SUP top AUXILIARY
|
||||
# DESC 'Added to an account to allow tinytinyrss access'
|
||||
# MUST ( mail $ userPassword ))
|
||||
# ''
|
||||
# ];
|
||||
# };
|
||||
# "cn={1}prometheus,cn=schema".attrs = {
|
||||
# cn = "{1}prometheus";
|
||||
# objectClass = "olcSchemaConfig";
|
||||
# olcObjectClasses = [
|
||||
# ''
|
||||
# ( 1.3.6.1.4.1.28296.1.2.4
|
||||
# NAME 'prometheus'
|
||||
# SUP uidObject AUXILIARY
|
||||
# DESC 'Added to an account to allow prometheus access'
|
||||
# MUST (mail))
|
||||
# ''
|
||||
# ];
|
||||
# };
|
||||
# "cn={1}loki,cn=schema".attrs = {
|
||||
# cn = "{1}loki";
|
||||
# objectClass = "olcSchemaConfig";
|
||||
# olcObjectClasses = [
|
||||
# ''
|
||||
# ( 1.3.6.1.4.1.28299.1.2.4
|
||||
# NAME 'loki'
|
||||
# SUP uidObject AUXILIARY
|
||||
# DESC 'Added to an account to allow loki access'
|
||||
# MUST (mail))
|
||||
# ''
|
||||
# ];
|
||||
# };
|
||||
# "cn={1}flood,cn=schema".attrs = {
|
||||
# cn = "{1}flood";
|
||||
# objectClass = "olcSchemaConfig";
|
||||
# olcObjectClasses = [
|
||||
# ''
|
||||
# (1.3.6.1.4.1.28300.1.2.4 NAME 'flood'
|
||||
# SUP uidObject AUXILIARY
|
||||
# DESC 'Added to an account to allow flood access'
|
||||
# MUST (mail))
|
||||
# ''
|
||||
# ];
|
||||
# };
|
||||
};
|
||||
};
|
||||
|
||||
sops.secrets.openldap-rootpw = {
|
||||
owner = "openldap";
|
||||
sopsFile = ./secrets.yaml;
|
||||
};
|
||||
sops.secrets.openldap-ca = {
|
||||
owner = "openldap";
|
||||
sopsFile = ./secrets.yaml;
|
||||
};
|
||||
sops.secrets.openldap-cert = {
|
||||
owner = "openldap";
|
||||
sopsFile = ./secrets.yaml;
|
||||
};
|
||||
sops.secrets.openldap-key = {
|
||||
owner = "openldap";
|
||||
sopsFile = ./secrets.yaml;
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [636];
|
||||
}
|
||||
480
utils/modules/openldap/default.nix
Normal file
480
utils/modules/openldap/default.nix
Normal file
@@ -0,0 +1,480 @@
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
domain = config.networking.domain;
|
||||
# domain = "cloonar.com";
|
||||
in {
|
||||
services.openldap = {
|
||||
enable = true;
|
||||
|
||||
urlList = [ "ldap:///" "ldaps:///" ];
|
||||
|
||||
settings.attrs = {
|
||||
olcLogLevel = "-1";
|
||||
|
||||
olcTLSCACertificateFile = "/var/lib/acme/ldap.${domain}/full.pem";
|
||||
olcTLSCertificateFile = "/var/lib/acme/ldap.${domain}/cert.pem";
|
||||
olcTLSCertificateKeyFile = "/var/lib/acme/ldap.${domain}/key.pem";
|
||||
olcTLSCipherSuite = "HIGH:MEDIUM:+3DES:+RC4:+aNULL";
|
||||
olcTLSCRLCheck = "none";
|
||||
olcTLSVerifyClient = "never";
|
||||
olcTLSProtocolMin = "3.1";
|
||||
olcSecurity = "tls=1";
|
||||
};
|
||||
|
||||
settings.children = {
|
||||
"cn=schema".includes = [
|
||||
"${pkgs.openldap}/etc/schema/core.ldif"
|
||||
"${pkgs.openldap}/etc/schema/cosine.ldif"
|
||||
"${pkgs.openldap}/etc/schema/inetorgperson.ldif"
|
||||
"${pkgs.openldap}/etc/schema/nis.ldif"
|
||||
];
|
||||
|
||||
"olcDatabase={1}mdb".attrs = {
|
||||
objectClass = ["olcDatabaseConfig" "olcMdbConfig"];
|
||||
|
||||
olcDatabase = "{1}mdb";
|
||||
olcDbDirectory = "/var/lib/openldap/data";
|
||||
|
||||
olcSuffix = "dc=cloonar,dc=com";
|
||||
|
||||
olcRootDN = "cn=admin,dc=cloonar,dc=com";
|
||||
olcRootPW.path = config.sops.secrets.openldap-rootpw.path;
|
||||
|
||||
|
||||
olcAccess = [
|
||||
''
|
||||
{0}to attrs=userPassword
|
||||
by self write
|
||||
by anonymous auth
|
||||
by dn="cn=owncloud,ou=system,ou=users,dc=cloonar,dc=com" write
|
||||
by dn.subtree="ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
by group.exact="cn=Administrators,ou=groups,dc=cloonar,dc=com" write
|
||||
by * none
|
||||
''
|
||||
''
|
||||
{1}to attrs=loginShell
|
||||
by self write
|
||||
by dn.subtree="ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
by group.exact="cn=Administrators,ou=groups,dc=cloonar,dc=com" write
|
||||
by * none
|
||||
''
|
||||
''
|
||||
{2}to dn.subtree="ou=system,ou=users,dc=cloonar,dc=com"
|
||||
by dn.subtree="ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
by group.exact="cn=Administrators,ou=groups,dc=cloonar,dc=com" write
|
||||
by * none
|
||||
''
|
||||
''
|
||||
{3}to *
|
||||
by dn.subtree="ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
by dn="cn=admin,dc=cloonar,dc=com" write
|
||||
by group.exact="cn=Administrators,ou=groups,dc=cloonar,dc=com" write
|
||||
by * none
|
||||
''
|
||||
];
|
||||
};
|
||||
"olcOverlay=memberof,olcDatabase={1}mdb".attrs = {
|
||||
objectClass = [ "olcOverlayConfig" "olcMemberOf" ];
|
||||
olcOverlay = "memberof";
|
||||
olcMemberOfRefint = "TRUE";
|
||||
};
|
||||
"olcOverlay=ppolicy,olcDatabase={1}mdb".attrs = {
|
||||
objectClass = [ "olcOverlayConfig" "olcPPolicyConfig" ];
|
||||
olcOverlay = "ppolicy";
|
||||
olcPPolicyHashCleartext = "TRUE";
|
||||
};
|
||||
# "olcOverlay=syncprov,olcDatabase={1}mdb".attrs = {
|
||||
# objectClass = ["olcOverlayConfig" "olcSyncProvConfig"];
|
||||
# olcOverlay = "syncprov";
|
||||
# olcSpSessionLog = "100";
|
||||
# };
|
||||
"olcDatabase={2}monitor".attrs = {
|
||||
olcDatabase = "{2}monitor";
|
||||
objectClass = ["olcDatabaseConfig" "olcMonitorConfig"];
|
||||
olcAccess = [
|
||||
''
|
||||
{0}to *
|
||||
by dn.exact="cn=netdata,ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
by * none
|
||||
''
|
||||
];
|
||||
};
|
||||
|
||||
"olcDatabase={3}mdb".attrs = {
|
||||
objectClass = ["olcDatabaseConfig" "olcMdbConfig"];
|
||||
|
||||
olcDatabase = "{3}mdb";
|
||||
olcDbDirectory = "/var/lib/openldap/data";
|
||||
|
||||
olcSuffix = "dc=ghetto,dc=at";
|
||||
|
||||
olcAccess = [
|
||||
''
|
||||
{0}to attrs=userPassword
|
||||
by self write
|
||||
by anonymous auth
|
||||
by dn="cn=owncloud,ou=system,ou=users,dc=cloonar,dc=com" write
|
||||
by dn.subtree="ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
by group.exact="cn=Administrators,ou=groups,dc=cloonar,dc=com" write
|
||||
by * none
|
||||
''
|
||||
''
|
||||
{1}to *
|
||||
by dn.subtree="ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
by group.exact="cn=Administrators,ou=groups,dc=cloonar,dc=com" write
|
||||
by * read
|
||||
''
|
||||
];
|
||||
};
|
||||
"olcOverlay=memberof,olcDatabase={3}mdb".attrs = {
|
||||
objectClass = [ "olcOverlayConfig" "olcMemberOf" ];
|
||||
olcOverlay = "memberof";
|
||||
olcMemberOfRefint = "TRUE";
|
||||
};
|
||||
"olcOverlay=ppolicy,olcDatabase={3}mdb".attrs = {
|
||||
objectClass = [ "olcOverlayConfig" "olcPPolicyConfig" ];
|
||||
olcOverlay = "ppolicy";
|
||||
olcPPolicyHashCleartext = "TRUE";
|
||||
};
|
||||
|
||||
"olcDatabase={4}mdb".attrs = {
|
||||
objectClass = ["olcDatabaseConfig" "olcMdbConfig"];
|
||||
|
||||
olcDatabase = "{4}mdb";
|
||||
olcDbDirectory = "/var/lib/openldap/data";
|
||||
|
||||
olcSuffix = "dc=superbros,dc=tv";
|
||||
|
||||
olcAccess = [
|
||||
''
|
||||
{0}to attrs=userPassword
|
||||
by self write
|
||||
by anonymous auth
|
||||
by dn="cn=owncloud,ou=system,ou=users,dc=cloonar,dc=com" write
|
||||
by dn.subtree="ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
by group.exact="cn=Administrators,ou=groups,dc=cloonar,dc=com" write
|
||||
by * none
|
||||
''
|
||||
''
|
||||
{1}to *
|
||||
by dn.subtree="ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
by group.exact="cn=Administrators,ou=groups,dc=cloonar,dc=com" write
|
||||
by * read
|
||||
''
|
||||
];
|
||||
};
|
||||
"olcOverlay=memberof,olcDatabase={4}mdb".attrs = {
|
||||
objectClass = [ "olcOverlayConfig" "olcMemberOf" ];
|
||||
olcOverlay = "memberof";
|
||||
olcMemberOfRefint = "TRUE";
|
||||
};
|
||||
"olcOverlay=ppolicy,olcDatabase={4}mdb".attrs = {
|
||||
objectClass = [ "olcOverlayConfig" "olcPPolicyConfig" ];
|
||||
olcOverlay = "ppolicy";
|
||||
olcPPolicyHashCleartext = "TRUE";
|
||||
};
|
||||
|
||||
"olcDatabase={5}mdb".attrs = {
|
||||
objectClass = ["olcDatabaseConfig" "olcMdbConfig"];
|
||||
|
||||
olcDatabase = "{5}mdb";
|
||||
olcDbDirectory = "/var/lib/openldap/data";
|
||||
|
||||
olcSuffix = "dc=optiprot,dc=eu";
|
||||
|
||||
olcAccess = [
|
||||
''
|
||||
{0}to attrs=userPassword
|
||||
by self write
|
||||
by anonymous auth
|
||||
by dn="cn=owncloud,ou=system,ou=users,dc=cloonar,dc=com" write
|
||||
by dn.subtree="ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
by group.exact="cn=Administrators,ou=groups,dc=cloonar,dc=com" write
|
||||
by * none
|
||||
''
|
||||
''
|
||||
{1}to *
|
||||
by dn.subtree="ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
by group.exact="cn=Administrators,ou=groups,dc=cloonar,dc=com" write
|
||||
by * read
|
||||
''
|
||||
];
|
||||
};
|
||||
"olcOverlay=memberof,olcDatabase={5}mdb".attrs = {
|
||||
objectClass = [ "olcOverlayConfig" "olcMemberOf" ];
|
||||
olcOverlay = "memberof";
|
||||
olcMemberOfRefint = "TRUE";
|
||||
};
|
||||
"olcOverlay=ppolicy,olcDatabase={5}mdb".attrs = {
|
||||
objectClass = [ "olcOverlayConfig" "olcPPolicyConfig" ];
|
||||
olcOverlay = "ppolicy";
|
||||
olcPPolicyHashCleartext = "TRUE";
|
||||
};
|
||||
|
||||
"olcDatabase={6}mdb".attrs = {
|
||||
objectClass = ["olcDatabaseConfig" "olcMdbConfig"];
|
||||
|
||||
olcDatabase = "{6}mdb";
|
||||
olcDbDirectory = "/var/lib/openldap/data";
|
||||
|
||||
olcSuffix = "dc=szaku-consulting,dc=at";
|
||||
|
||||
olcAccess = [
|
||||
''
|
||||
{0}to attrs=userPassword
|
||||
by self write
|
||||
by anonymous auth
|
||||
by dn="cn=owncloud,ou=system,ou=users,dc=cloonar,dc=com" write
|
||||
by dn.subtree="ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
by group.exact="cn=Administrators,ou=groups,dc=cloonar,dc=com" write
|
||||
by * none
|
||||
''
|
||||
''
|
||||
{1}to *
|
||||
by dn.subtree="ou=system,ou=users,dc=cloonar,dc=com" read
|
||||
by group.exact="cn=Administrators,ou=groups,dc=cloonar,dc=com" write
|
||||
by * read
|
||||
''
|
||||
];
|
||||
};
|
||||
"olcOverlay=memberof,olcDatabase={6}mdb".attrs = {
|
||||
objectClass = [ "olcOverlayConfig" "olcMemberOf" ];
|
||||
olcOverlay = "memberof";
|
||||
olcMemberOfRefint = "TRUE";
|
||||
};
|
||||
"olcOverlay=ppolicy,olcDatabase={6}mdb".attrs = {
|
||||
objectClass = [ "olcOverlayConfig" "olcPPolicyConfig" ];
|
||||
olcOverlay = "ppolicy";
|
||||
olcPPolicyHashCleartext = "TRUE";
|
||||
};
|
||||
|
||||
# "cn=module{0},cn=config" = {
|
||||
# attrs = {
|
||||
# objectClass = "olcModuleList";
|
||||
# cn = "module{0}";
|
||||
# olcModuleLoad = "ppolicy.la";
|
||||
# };
|
||||
# };
|
||||
|
||||
"cn={3}cloonar,cn=schema" = {
|
||||
attrs = {
|
||||
cn = "{1}cloonar";
|
||||
objectClass = "olcSchemaConfig";
|
||||
olcObjectClasses = [
|
||||
''
|
||||
(1.3.6.1.4.1.28298.1.2.4 NAME 'cloonarUser'
|
||||
SUP (mailAccount) AUXILIARY
|
||||
DESC 'Cloonar Account'
|
||||
MAY (sshPublicKey $ ownCloudQuota $ quota))
|
||||
''
|
||||
];
|
||||
};
|
||||
};
|
||||
"cn={2}postfix,cn=schema".attrs = {
|
||||
cn = "{2}postfix";
|
||||
objectClass = "olcSchemaConfig";
|
||||
olcAttributeTypes = [
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.1.1 NAME 'postfixTransport'
|
||||
DESC 'A string directing postfix which transport to use'
|
||||
EQUALITY caseExactIA5Match
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{20} SINGLE-VALUE)''
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.1.5 NAME 'mailbox'
|
||||
DESC 'The absolute path to the mailbox for a mail account in a non-default location'
|
||||
EQUALITY caseExactIA5Match
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE)
|
||||
''
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.1.6 NAME 'quota'
|
||||
DESC 'A string that represents the quota on a mailbox'
|
||||
EQUALITY caseExactIA5Match
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE)
|
||||
''
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.1.8 NAME 'maildrop'
|
||||
DESC 'RFC822 Mailbox - mail alias'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256})
|
||||
''
|
||||
];
|
||||
olcObjectClasses = [
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.2.1 NAME 'mailAccount'
|
||||
SUP top AUXILIARY
|
||||
DESC 'Mail account objects'
|
||||
MUST ( mail $ userPassword )
|
||||
MAY ( cn $ description $ quota))
|
||||
''
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.2.2 NAME 'mailAlias'
|
||||
SUP top STRUCTURAL
|
||||
DESC 'Mail aliasing/forwarding entry'
|
||||
MUST ( mail $ maildrop )
|
||||
MAY ( cn $ description ))
|
||||
''
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.2.3 NAME 'mailDomain'
|
||||
SUP domain STRUCTURAL
|
||||
DESC 'Virtual Domain entry to be used with postfix transport maps'
|
||||
MUST ( dc )
|
||||
MAY ( postfixTransport $ description ))
|
||||
''
|
||||
''
|
||||
(1.3.6.1.4.1.12461.1.2.4 NAME 'mailPostmaster'
|
||||
SUP top AUXILIARY
|
||||
DESC 'Added to a mailAlias to create a postmaster entry'
|
||||
MUST roleOccupant)
|
||||
''
|
||||
];
|
||||
};
|
||||
"cn={1}openssh,cn=schema".attrs = {
|
||||
cn = "{1}openssh";
|
||||
objectClass = "olcSchemaConfig";
|
||||
olcAttributeTypes = [
|
||||
''
|
||||
(1.3.6.1.4.1.24552.500.1.1.1.13
|
||||
NAME 'sshPublicKey'
|
||||
DESC 'MANDATORY: OpenSSH Public key'
|
||||
EQUALITY octetStringMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
|
||||
''
|
||||
];
|
||||
olcObjectClasses = [
|
||||
''
|
||||
(1.3.6.1.4.1.24552.500.1.1.2.0
|
||||
NAME 'ldapPublicKey'
|
||||
SUP top AUXILIARY
|
||||
DESC 'MANDATORY: OpenSSH LPK objectclass'
|
||||
MUST ( sshPublicKey $ uid ))
|
||||
''
|
||||
];
|
||||
};
|
||||
"cn={1}nextcloud,cn=schema".attrs = {
|
||||
cn = "{1}nextcloud";
|
||||
objectClass = "olcSchemaConfig";
|
||||
olcAttributeTypes = [
|
||||
''
|
||||
(1.3.6.1.4.1.39430.1.1.1
|
||||
NAME 'ownCloudQuota'
|
||||
DESC 'User Quota (e.g. 15 GB)'
|
||||
SYNTAX '1.3.6.1.4.1.1466.115.121.1.15')
|
||||
''
|
||||
];
|
||||
olcObjectClasses = [
|
||||
''
|
||||
(1.3.6.1.4.1.39430.1.2.1
|
||||
NAME 'ownCloud'
|
||||
DESC 'ownCloud LDAP Schema'
|
||||
AUXILIARY
|
||||
MUST ( mail $ userPassword )
|
||||
MAY ( ownCloudQuota ))
|
||||
''
|
||||
];
|
||||
};
|
||||
"cn={1}gogs,cn=schema".attrs = {
|
||||
cn = "{1}gogs";
|
||||
objectClass = "olcSchemaConfig";
|
||||
olcObjectClasses = [
|
||||
''
|
||||
( 1.3.6.1.4.1.28293.1.2.4 NAME 'gitlab'
|
||||
SUP uidObject AUXILIARY
|
||||
DESC 'Added to an account to allow gitlab access'
|
||||
MUST (mail))
|
||||
''
|
||||
];
|
||||
};
|
||||
"cn={1}homeAssistant,cn=schema".attrs = {
|
||||
cn = "{1}homeAssistant";
|
||||
objectClass = "olcSchemaConfig";
|
||||
olcObjectClasses = [
|
||||
''
|
||||
(1.3.6.1.4.1.28297.1.2.4 NAME 'homeAssistant'
|
||||
SUP uidObject AUXILIARY
|
||||
DESC 'Added to an account to allow home-assistant access'
|
||||
MUST (mail) )
|
||||
''
|
||||
];
|
||||
};
|
||||
# "cn={1}ttrss,cn=schema".attrs = {
|
||||
# cn = "{1}ttrss";
|
||||
# objectClass = "olcSchemaConfig";
|
||||
# olcObjectClasses = [
|
||||
# ''
|
||||
# ( 1.3.6.1.4.1.28294.1.2.4 NAME 'ttrss'
|
||||
# SUP top AUXILIARY
|
||||
# DESC 'Added to an account to allow tinytinyrss access'
|
||||
# MUST ( mail $ userPassword ))
|
||||
# ''
|
||||
# ];
|
||||
# };
|
||||
# "cn={1}prometheus,cn=schema".attrs = {
|
||||
# cn = "{1}prometheus";
|
||||
# objectClass = "olcSchemaConfig";
|
||||
# olcObjectClasses = [
|
||||
# ''
|
||||
# ( 1.3.6.1.4.1.28296.1.2.4
|
||||
# NAME 'prometheus'
|
||||
# SUP uidObject AUXILIARY
|
||||
# DESC 'Added to an account to allow prometheus access'
|
||||
# MUST (mail))
|
||||
# ''
|
||||
# ];
|
||||
# };
|
||||
# "cn={1}loki,cn=schema".attrs = {
|
||||
# cn = "{1}loki";
|
||||
# objectClass = "olcSchemaConfig";
|
||||
# olcObjectClasses = [
|
||||
# ''
|
||||
# ( 1.3.6.1.4.1.28299.1.2.4
|
||||
# NAME 'loki'
|
||||
# SUP uidObject AUXILIARY
|
||||
# DESC 'Added to an account to allow loki access'
|
||||
# MUST (mail))
|
||||
# ''
|
||||
# ];
|
||||
# };
|
||||
# "cn={1}flood,cn=schema".attrs = {
|
||||
# cn = "{1}flood";
|
||||
# objectClass = "olcSchemaConfig";
|
||||
# olcObjectClasses = [
|
||||
# ''
|
||||
# (1.3.6.1.4.1.28300.1.2.4 NAME 'flood'
|
||||
# SUP uidObject AUXILIARY
|
||||
# DESC 'Added to an account to allow flood access'
|
||||
# MUST (mail))
|
||||
# ''
|
||||
# ];
|
||||
# };
|
||||
};
|
||||
};
|
||||
|
||||
/* ensure openldap is launched after certificates are created */
|
||||
systemd.services.openldap = {
|
||||
wants = [ "acme-${domain}.service" ];
|
||||
after = [ "acme-${domain}.service" ];
|
||||
};
|
||||
|
||||
users.groups.acme.members = [ "openldap" ];
|
||||
|
||||
/* trigger the actual certificate generation for your hostname */
|
||||
security.acme.certs."ldap.${domain}" = {
|
||||
extraDomainNames = [
|
||||
"ldap-test.${domain}"
|
||||
"ldap-02.${domain}"
|
||||
];
|
||||
postRun = "systemctl restart openldap.service";
|
||||
};
|
||||
|
||||
sops.secrets.openldap-rootpw = {
|
||||
owner = "openldap";
|
||||
sopsFile = ./secrets.yaml;
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 389 636 ];
|
||||
}
|
||||
40
utils/modules/openldap/secrets.yaml
Normal file
40
utils/modules/openldap/secrets.yaml
Normal file
@@ -0,0 +1,40 @@
|
||||
openldap-rootpw: ENC[AES256_GCM,data:cwxXkLd5jyrGI4IoewQL4HBH/Xi6SfVkizitKa0Qyr30SeH02VDLyGXzbpuRfZuPRePbLFEOMKUcCwkZV/2RTA==,iv:SqxCK5rnsgU6i68ZoBZtbRxLgUe59wMg7EYO5jlAwFw=,tag:SbORanDDqLPF+dNleqzYNg==,type:str]
|
||||
dovecot-ldap-password: ENC[AES256_GCM,data:czkIYqmWXs0U6LFbetJg47VQHw+E5kcHpdwRGmZAKi6Q3hP/IOW8N1dhIkrQRLzKih9vWXKhyo6BDA2e6w6pHQ==,iv:Ka18K0/pGJubfiQ1GKq3uxwZ/CgujO1DulwBomXBbco=,tag:QACpoLJ+QIMM3mCI/vTjtA==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
azure_kv: []
|
||||
hc_vault: []
|
||||
age:
|
||||
- recipient: age16veg3fmvpfm7a89a9fc8dvvsxmsthlm70nfxqspr6t8vnf9wkcwsvdq38d
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpcnBXWk1JaE9McXlzMUk3
|
||||
bXZHRXRQbDdsK25MNTY1MHA0UWhCcWJRdlVVCmlzcDE0L1ZOQzB6MVBPYUdncUZr
|
||||
M0FGSkdxaFpiY2NUTlRBSUZZdUJmRzgKLS0tIGs3UlNwUDJYVTFHTXcvZkJCS0w5
|
||||
cGJic1JZTHE2NnkxN2JuYXY0TmZUWjAKN6orRU5LnJbl84HtKy0MBNA/PiuEmuhO
|
||||
JL/tpFX+LiOScFHrvb40Ka6YvnyER+rufZXi1xknBzW1uyDt+lSyQw==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1jyeppc8yl2twnv8fwcewutd5gjewnxl59lmhev6ygds9qel8zf8syt7zz4
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1RWNUenVwS2xISmRQK3RN
|
||||
ZEc5TGF2MGNocnZWNkhHQ1lGOU1adlFCZlJ3CmdOWC8vQVd4aEdLVTJtNTZCM1R5
|
||||
VndOM3RJRy9laW1pa1k0TUt5UTEyVmsKLS0tIFB5aDNZQXlTRlYvUkJaOXI3NVky
|
||||
VHFINVFjVVVsTXViTDV0QmFBWTRsbVkKJCjMI1GImwSKpgTDVwF5xAdnbUqBkxUO
|
||||
vYFySQg5p12lZ7RtMbxdql24a52J9Jm/2dMMKKph339vw/rcW7YRXQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1azmxsw5llmp2nnsv3yc2l8paelmq9rfepxd8jvmswgsmax0qyyxqdnsc7t
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBDdXJGOFgzZFhFWXEvZkNB
|
||||
OWI3MDQxVGZ5dGpXM245ZUlHZHJhRnR0UWl3CnNKeGhLNVdYVWdoWWFBaC90ZUhj
|
||||
Mjc4MDQxa0ZaMnVaSndWRDFrTjVpZmMKLS0tIG9rZGJJb0J6SE1lSjdWSHc0V2FH
|
||||
dGJqSzB5NE5ESzE1L0ZxTDBORnpvRUUKtKejHfzBGnrOJzPStRUcjD/cRq3BqsdP
|
||||
PtSh9ujx/aazn1O86wMYuIgb1WfWL3ZyTtoPCukGKth9KT1JweU1eA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2023-01-22T20:44:32Z"
|
||||
mac: ENC[AES256_GCM,data:nKR47o4Evt4TPyndEwZlnP/ctGaaz6wwn0k+JnDCL3FW1TO64spNL7xDcoxWwPuRLrgjgtazsm4Tevplzc3J/N4dhnPAdiPtZOQd3tKibIJKDkxG+6upGvzMMrXXInzoGVqwFMrZmdIqlpLAgqX/1VwY4Tnrf0IfiwJ8wWmSZe8=,iv:FUL/gcDZBZrclYupzstSFG86NOnEOvvgr8ou7wVQ3AY=,tag:KPXm0HHwc8v64dnqGqlFUQ==,type:str]
|
||||
pgp: []
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.7.3
|
||||
2
utils/modules/parsecgaming.nix
Normal file
2
utils/modules/parsecgaming.nix
Normal file
@@ -0,0 +1,2 @@
|
||||
#(import <nixpkgs> {}).callPackage (builtins.fetchurl "https://raw.githubusercontent.com/delroth/infra.delroth.net/master/pkgs/parsec.nix") {}
|
||||
#(import <nixpkgs> {}).callPackage (builtins.fetchurl "https://raw.githubusercontent.com/delroth/infra.delroth.net/38a040e4bbfef7ee13c4b0a75dc79c77ddfdc759/pkgs/parsec.nix") {}
|
||||
42
utils/modules/plausible/default.nix
Normal file
42
utils/modules/plausible/default.nix
Normal file
@@ -0,0 +1,42 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
sops.secrets.plausible-admin-password = {
|
||||
sopsFile = ./secrets.yaml;
|
||||
};
|
||||
sops.secrets.plausible-secret = {
|
||||
sopsFile = ./secrets.yaml;
|
||||
};
|
||||
|
||||
services.plausible = {
|
||||
enable = true;
|
||||
releaseCookiePath = "/run/secrets/plausible-release-cookie";
|
||||
server = {
|
||||
secretKeybaseFile = config.sops.secrets.plausible-secret.path;
|
||||
baseUrl = "plausible.cloonar.com";
|
||||
};
|
||||
database.clickhouse = {
|
||||
setup = false;
|
||||
};
|
||||
database.postgres = {
|
||||
dbname = "plausible";
|
||||
};
|
||||
adminUser = {
|
||||
activate = true;
|
||||
email = "plausible@cloonar.com";
|
||||
passwordFile = config.sops.secrets.plausible-admin-password.path;
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.enable = true;
|
||||
services.nginx.virtualHosts."plausible.cloonar.com" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:8000";
|
||||
};
|
||||
};
|
||||
|
||||
services.postgresqlBackup.databases = [ "plausible" ];
|
||||
}
|
||||
31
utils/modules/plausible/secrets.yaml
Normal file
31
utils/modules/plausible/secrets.yaml
Normal file
@@ -0,0 +1,31 @@
|
||||
plausible-admin-password: ENC[AES256_GCM,data:S46PqHBpGRnAq5lv9Pb0NZalg+9hVj8330prH45DlhGG679W4gXzQOwetgQlsr3HAL8I3Uu6Dk4/FWHIKQKGFw==,iv:x9AXhJEoe0Ilx/WEc8f3g2hS0ZFo/DvKcwQBk62KUSk=,tag:Pn9lddsKeEKIv2IDQjFHjA==,type:str]
|
||||
plausible-secret: ENC[AES256_GCM,data:HS5rDCbGzjhgv5lxNS9IgjrQ+EzBQgfVQxjHK3Kh++9Q1o7TO5IsFBaBw9BRXKMvzILpmCV737ltBcTV6zSZaZBiJmCf+hA7501Zn1RxWMjujlMWf+DTM/Ut7VK/4oc63K/4TLvvGhManl0ia0f8Rwm720JBdbnIrb7e6YSfe74=,iv:atUmTo4+uHFMIiWoxDe79Pj4dE00+0o30DsqUPoL9NY=,tag:jFd+xZvwyRB//Nx1e8BgKw==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
azure_kv: []
|
||||
hc_vault: []
|
||||
age:
|
||||
- recipient: age16veg3fmvpfm7a89a9fc8dvvsxmsthlm70nfxqspr6t8vnf9wkcwsvdq38d
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMUGdqU1hWR1dMVXhnYUNY
|
||||
ZFYvb3pCOG1DMWs5bGtscmNTdHdQY0ltRGhrCmhJZkdWMmNUMk5WaFI0REZNc0Jp
|
||||
SkFHUzB0RjA5cWh2bDd6NDAxeUFqd1kKLS0tIEFmcFNOUTBPcXpJUDRLRGRVWWVC
|
||||
b3FkcVRhLzNZa0poUmdPM3NoRnRnUnMK/HRww0ewz+LIBeWlbgHlgh/+mAJuhmwI
|
||||
xEID8pv0gOh+HGEKdRa+BajLmDhTfvnoJadhVswSTMWc/iewgAPs3w==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1y6lvl5jkwc47p5ae9yz9j9kuwhy7rtttua5xhygrgmr7ehd49svsszyt42
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKcXdNeTFzeWJkSUx4TllE
|
||||
azZtQXhtSmZHWk1ld05hcTNXTWhaQlY4eVFFClZrOTN5QTRHKzR1VFhENFEyQ3Qv
|
||||
Yno4aUw3Y2c5Q1RUSTF0L1hBdTY5bE0KLS0tIHd0T2Zpeko5QVFnVHZ4alh5cUJz
|
||||
ejh0bExnMEF1MUhLZ0N5SzFpZnM0cFUKgzlIYqwgi9nsik59S+Bxj/Mj5f09JS5I
|
||||
nVG+2A05+8XxA+eGqcRTYFyo3w71R8hdfmu3vfXl+Ywb+P51K+SDkA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2023-04-17T20:01:37Z"
|
||||
mac: ENC[AES256_GCM,data:cm8XdC5CUaQ5KUrkKXSaEfJ/VbxpQQAJg5LZ5O5+3kkWL1qSAK3z4PSnGs58GFlEfw2iFcyOWQr/wH7GPZsSo8/J4fN0zTqYkn+Mn2GZaYMcqr1K1U8tIgq6qLGf2UqG5/AvED4nGY48/aGvGyYyKIak8sgPm8uGz+DwX+ApiMk=,iv:jNe/PmLq5fHuyxQQj4H4hF8V7rCl/Xj3wNMP2bEsEQY=,tag:BNOi0YVH83S4pV9e38WcHQ==,type:str]
|
||||
pgp: []
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.7.3
|
||||
246
utils/modules/postfix.nix
Normal file
246
utils/modules/postfix.nix
Normal file
@@ -0,0 +1,246 @@
|
||||
{ pkgs
|
||||
, lib
|
||||
, config
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
domain = config.networking.domain;
|
||||
ldapServer = "ldap.cloonar.com";
|
||||
# domain = "cloonar.com";
|
||||
|
||||
domains = pkgs.writeText "domains.cf" ''
|
||||
server_host = ldap://${ldapServer}
|
||||
search_base = ou=domains,dc=cloonar,dc=com
|
||||
version = 3
|
||||
bind = yes
|
||||
start_tls = yes
|
||||
bind_dn = cn=vmail,ou=system,ou=users,dc=cloonar,dc=com
|
||||
bind_pw = @ldap-password@
|
||||
scope = one
|
||||
query_filter = (&(dc=%s)(objectClass=mailDomain))
|
||||
result_attribute = postfixTransport
|
||||
debuglevel = 0
|
||||
'';
|
||||
|
||||
mailboxes = pkgs.writeText "mailboxes.cf" ''
|
||||
server_host = ldap://${ldapServer}
|
||||
search_base = ou=users,dc=%2,dc=%1
|
||||
version = 3
|
||||
bind = yes
|
||||
start_tls = yes
|
||||
bind_dn = cn=vmail,ou=system,ou=users,dc=cloonar,dc=com
|
||||
bind_pw = @ldap-password@
|
||||
scope = sub
|
||||
query_filter = (&(uid=%u)(objectClass=mailAccount))
|
||||
result_attribute = mail
|
||||
debuglevel = 0
|
||||
'';
|
||||
|
||||
senderLoginMaps = pkgs.writeText "sender_login_maps.cf" ''
|
||||
server_host = ldap://${ldapServer}
|
||||
search_base = dc=%2,dc=%1
|
||||
version = 3
|
||||
bind = yes
|
||||
start_tls = yes
|
||||
bind_dn = cn=vmail,ou=system,ou=users,dc=cloonar,dc=com
|
||||
bind_pw = @ldap-password@
|
||||
scope = sub
|
||||
query_filter = (|(&(objectClass=mailAccount)(uid=%u))(&(objectClass=mailAlias)(mail=%s)))
|
||||
result_attribute = maildrop, mail
|
||||
debuglevel = 0
|
||||
'';
|
||||
|
||||
accountsmap = pkgs.writeText "accountsmap.cf" ''
|
||||
server_host = ldap://${ldapServer}
|
||||
search_base = ou=users,dc=%2,dc=%1
|
||||
version = 3
|
||||
bind = yes
|
||||
start_tls = yes
|
||||
bind_dn = cn=vmail,ou=system,ou=users,dc=cloonar,dc=com
|
||||
bind_pw = @ldap-password@
|
||||
scope = sub
|
||||
query_filter = (&(objectClass=mailAccount)(uid=%u))
|
||||
result_attribute = mail
|
||||
debuglevel = 0
|
||||
'';
|
||||
|
||||
aliases = pkgs.writeText "aliases.cf" ''
|
||||
server_host = ldap://${ldapServer}
|
||||
search_base = ou=aliases,dc=%2,dc=%1
|
||||
version = 3
|
||||
bind = yes
|
||||
start_tls = yes
|
||||
bind_dn = cn=vmail,ou=system,ou=users,dc=cloonar,dc=com
|
||||
bind_pw = @ldap-password@
|
||||
scope = one
|
||||
query_filter = (&(objectClass=mailAlias)(mail=%s))
|
||||
result_attribute = maildrop
|
||||
debuglevel = 0
|
||||
'';
|
||||
|
||||
helo_access = pkgs.writeText "helo_access" ''
|
||||
/^([0-9\.]+)$/ REJECT ACCESS DENIED. Your email was rejected because the sending mail server sent non RFC compliant HELO identity (''${1})
|
||||
cloonar.com REJECT ACCESS DENIED. Your email was rejected because the sending mail server sent non RFC compliant HELO identity (''${1})
|
||||
ghetto.at REJECT ACCESS DENIED. Your email was rejected because the sending mail server sent non RFC compliant HELO identity (''${1})
|
||||
'';
|
||||
in
|
||||
{
|
||||
services.postfix = {
|
||||
enable = true;
|
||||
enableSubmission = true;
|
||||
hostname = "mail.${domain}";
|
||||
domain = "cloonar.com";
|
||||
|
||||
masterConfig."465" = {
|
||||
type = "inet";
|
||||
private = false;
|
||||
command = "smtpd";
|
||||
args = [
|
||||
"-o smtpd_client_restrictions=permit_sasl_authenticated,reject"
|
||||
"-o syslog_name=postfix/smtps"
|
||||
"-o smtpd_tls_wrappermode=yes"
|
||||
"-o smtpd_sasl_auth_enable=yes"
|
||||
"-o smtpd_tls_security_level=none"
|
||||
"-o smtpd_reject_unlisted_recipient=no"
|
||||
"-o smtpd_recipient_restrictions="
|
||||
"-o smtpd_relay_restrictions=permit_sasl_authenticated,reject"
|
||||
"-o milter_macro_daemon_name=ORIGINATING"
|
||||
];
|
||||
};
|
||||
|
||||
mapFiles."helo_access" = helo_access;
|
||||
|
||||
config = {
|
||||
# debug_peer_list = "10.42.96.190";
|
||||
# smtp_bind_address = config.networking.eve.ipv4.address;
|
||||
# smtp_bind_address6 = "2a01:4f9:2b:1605::1";
|
||||
mailbox_transport = "lmtp:unix:private/dovecot-lmtp";
|
||||
virtual_mailbox_domains = "ldap:/run/postfix/domains.cf";
|
||||
virtual_mailbox_maps = "ldap:/run/postfix/mailboxes.cf";
|
||||
virtual_alias_maps = "ldap:/run/postfix/accountsmap.cf,ldap:/run/postfix/aliases.cf";
|
||||
virtual_transport = "lmtp:unix:private/dovecot-lmtp";
|
||||
smtpd_sender_login_maps = "ldap:/run/postfix/sender_login_maps.cf";
|
||||
|
||||
# Do not display the name of the recipient table in the "User unknown" responses.
|
||||
# The extra detail makes trouble shooting easier but also reveals information
|
||||
# that is nobody elses business.
|
||||
show_user_unknown_table_name = "no";
|
||||
compatibility_level = "2";
|
||||
|
||||
# bigger attachement size
|
||||
mailbox_size_limit = "202400000";
|
||||
message_size_limit = "51200000";
|
||||
smtpd_helo_required = "yes";
|
||||
smtpd_delay_reject = "yes";
|
||||
strict_rfc821_envelopes = "yes";
|
||||
|
||||
# send Limit
|
||||
smtpd_error_sleep_time = "1s";
|
||||
smtpd_soft_error_limit = "10";
|
||||
smtpd_hard_error_limit = "20";
|
||||
|
||||
smtpd_use_tls = "yes";
|
||||
smtp_tls_note_starttls_offer = "yes";
|
||||
smtpd_tls_security_level = "may";
|
||||
smtpd_tls_auth_only = "yes";
|
||||
|
||||
smtp_dns_support_level = "dnssec";
|
||||
smtp_tls_security_level = "dane";
|
||||
|
||||
smtpd_tls_cert_file = "/var/lib/acme/mail.cloonar.com/full.pem";
|
||||
smtpd_tls_key_file = "/var/lib/acme/mail.cloonar.com/key.pem";
|
||||
smtpd_tls_CAfile = "/var/lib/acme/mail.cloonar.com/fullchain.pem";
|
||||
|
||||
smtpd_tls_dh512_param_file = config.security.dhparams.params.postfix512.path;
|
||||
smtpd_tls_dh1024_param_file = config.security.dhparams.params.postfix2048.path;
|
||||
|
||||
smtpd_tls_session_cache_database = ''btree:''${data_directory}/smtpd_scache'';
|
||||
smtpd_tls_mandatory_protocols = "!SSLv2,!SSLv3,!TLSv1,!TLSv1.1";
|
||||
smtpd_tls_protocols = "!SSLv2,!SSLv3,!TLSv1,!TLSv1.1";
|
||||
smtpd_tls_mandatory_ciphers = "medium";
|
||||
tls_medium_cipherlist = "AES128+EECDH:AES128+EDH";
|
||||
|
||||
# authentication
|
||||
smtpd_sasl_auth_enable = "yes";
|
||||
smtpd_sasl_local_domain = "$mydomain";
|
||||
smtpd_sasl_security_options = "noanonymous";
|
||||
smtpd_sasl_tls_security_options = "$smtpd_sasl_security_options";
|
||||
smtpd_sasl_type = "dovecot";
|
||||
smtpd_sasl_path = "/var/lib/postfix/queue/private/auth";
|
||||
smtpd_relay_restrictions = "
|
||||
permit_mynetworks,
|
||||
permit_sasl_authenticated,
|
||||
defer_unauth_destination";
|
||||
smtpd_client_restrictions = "
|
||||
permit_mynetworks,
|
||||
permit_sasl_authenticated,
|
||||
reject_invalid_hostname,
|
||||
reject_unknown_client,
|
||||
permit";
|
||||
smtpd_helo_restrictions = "
|
||||
permit_mynetworks,
|
||||
permit_sasl_authenticated,
|
||||
reject_unauth_pipelining,
|
||||
reject_non_fqdn_hostname,
|
||||
reject_invalid_hostname,
|
||||
warn_if_reject reject_unknown_hostname,
|
||||
permit";
|
||||
smtpd_recipient_restrictions = "
|
||||
permit_mynetworks,
|
||||
permit_sasl_authenticated,
|
||||
reject_non_fqdn_sender,
|
||||
reject_non_fqdn_recipient,
|
||||
reject_non_fqdn_hostname,
|
||||
reject_invalid_hostname,
|
||||
reject_unknown_sender_domain,
|
||||
reject_unknown_recipient_domain,
|
||||
reject_unknown_client_hostname,
|
||||
reject_unauth_pipelining,
|
||||
reject_unknown_client,
|
||||
permit";
|
||||
smtpd_sender_restrictions = "
|
||||
reject_non_fqdn_sender,
|
||||
reject_unlisted_sender,
|
||||
reject_authenticated_sender_login_mismatch,
|
||||
permit_mynetworks,
|
||||
permit_sasl_authenticated,
|
||||
reject_unknown_sender_domain,
|
||||
reject_unknown_client_hostname,
|
||||
reject_unknown_address";
|
||||
|
||||
smtpd_etrn_restrictions = "permit_mynetworks, reject";
|
||||
smtpd_data_restrictions = "reject_unauth_pipelining, reject_multi_recipient_bounce, permit";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [ "d /run/postfix 0750 postfix postfix -" ];
|
||||
|
||||
systemd.services.postfix.preStart = ''
|
||||
sed -e "s/@ldap-password@/$(cat ${config.sops.secrets.dovecot-ldap-password.path})/" ${domains} > /run/postfix/domains.cf
|
||||
sed -e "s/@ldap-password@/$(cat ${config.sops.secrets.dovecot-ldap-password.path})/" ${mailboxes} > /run/postfix/mailboxes.cf
|
||||
sed -e "s/@ldap-password@/$(cat ${config.sops.secrets.dovecot-ldap-password.path})/" ${accountsmap} > /run/postfix/accountsmap.cf
|
||||
sed -e "s/@ldap-password@/$(cat ${config.sops.secrets.dovecot-ldap-password.path})/" ${aliases} > /run/postfix/aliases.cf
|
||||
sed -e "s/@ldap-password@/$(cat ${config.sops.secrets.dovecot-ldap-password.path})/" ${senderLoginMaps} > /run/postfix/sender_login_maps.cf
|
||||
'';
|
||||
|
||||
security.dhparams = {
|
||||
enable = true;
|
||||
params.postfix512.bits = 512;
|
||||
params.postfix2048.bits = 1024;
|
||||
};
|
||||
|
||||
security.acme.certs."mail.${domain}" = {
|
||||
extraDomainNames = [
|
||||
"mail-test.${domain}"
|
||||
"mail-02.${domain}"
|
||||
];
|
||||
postRun = "systemctl restart postfix.service";
|
||||
group = "postfix";
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
25 # smtp
|
||||
465 # smtps
|
||||
587 # submission
|
||||
];
|
||||
}
|
||||
112
utils/modules/room-assistant.nix
Normal file
112
utils/modules/room-assistant.nix
Normal file
@@ -0,0 +1,112 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.services.room-assistant;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
services.room-assistant = {
|
||||
enable = mkEnableOption (lib.mdDoc "room-assistant");
|
||||
|
||||
name = mkOption {
|
||||
type = with types; uniq string;
|
||||
description = "
|
||||
...
|
||||
";
|
||||
default = "room";
|
||||
};
|
||||
|
||||
mqttHost = mkOption {
|
||||
type = with types; uniq string;
|
||||
description = "
|
||||
...
|
||||
";
|
||||
default = "";
|
||||
};
|
||||
|
||||
mqttUser = mkOption {
|
||||
type = with types; uniq string;
|
||||
description = "
|
||||
...
|
||||
";
|
||||
default = "espresense";
|
||||
};
|
||||
|
||||
mqttPassword = mkOption {
|
||||
type = with types; uniq string;
|
||||
description = "
|
||||
...
|
||||
";
|
||||
default = "insecure-password";
|
||||
};
|
||||
};
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
hardware = {
|
||||
bluetooth.enable = true;
|
||||
deviceTree.filter = "bcm2711-rpi-*.dtb";
|
||||
};
|
||||
|
||||
systemd.services = {
|
||||
btattach = {
|
||||
before = [ "bluetooth.service" ];
|
||||
after = [ "dev-ttyAMA0.device" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
ExecStart = "${pkgs.bluez}/bin/btattach -B /dev/ttyAMA0 -P bcm -S 3000000";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
virtualisation.docker.enable = true;
|
||||
|
||||
environment.etc."room-assistant.yml" = {
|
||||
text = ''
|
||||
global:
|
||||
instanceName: ${cfg.name}
|
||||
integrations:
|
||||
- homeAssistant
|
||||
- bluetoothClassic
|
||||
homeAssistant:
|
||||
mqttUrl: 'mqtt://${cfg.mqttHost}'
|
||||
mqttOptions:
|
||||
username: ${cfg.mqttUser}
|
||||
password: ${cfg.mqttPassword}
|
||||
bluetoothClassic:
|
||||
addresses:
|
||||
- A8:5B:B7:98:84:F0
|
||||
- 00:24:E4:E6:FE:AD
|
||||
|
||||
'';
|
||||
|
||||
# The UNIX file mode bits
|
||||
mode = "0440";
|
||||
};
|
||||
|
||||
systemd.services."room-assistant" = {
|
||||
description = "room-assistant";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "docker.service" "docker.socket" ];
|
||||
requires = [ "docker.service" "docker.socket" ];
|
||||
script = ''
|
||||
exec ${pkgs.docker}/bin/docker run \
|
||||
--rm \
|
||||
--name=room-assistant \
|
||||
--network=host \
|
||||
-v /var/run/dbus:/var/run/dbus \
|
||||
-v /etc/room-assistant.yml:/room-assistant/config/local.yml \
|
||||
--cap-add=NET_ADMIN \
|
||||
mkerix/room-assistant:2.20.0
|
||||
'';
|
||||
preStop = "${pkgs.docker}/bin/docker stop room-assistant";
|
||||
reload = "${pkgs.docker}/bin/docker restart room-assistant";
|
||||
serviceConfig = {
|
||||
ExecStartPre = "-${pkgs.docker}/bin/docker rm -f room-assistant";
|
||||
ExecStopPost = "-${pkgs.docker}/bin/docker rm -f room-assistant";
|
||||
TimeoutStartSec = 0;
|
||||
TimeoutStopSec = 120;
|
||||
Restart = "always";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
22
utils/modules/roundcube.nix
Normal file
22
utils/modules/roundcube.nix
Normal file
@@ -0,0 +1,22 @@
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
domain = "mail-test.cloonar.com";
|
||||
in
|
||||
{
|
||||
services.roundcube = {
|
||||
enable = true;
|
||||
hostName = "${domain}";
|
||||
extraConfig = ''
|
||||
$config['imap_host'] = 'tls://imap-test.cloonar.com';
|
||||
$config['smtp_server'] = "tls://mail-test.cloonar.com";
|
||||
$config['smtp_user'] = "%u";
|
||||
$config['smtp_pass'] = "%p";
|
||||
'';
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."${domain}" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
};
|
||||
}
|
||||
131
utils/modules/rspamd.nix
Normal file
131
utils/modules/rspamd.nix
Normal file
@@ -0,0 +1,131 @@
|
||||
{ pkgs
|
||||
, config
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
domain = config.networking.domain;
|
||||
|
||||
localConfig = pkgs.writeText "local.conf" ''
|
||||
logging {
|
||||
level = "notice";
|
||||
}
|
||||
classifier "bayes" {
|
||||
autolearn = true;
|
||||
}
|
||||
dkim_signing {
|
||||
path = "/var/lib/rspamd/dkim/$domain.$selector.key";
|
||||
selector = "default";
|
||||
allow_username_mismatch = true;
|
||||
}
|
||||
arc {
|
||||
path = "/var/lib/rspamd/dkim/$domain.$selector.key";
|
||||
selector = "default";
|
||||
allow_username_mismatch = true;
|
||||
}
|
||||
milter_headers {
|
||||
use = ["authentication-results", "x-spam-status"];
|
||||
authenticated_headers = ["authentication-results"];
|
||||
}
|
||||
replies {
|
||||
action = "no action";
|
||||
}
|
||||
url_reputation {
|
||||
enabled = true;
|
||||
}
|
||||
phishing {
|
||||
openphish_enabled = true;
|
||||
# too much memory
|
||||
#phishtank_enabled = true;
|
||||
}
|
||||
neural {
|
||||
enabled = true;
|
||||
}
|
||||
neural_group {
|
||||
symbols = {
|
||||
"NEURAL_SPAM" {
|
||||
weight = 3.0; # sample weight
|
||||
description = "Neural network spam";
|
||||
}
|
||||
"NEURAL_HAM" {
|
||||
weight = -3.0; # sample weight
|
||||
description = "Neural network ham";
|
||||
}
|
||||
}
|
||||
}
|
||||
'';
|
||||
|
||||
sieve-spam-filter = pkgs.callPackage ../pkgs/sieve-spam-filter { };
|
||||
in
|
||||
{
|
||||
services.rspamd = {
|
||||
enable = true;
|
||||
extraConfig = ''
|
||||
.include(priority=1,duplicate=merge) "${localConfig}"
|
||||
'';
|
||||
|
||||
postfix.enable = true;
|
||||
workers.controller = {
|
||||
extraConfig = ''
|
||||
count = 1;
|
||||
static_dir = "''${WWWDIR}";
|
||||
password = "$2$7rb4gnnw8qbcy3x3m7au8c4mezecfjim$da4ahtt3gnjtbj7ni6bt1q8jwgqtzxp5ck6941m6prjxsz3udfgb";
|
||||
enable_password = "$2$xo1qdd1zgozwto8yazr1o35zbarbzcgp$u8mx6hcsb1qdscejb4zadcb3iucmm4mw6btgmim9h6e5d8cpy5ib";
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
services.dovecot2 = {
|
||||
mailboxes.Spam = {
|
||||
auto = "subscribe";
|
||||
specialUse = "Junk";
|
||||
};
|
||||
extraConfig = ''
|
||||
protocol imap {
|
||||
mail_plugins = $mail_plugins imap_sieve
|
||||
}
|
||||
|
||||
plugin {
|
||||
sieve_plugins = sieve_imapsieve sieve_extprograms
|
||||
|
||||
# From elsewhere to Spam folder
|
||||
imapsieve_mailbox1_name = Spam
|
||||
imapsieve_mailbox1_causes = COPY
|
||||
imapsieve_mailbox1_before = file:/var/lib/dovecot/sieve/report-spam.sieve
|
||||
|
||||
# From Spam folder to elsewhere
|
||||
imapsieve_mailbox2_name = *
|
||||
imapsieve_mailbox2_from = Spam
|
||||
imapsieve_mailbox2_causes = COPY
|
||||
imapsieve_mailbox2_before = file:/var/lib/dovecot/sieve/report-ham.sieve
|
||||
|
||||
# Move Spam emails to Spam folder
|
||||
sieve_before = /var/lib/dovecot/sieve/move-to-spam.sieve
|
||||
|
||||
sieve_pipe_bin_dir = ${sieve-spam-filter}/bin
|
||||
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
services.nginx.enable = true;
|
||||
services.nginx.virtualHosts."rspamd.${domain}" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
locations."/".extraConfig = ''
|
||||
proxy_pass http://localhost:11334;
|
||||
'';
|
||||
};
|
||||
|
||||
# systemd.services.rspamd.serviceConfig.SupplementaryGroups = [ "redis-rspamd" ];
|
||||
|
||||
systemd.services.dovecot2.preStart = ''
|
||||
mkdir -p /var/lib/dovecot/sieve/
|
||||
for i in ${sieve-spam-filter}/share/sieve-rspamd-filter/*.sieve; do
|
||||
dest="/var/lib/dovecot/sieve/$(basename $i)"
|
||||
cp "$i" "$dest"
|
||||
${pkgs.dovecot_pigeonhole}/bin/sievec "$dest"
|
||||
done
|
||||
chown -R "${config.services.dovecot2.mailUser}:${config.services.dovecot2.mailGroup}" /var/lib/dovecot/sieve
|
||||
'';
|
||||
}
|
||||
118
utils/modules/self-service-password.nix
Normal file
118
utils/modules/self-service-password.nix
Normal file
@@ -0,0 +1,118 @@
|
||||
{ pkgs, lib, config, ... }:
|
||||
let
|
||||
domain = "self-service.cloonar.com";
|
||||
php = pkgs.php82;
|
||||
version = "1.5.2";
|
||||
dataDir = "/var/www/${domain}";
|
||||
in {
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
smarty3
|
||||
];
|
||||
|
||||
systemd.services."phpfpm-${domain}".serviceConfig.ProtectHome = lib.mkForce false;
|
||||
|
||||
systemd.services.selfservicepassword_setup = let
|
||||
overrideConfig = pkgs.writeText "nextcloud-config.php" ''
|
||||
<?php
|
||||
$ldap_url = "ldap://ldap-test.cloonar.com:389";
|
||||
$ldap_starttls = true;
|
||||
define("SMARTY", "Smarty.class.php");
|
||||
$use_tokens = false;
|
||||
$use_sms = false;
|
||||
'';
|
||||
in {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
before = [ "phpfpm-${domain}.service" ];
|
||||
script = ''
|
||||
mkdir -p ${dataDir}/public
|
||||
curl -L https://github.com/ltb-project/self-service-password/archive/refs/tags/v${version}.tar.gz > ${dataDir}/package.tar.gz
|
||||
/run/current-system/sw/bin/tar xf ${dataDir}/package.tar.gz -C ${dataDir}
|
||||
mv ${dataDir}/self-service-password-${version}/* ${dataDir}/public/
|
||||
rm -rf ${dataDir}/self-service-password-${version}
|
||||
cp ${overrideConfig} ${dataDir}/public/conf/config.inc.local.php
|
||||
'';
|
||||
path = [ pkgs.gzip pkgs.curl ];
|
||||
serviceConfig.Type = "oneshot";
|
||||
serviceConfig.User = domain;
|
||||
};
|
||||
|
||||
services.phpfpm.pools."${domain}" = {
|
||||
user = domain;
|
||||
settings = {
|
||||
"listen.owner" = config.services.nginx.user;
|
||||
"pm" = "dynamic";
|
||||
"pm.max_children" = 32;
|
||||
"pm.max_requests" = 500;
|
||||
"pm.start_servers" = 2;
|
||||
"pm.min_spare_servers" = 2;
|
||||
"pm.max_spare_servers" = 5;
|
||||
"php_flag[display_errors]" = "on";
|
||||
"php_admin_value[error_log]" = "/var/log/${domain}.error.log";
|
||||
"php_admin_flag[log_errors]" = "on";
|
||||
"php_value[include_path]" = ".:/usr/share/php:${pkgs.smarty3}";
|
||||
"catch_workers_output" = "yes";
|
||||
"access.log" = "/var/log/$pool.access.log";
|
||||
};
|
||||
phpPackage = php;
|
||||
phpEnv."PATH" = lib.makeBinPath [ php ];
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."${domain}" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
root = "${dataDir}/public/htdocs";
|
||||
|
||||
locations."/favicon.ico".extraConfig = ''
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
'';
|
||||
|
||||
# extraConfig = ''
|
||||
# if (!-e $request_filename) {
|
||||
# rewrite ^/(.+)\.(\d+)\.(php|js|css|png|jpg|gif|gzip)$ /$1.$3 last;
|
||||
# }
|
||||
# '';
|
||||
|
||||
locations."/".extraConfig = ''
|
||||
index index.php index.html;
|
||||
try_files $uri $uri/ /index.php$is_args$args;
|
||||
'';
|
||||
|
||||
locations."~ [^/]\.php(/|$)".extraConfig = ''
|
||||
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
|
||||
if (!-f $document_root$fastcgi_script_name) {
|
||||
return 404;
|
||||
}
|
||||
include ${pkgs.nginx}/conf/fastcgi_params;
|
||||
include ${pkgs.nginx}/conf/fastcgi.conf;
|
||||
fastcgi_buffer_size 32k;
|
||||
fastcgi_buffers 8 16k;
|
||||
fastcgi_connect_timeout 240s;
|
||||
fastcgi_read_timeout 240s;
|
||||
fastcgi_send_timeout 240s;
|
||||
fastcgi_pass unix:${config.services.phpfpm.pools."${domain}".socket};
|
||||
fastcgi_index index.php;
|
||||
'';
|
||||
|
||||
# locations."~ /\.".extraConfig = ''
|
||||
# log_not_found off;
|
||||
# deny all;
|
||||
# '';
|
||||
#
|
||||
# locations."~ /scripts".extraConfig = ''
|
||||
# log_not_found off;
|
||||
# deny all;
|
||||
# '';
|
||||
};
|
||||
users.users."${domain}" = {
|
||||
#isSystemUser = true;
|
||||
isNormalUser = true;
|
||||
createHome = true;
|
||||
home = dataDir;
|
||||
homeMode= "770";
|
||||
group = "nginx";
|
||||
};
|
||||
users.groups.${domain} = {};
|
||||
}
|
||||
319
utils/modules/services/web/stack.nix
Normal file
319
utils/modules/services/web/stack.nix
Normal file
@@ -0,0 +1,319 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.webstack;
|
||||
|
||||
instanceOpts = { name, ... }:
|
||||
{
|
||||
options = {
|
||||
user = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
User of the typo3 instance. Defaults to attribute name in instances.
|
||||
'';
|
||||
example = "example.org";
|
||||
};
|
||||
|
||||
domain = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
Domain of the typo3 instance. Defaults to attribute name in instances.
|
||||
'';
|
||||
example = "example.org";
|
||||
};
|
||||
|
||||
domainAliases = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "www.example.org" "example.org" ];
|
||||
description = lib.mdDoc ''
|
||||
Additional domains served by this typo3 instance.
|
||||
'';
|
||||
};
|
||||
|
||||
phpPackage = mkOption {
|
||||
type = types.package;
|
||||
example = literalExpression "pkgs.php";
|
||||
description = lib.mdDoc ''
|
||||
Which PHP package to use in this typo3 instance.
|
||||
'';
|
||||
};
|
||||
|
||||
enableMysql = mkEnableOption (lib.mdDoc "MySQL Database");
|
||||
enableDefaultLocations = mkEnableOption (lib.mdDoc "Create default nginx location directives") // { default = true; };
|
||||
|
||||
authorizedKeys = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
Authorized keys for the typo3 instance ssh user.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = ''
|
||||
if (!-e $request_filename) {
|
||||
rewrite ^/(.+)\.(\d+)\.(php|js|css|png|jpg|gif|gzip)$ /$1.$3 last;
|
||||
}
|
||||
'';
|
||||
description = lib.mdDoc ''
|
||||
These lines go to the end of the vhost verbatim.
|
||||
'';
|
||||
};
|
||||
|
||||
locations = mkOption {
|
||||
type = types.attrsOf (types.submodule (import <nixpkgs/nixos/modules/services/web-servers/nginx/location-options.nix> {
|
||||
inherit lib config;
|
||||
}));
|
||||
default = {};
|
||||
example = literalExpression ''
|
||||
{
|
||||
"/" = {
|
||||
proxyPass = "http://localhost:3000";
|
||||
};
|
||||
};
|
||||
'';
|
||||
description = lib.mdDoc "Declarative location config";
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
in
|
||||
|
||||
{
|
||||
options.services.webstack = {
|
||||
dataDir = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/www";
|
||||
description = lib.mdDoc ''
|
||||
The data directory for MySQL.
|
||||
|
||||
::: {.note}
|
||||
If left as the default value of `/var/www` this directory will automatically be created before the web
|
||||
server starts, otherwise you are responsible for ensuring the directory exists with appropriate ownership and permissions.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
instances = mkOption {
|
||||
type = types.attrsOf (types.submodule instanceOpts);
|
||||
default = {};
|
||||
description = lib.mdDoc "Create vhosts for typo3";
|
||||
example = literalExpression ''
|
||||
{
|
||||
"typo3.example.com" = {
|
||||
domain = "example.com";
|
||||
domainAliases = [ "www.example.com" ];
|
||||
phpPackage = pkgs.php81;
|
||||
authorizedKeys = [
|
||||
"ssh-rsa AZA=="
|
||||
];
|
||||
};
|
||||
};
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
systemd.services = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
in
|
||||
nameValuePair "phpfpm-${domain}" {
|
||||
serviceConfig = {
|
||||
ProtectHome = lib.mkForce "tmpfs";
|
||||
BindPaths = "BindPaths=/var/www/${domain}:/var/www/${domain}";
|
||||
};
|
||||
}
|
||||
) cfg.instances;
|
||||
|
||||
services.phpfpm.pools = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
nameValuePair domain {
|
||||
user = user;
|
||||
settings = {
|
||||
"listen.owner" = config.services.nginx.user;
|
||||
"pm" = "dynamic";
|
||||
"pm.max_children" = 32;
|
||||
"pm.max_requests" = 500;
|
||||
"pm.start_servers" = 2;
|
||||
"pm.min_spare_servers" = 2;
|
||||
"pm.max_spare_servers" = 5;
|
||||
"php_admin_value[error_log]" = "syslog";
|
||||
"php_admin_value[max_execution_time]" = 240;
|
||||
"php_admin_value[max_input_vars]" = 1500;
|
||||
"access.log" = "/var/log/$pool.access.log";
|
||||
};
|
||||
phpPackage = instanceOpts.phpPackage;
|
||||
phpEnv."PATH" = pkgs.lib.makeBinPath [ instanceOpts.phpPackage ];
|
||||
}
|
||||
) cfg.instances;
|
||||
|
||||
};
|
||||
|
||||
|
||||
config.services.nginx.virtualHosts = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
nameValuePair domain {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
root = cfg.dataDir + "/" + domain + "/public";
|
||||
|
||||
locations = lib.mkMerge [
|
||||
instanceOpts.locations
|
||||
(mkIf instanceOpts.enableDefaultLocations {
|
||||
"/favicon.ico".extraConfig = ''
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
'';
|
||||
|
||||
# Cache.appcache, your document html and data
|
||||
"~* \\.(?:manifest|appcache|html?|xml|json)$".extraConfig = ''
|
||||
expires -1;
|
||||
# access_log logs/static.log; # I don't usually include a static log
|
||||
'';
|
||||
|
||||
"~* \\.(jpe?g|png)$".extraConfig = ''
|
||||
set $red Z;
|
||||
|
||||
if ($http_accept ~* "webp") {
|
||||
set $red A;
|
||||
}
|
||||
|
||||
if (-f $document_root/webp/$request_uri.webp) {
|
||||
set $red "''${red}B";
|
||||
}
|
||||
|
||||
if ($red = "AB") {
|
||||
add_header Vary Accept;
|
||||
rewrite ^ /webp/$request_uri.webp;
|
||||
}
|
||||
'';
|
||||
|
||||
# Cache Media: images, icons, video, audio, HTC
|
||||
"~* \\.(?:jpg|jpeg|gif|png|webp|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|woff2)$".extraConfig = ''
|
||||
expires 1y;
|
||||
access_log off;
|
||||
add_header Cache-Control "public";
|
||||
'';
|
||||
|
||||
# Feed
|
||||
"~* \\.(?:rss|atom)$".extraConfig = ''
|
||||
expires 1h;
|
||||
add_header Cache-Control "public";
|
||||
'';
|
||||
|
||||
# Cache CSS, Javascript, Images, Icons, Video, Audio, HTC, Fonts
|
||||
"~* \\.(?:css|js|jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|woff2)$".extraConfig = ''
|
||||
expires 1y;
|
||||
access_log off;
|
||||
add_header Cache-Control "public";
|
||||
'';
|
||||
|
||||
"/".extraConfig = ''
|
||||
index index.php index.html;
|
||||
try_files $uri $uri/ /index.php$is_args$args;
|
||||
'';
|
||||
})
|
||||
{
|
||||
"~ [^/]\\.php(/|$)".extraConfig = ''
|
||||
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
|
||||
if (!-f $document_root$fastcgi_script_name) {
|
||||
return 404;
|
||||
}
|
||||
include ${pkgs.nginx}/conf/fastcgi_params;
|
||||
include ${pkgs.nginx}/conf/fastcgi.conf;
|
||||
fastcgi_buffer_size 32k;
|
||||
fastcgi_buffers 8 16k;
|
||||
fastcgi_connect_timeout 240s;
|
||||
fastcgi_read_timeout 240s;
|
||||
fastcgi_send_timeout 240s;
|
||||
fastcgi_pass unix:${config.services.phpfpm.pools."${domain}".socket};
|
||||
fastcgi_index index.php;
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
extraConfig = instanceOpts.extraConfig;
|
||||
|
||||
|
||||
# locations = mapAttrs' (location: locationOpts:
|
||||
# nameValuePair location locationOpts) instanceOpts.locations;
|
||||
|
||||
}
|
||||
) cfg.instances;
|
||||
|
||||
config.users.users = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
nameValuePair user {
|
||||
isNormalUser = true;
|
||||
createHome = true;
|
||||
home = "/var/www/" + domain;
|
||||
homeMode= "770";
|
||||
group = config.services.nginx.group;
|
||||
openssh.authorizedKeys.keys = instanceOpts.authorizedKeys;
|
||||
}
|
||||
) cfg.instances;
|
||||
config.users.groups = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in nameValuePair user {}) cfg.instances;
|
||||
|
||||
config.services.mysql.ensureUsers = mapAttrsToList (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
mkIf instanceOpts.enableMysql {
|
||||
name = user;
|
||||
ensurePermissions = {
|
||||
"${user}.*" = "ALL PRIVILEGES";
|
||||
};
|
||||
}) cfg.instances;
|
||||
|
||||
config.services.mysql.ensureDatabases = mapAttrsToList (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
mkIf instanceOpts.enableMysql user
|
||||
) cfg.instances;
|
||||
config.services.mysqlBackup.databases = mapAttrsToList (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
mkIf instanceOpts.enableMysql user
|
||||
) cfg.instances;
|
||||
}
|
||||
|
||||
367
utils/modules/services/web/typo3.nix
Normal file
367
utils/modules/services/web/typo3.nix
Normal file
@@ -0,0 +1,367 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.typo3;
|
||||
|
||||
instanceOpts = { name, ... }:
|
||||
{
|
||||
options = {
|
||||
user = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
User of the typo3 instance. Defaults to attribute name in instances.
|
||||
'';
|
||||
example = "example.org";
|
||||
};
|
||||
|
||||
domain = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
Domain of the typo3 instance. Defaults to attribute name in instances.
|
||||
'';
|
||||
example = "example.org";
|
||||
};
|
||||
|
||||
domainAliases = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "www.example.org" "example.org" ];
|
||||
description = lib.mdDoc ''
|
||||
Additional domains served by this typo3 instance.
|
||||
'';
|
||||
};
|
||||
|
||||
phpPackage = mkOption {
|
||||
type = types.package;
|
||||
example = literalExpression "pkgs.php";
|
||||
description = lib.mdDoc ''
|
||||
Which PHP package to use in this typo3 instance.
|
||||
'';
|
||||
};
|
||||
|
||||
authorizedKeys = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
Authorized keys for the typo3 instance ssh user.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
|
||||
{
|
||||
options.services.typo3 = {
|
||||
dataDir = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/www";
|
||||
description = lib.mdDoc ''
|
||||
The data directory for MySQL.
|
||||
|
||||
::: {.note}
|
||||
If left as the default value of `/var/www` this directory will automatically be created before the web
|
||||
server starts, otherwise you are responsible for ensuring the directory exists with appropriate ownership and permissions.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
instances = mkOption {
|
||||
type = types.attrsOf (types.submodule instanceOpts);
|
||||
default = {};
|
||||
description = lib.mdDoc "Create vhosts for typo3";
|
||||
example = literalExpression ''
|
||||
{
|
||||
"typo3.example.com" = {
|
||||
domain = "example.com";
|
||||
domainAliases = [ "www.example.com" ];
|
||||
phpPackage = pkgs.php82;
|
||||
authorizedKeys = [
|
||||
"ssh-rsa AZA=="
|
||||
];
|
||||
};
|
||||
};
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
# systemd.services = mapAttrs' (instance: instanceOpts:
|
||||
# let
|
||||
# domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
# in
|
||||
# nameValuePair "phpfpm-${domain}" {
|
||||
# serviceConfig = {
|
||||
# ProtectHome = lib.mkForce "tmpfs";
|
||||
# BindPaths = "BindPaths=/var/www/${domain}:/var/www/${domain}";
|
||||
# };
|
||||
# }
|
||||
# ) cfg.instances;
|
||||
|
||||
systemd.timers = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
nameValuePair ("typo3-cron-" + domain) {
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnCalendar = "05:00";
|
||||
Unit = "typo3-cron-" + domain + ".service";
|
||||
};
|
||||
}
|
||||
) cfg.instances;
|
||||
systemd.services = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
nameValuePair ("typo3-cron-" + domain) {
|
||||
script = ''
|
||||
set -eu
|
||||
${instanceOpts.phpPackage}/bin/php /var/www/${domain}/.Build/bin/typo3 scheduler:run
|
||||
${instanceOpts.phpPackage}/bin/php /var/www/${domain}/.Build/bin/typo3 ke_search:indexing
|
||||
'';
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = user;
|
||||
};
|
||||
}
|
||||
) cfg.instances;
|
||||
|
||||
services.phpfpm.pools = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
nameValuePair domain {
|
||||
user = user;
|
||||
settings = {
|
||||
"listen.owner" = config.services.nginx.user;
|
||||
"pm" = "dynamic";
|
||||
"pm.max_children" = 32;
|
||||
"pm.max_requests" = 500;
|
||||
"pm.start_servers" = 2;
|
||||
"pm.min_spare_servers" = 2;
|
||||
"pm.max_spare_servers" = 5;
|
||||
"php_admin_value[error_log]" = "syslog";
|
||||
"php_admin_value[max_execution_time]" = 240;
|
||||
"php_admin_value[max_input_vars]" = 1500;
|
||||
"php_admin_value[upload_max_filesize]" = "256M";
|
||||
"php_admin_value[post_max_size]" = "256M";
|
||||
"access.log" = "/var/log/$pool.access.log";
|
||||
};
|
||||
phpOptions = ''
|
||||
opcache.enable=1
|
||||
opcache.memory_consumption=128
|
||||
opcache.validate_timestamps=0
|
||||
opcache.revalidate_path=0
|
||||
'';
|
||||
phpPackage = instanceOpts.phpPackage;
|
||||
phpEnv."PATH" = pkgs.lib.makeBinPath [ instanceOpts.phpPackage ];
|
||||
}
|
||||
) cfg.instances;
|
||||
|
||||
};
|
||||
|
||||
|
||||
config.services.nginx.virtualHosts = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
nameValuePair domain {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
root = cfg.dataDir + "/" + domain + "/public";
|
||||
serverAliases = instanceOpts.domainAliases;
|
||||
|
||||
locations."/favicon.ico".extraConfig = ''
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
'';
|
||||
|
||||
extraConfig = ''
|
||||
if (!-e $request_filename) {
|
||||
rewrite ^/(.+)\.(\d+)\.(php|js|css|png|jpg|gif|gzip)$ /$1.$3 last;
|
||||
}
|
||||
'';
|
||||
|
||||
# TYPO3 - Block access to composer files
|
||||
locations."~* composer\\.(?:json|lock)".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
|
||||
# TYPO3 - Block access to flexform files
|
||||
locations."~* flexform[^.]*\\.xml".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
# TYPO3 - Block access to language files
|
||||
locations."~* locallang[^.]*\\.(?:xml|xlf)$".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
# TYPO3 - Block access to static typoscript files
|
||||
locations."~* ext_conf_template\\.txt|ext_typoscript_constants\\.txt|ext_typoscript_setup\\.txt".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
# TYPO3 - Block access to miscellaneous protected files
|
||||
locations."~* /.*\\.(?:bak|co?nf|cfg|ya?ml|ts|typoscript|tsconfig|dist|fla|in[ci]|log|sh|sql|sqlite)$".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
# locations."~* /.*\.(?:bak|cfg|co?nf|ya?ml|ts)$".extraConfig = ''
|
||||
# deny all;
|
||||
# '';
|
||||
|
||||
# TYPO3 - Block access to recycler and temporary directories
|
||||
locations."~ _(?:recycler|temp)_/".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
# TYPO3 - Block access to configuration files stored in fileadmin
|
||||
locations."~ fileadmin/(?:templates)/.*\\.(?:txt|ts|typoscript)$".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
|
||||
# TYPO3 - Block access to libraries, source and temporary compiled data
|
||||
locations."~ ^(?:vendor|typo3_src|typo3temp/var)".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
|
||||
# TYPO3 - Block access to protected extension directories
|
||||
locations."~ (?:typo3conf/ext|typo3/sysext|typo3/ext)/[^/]+/(?:Configuration|Resources/Private|Tests?|Documentation|docs?)/".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
|
||||
# Cache.appcache, your document html and data
|
||||
locations."~* \\.(?:manifest|appcache|html?|xml|json)$".extraConfig = ''
|
||||
expires -1;
|
||||
# access_log logs/static.log; # I don't usually include a static log
|
||||
'';
|
||||
|
||||
# Cache Media: images, icons, video, audio, HTC
|
||||
locations."~* \\.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|woff2)$".extraConfig = ''
|
||||
expires 1y;
|
||||
access_log off;
|
||||
add_header Cache-Control "public";
|
||||
'';
|
||||
|
||||
# Feed
|
||||
locations."~* \\.(?:rss|atom)$".extraConfig = ''
|
||||
expires 1h;
|
||||
add_header Cache-Control "public";
|
||||
'';
|
||||
|
||||
# Cache CSS, Javascript, Images, Icons, Video, Audio, HTC, Fonts
|
||||
locations."~* \\.(?:css|js|jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|woff2)$".extraConfig = ''
|
||||
expires 1y;
|
||||
access_log off;
|
||||
add_header Cache-Control "public";
|
||||
'';
|
||||
|
||||
locations."/".extraConfig = ''
|
||||
index index.php index.html;
|
||||
try_files $uri $uri/ /index.php$is_args$args;
|
||||
'';
|
||||
|
||||
# TYPO3 Backend URLs
|
||||
locations."/typo3$".extraConfig = ''
|
||||
rewrite ^ /typo3/;
|
||||
'';
|
||||
|
||||
locations."/typo3/".extraConfig = ''
|
||||
try_files $uri /typo3/index.php$is_args$args;
|
||||
'';
|
||||
|
||||
locations."~ [^/]\\.php(/|$)".extraConfig = ''
|
||||
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
|
||||
if (!-f $document_root$fastcgi_script_name) {
|
||||
return 404;
|
||||
}
|
||||
include ${pkgs.nginx}/conf/fastcgi_params;
|
||||
include ${pkgs.nginx}/conf/fastcgi.conf;
|
||||
fastcgi_buffer_size 32k;
|
||||
fastcgi_buffers 8 16k;
|
||||
fastcgi_connect_timeout 240s;
|
||||
fastcgi_read_timeout 240s;
|
||||
fastcgi_send_timeout 240s;
|
||||
fastcgi_pass unix:${config.services.phpfpm.pools."${domain}".socket};
|
||||
fastcgi_index index.php;
|
||||
'';
|
||||
}
|
||||
) cfg.instances;
|
||||
|
||||
config.users.users = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
nameValuePair user {
|
||||
isNormalUser = true;
|
||||
createHome = true;
|
||||
home = "/var/www/" + domain;
|
||||
homeMode= "770";
|
||||
group = config.services.nginx.group;
|
||||
openssh.authorizedKeys.keys = instanceOpts.authorizedKeys;
|
||||
}
|
||||
) cfg.instances;
|
||||
config.users.groups = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in nameValuePair user {}) cfg.instances;
|
||||
|
||||
config.services.mysql.ensureUsers = mapAttrsToList (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
{
|
||||
name = user;
|
||||
ensurePermissions = {
|
||||
"${user}.*" = "ALL PRIVILEGES";
|
||||
};
|
||||
}) cfg.instances;
|
||||
|
||||
config.services.mysql.ensureDatabases = mapAttrsToList (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
user
|
||||
) cfg.instances;
|
||||
config.services.mysqlBackup.databases = mapAttrsToList (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
user
|
||||
) cfg.instances;
|
||||
}
|
||||
38
utils/modules/snapclient.nix
Normal file
38
utils/modules/snapclient.nix
Normal file
@@ -0,0 +1,38 @@
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
|
||||
# security.rtkit.enable = true;
|
||||
# services.pipewire = {
|
||||
# enable = true;
|
||||
# alsa.enable = true;
|
||||
# alsa.support32Bit = true;
|
||||
# pulse.enable = true;
|
||||
#
|
||||
# };
|
||||
sound.enable = true;
|
||||
hardware.pulseaudio.enable = true;
|
||||
hardware.pulseaudio.support32Bit = true;
|
||||
services.getty.autologinUser = "snapclient";
|
||||
|
||||
users.groups.snapclient = {};
|
||||
users.users.snapclient = {
|
||||
isNormalUser = true;
|
||||
group = "snapclient";
|
||||
extraGroups = [ "audio" "pipewire" ];
|
||||
};
|
||||
|
||||
systemd.user.services.snapclient = {
|
||||
wantedBy = [
|
||||
"default.target"
|
||||
];
|
||||
after = [
|
||||
"network.target"
|
||||
];
|
||||
serviceConfig = {
|
||||
# User = "snapclient";
|
||||
# Group = "snapclient";
|
||||
ExecStart = "${pkgs.snapcast}/bin/snapclient -h mopidy.cloonar.com -p 1704 --player pulse";
|
||||
Restart = "on-failure";
|
||||
};
|
||||
};
|
||||
}
|
||||
80
utils/modules/snapserver.nix
Normal file
80
utils/modules/snapserver.nix
Normal file
@@ -0,0 +1,80 @@
|
||||
{ pkgs, config, python3Packages, ... }:
|
||||
let
|
||||
shairport-sync = pkgs.shairport-sync.overrideAttrs (_: {
|
||||
configureFlags = [
|
||||
"--with-alsa" "--with-pipe" "--with-pa" "--with-stdout"
|
||||
"--with-avahi" "--with-ssl=openssl" "--with-soxr"
|
||||
"--without-configfiles"
|
||||
"--sysconfdir=/etc"
|
||||
"--with-metadata"
|
||||
];
|
||||
});
|
||||
in
|
||||
{
|
||||
services.snapserver = {
|
||||
enable = true;
|
||||
codec = "flac";
|
||||
http.docRoot = "${pkgs.snapcast}/share/snapserver/snapweb";
|
||||
streams.mopidy = {
|
||||
type = "pipe";
|
||||
location = "/run/snapserver/mopidy";
|
||||
};
|
||||
streams.airplay = {
|
||||
type = "airplay";
|
||||
location = "${shairport-sync}/bin/shairport-sync";
|
||||
query = {
|
||||
devicename = "Multi Room";
|
||||
port = "5000";
|
||||
params = "--mdns=avahi";
|
||||
};
|
||||
};
|
||||
streams.mixed = {
|
||||
type = "meta";
|
||||
location = "/airplay/mopidy";
|
||||
};
|
||||
};
|
||||
|
||||
services.avahi.enable = true;
|
||||
services.avahi.publish.enable = true;
|
||||
services.avahi.publish.userServices = true;
|
||||
|
||||
# services.shairport-sync = {
|
||||
# enable = true;
|
||||
# arguments = "-v -o=pipe -- pipe:name=/run/snapserver/airplay";
|
||||
# };
|
||||
|
||||
services.nginx.virtualHosts."snapcast.cloonar.com" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
extraConfig = ''
|
||||
proxy_buffering off;
|
||||
'';
|
||||
locations."/".extraConfig = ''
|
||||
proxy_pass http://127.0.0.1:1780;
|
||||
proxy_set_header Host $host;
|
||||
proxy_redirect http:// https://;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
80 # http
|
||||
443 # https
|
||||
1704 # snapcast
|
||||
1705 # snapcast
|
||||
5000 # airplay
|
||||
5353 # airplay
|
||||
];
|
||||
networking.firewall.allowedUDPPorts = [
|
||||
5000 # airplay
|
||||
5353 # airplay
|
||||
];
|
||||
networking.firewall.allowedUDPPortRanges = [
|
||||
{ from = 6001; to = 6011; } # airplay
|
||||
];
|
||||
}
|
||||
6
utils/modules/sops.nix
Normal file
6
utils/modules/sops.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
imports = [
|
||||
"${builtins.fetchTarball "https://github.com/Mic92/sops-nix/archive/master.tar.gz"}/modules/sops"
|
||||
];
|
||||
|
||||
}
|
||||
7
utils/modules/sway/directory-studio-nix
Normal file
7
utils/modules/sway/directory-studio-nix
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
environment.systemPackages = [
|
||||
pkgs.apache-directory-studio
|
||||
];
|
||||
}
|
||||
17
utils/modules/sway/parsec.nix
Normal file
17
utils/modules/sway/parsec.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
unstable = import (fetchTarball https://nixos.org/channels/nixos-unstable/nixexprs.tar.xz) {
|
||||
config = { allowUnfree = true; };
|
||||
};
|
||||
parsecDesktopItem = pkgs.makeDesktopItem {
|
||||
name = "parsec";
|
||||
desktopName = "Parsec Gaming";
|
||||
exec = "parsecd";
|
||||
};
|
||||
in {
|
||||
environment.systemPackages = with pkgs; [
|
||||
unstable.parsec-bin
|
||||
parsecDesktopItem
|
||||
];
|
||||
}
|
||||
17
utils/modules/sway/signal-work.nix
Normal file
17
utils/modules/sway/signal-work.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
signalWorkDesktopItem = pkgs.makeDesktopItem {
|
||||
name = "signal-work";
|
||||
desktopName = "Signal with work profile";
|
||||
icon = "signal-desktop";
|
||||
exec = "signal-desktop --user-data-dir=/home/dominik/.config/Signal-work -- %u";
|
||||
};
|
||||
in {
|
||||
environment.systemPackages = [
|
||||
pkgs.signal-desktop
|
||||
pkgs.signal-cli
|
||||
signalWorkDesktopItem
|
||||
];
|
||||
}
|
||||
12
utils/modules/sway/social.nix
Normal file
12
utils/modules/sway/social.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
socialDesktopItem = pkgs.makeDesktopItem {
|
||||
name = "social";
|
||||
desktopName = "Firefox browser with social profile";
|
||||
exec = "firefox -P social";
|
||||
};
|
||||
in {
|
||||
environment.systemPackages = [ socialDesktopItem ];
|
||||
}
|
||||
350
utils/modules/sway/sway.conf
Normal file
350
utils/modules/sway/sway.conf
Normal file
@@ -0,0 +1,350 @@
|
||||
# Oxide theme
|
||||
#
|
||||
# Author: Diki Ananta <diki1aap@gmail.com> Repository: https://github.com/dikiaap/dotfiles
|
||||
# License: MIT
|
||||
# i3 config file (v4)
|
||||
|
||||
# font for window titles and bar
|
||||
font pango:Source Sans Pro 10
|
||||
|
||||
# use win key
|
||||
set $mod Mod4
|
||||
|
||||
# use these keys for focus, movement, and resize directions
|
||||
set $left h
|
||||
set $down j
|
||||
set $up k
|
||||
set $right l
|
||||
|
||||
# define names for workspaces
|
||||
set $ws1 "1: "
|
||||
set $ws2 "2: "
|
||||
set $ws3 "3: "
|
||||
set $ws4 "4: "
|
||||
set $ws5 "5: "
|
||||
set $ws6 "6: "
|
||||
set $ws7 "7: "
|
||||
set $ws8 "8: "
|
||||
set $ws9 "9: "
|
||||
set $ws10 "10: "
|
||||
|
||||
# assign workspaces to primary monitor
|
||||
workspace $ws1 output primary
|
||||
workspace $ws2 output primary
|
||||
workspace $ws3 output primary
|
||||
workspace $ws4 output primary
|
||||
workspace $ws5 output primary
|
||||
workspace $ws6 output primary
|
||||
workspace $ws7 output primary
|
||||
workspace $ws8 output primary
|
||||
workspace $ws9 output primary
|
||||
|
||||
# use $mod+Mouse to drag floating windows to their wanted position
|
||||
floating_modifier $mod
|
||||
|
||||
# control focused window when follows the mouse movements
|
||||
focus_follows_mouse no
|
||||
|
||||
# window border settings
|
||||
default_border none
|
||||
default_floating_border none
|
||||
|
||||
# hiding borders adjacent to the screen edges
|
||||
hide_edge_borders none
|
||||
|
||||
# set popups during fullscreen mode
|
||||
popup_during_fullscreen smart
|
||||
|
||||
# start a terminal
|
||||
#bindsym $mod+Return workspace $ws1; exec --no-startup-id alacritty
|
||||
bindsym $mod+Return workspace $ws1; exec alacritty -t alacritty-sway
|
||||
|
||||
# start a program launcher
|
||||
# bindsym $mod+d exec --no-startup-id wofi -s /etc/wofi/style.css --show drun --lines 5 --columns 1 -t alacritty
|
||||
bindsym $mod+d exec alacritty --class=launcher -e env TERMINAL_COMMAND="alacritty -e" sway-launcher-desktop
|
||||
#bindsym $mod+d exec --no-startup-id bemenu
|
||||
#bindsym $mod+d exec --no-startup-id i3-dmenu-desktop --dmenu="dmenu -i -fn 'Source Sans Pro-10' -nb '#212121' -sb '#2b83a6' -sf '#ffffff'
|
||||
#bindsym $mod+d exec --no-startup-id bemenu --dmenu="dmenu -i -fn 'Source Sans Pro-10' -nb '#212121' -sb '#2b83a6' -sf '#ffffff'
|
||||
|
||||
# start an explorer
|
||||
bindsym $mod+e exec --no-startup-id pcmanfm
|
||||
|
||||
# switching window with win+tab
|
||||
bindsym $mod+Tab exec --no-startup-id wofi -show window
|
||||
|
||||
# kill focused window
|
||||
bindsym $mod+Shift+q kill
|
||||
|
||||
# change keyboard layout
|
||||
bindsym $mod+i swaymsg input "*" us
|
||||
bindsym $mod+Shift+i swaymsg input "*" de
|
||||
|
||||
# change focus
|
||||
bindsym $mod+$left focus left
|
||||
bindsym $mod+$down focus down
|
||||
bindsym $mod+$up focus up
|
||||
bindsym $mod+$right focus right
|
||||
|
||||
# alternatively, you can use the cursor keys:
|
||||
bindsym $mod+Left focus left
|
||||
bindsym $mod+Down focus down
|
||||
bindsym $mod+Up focus up
|
||||
bindsym $mod+Right focus right
|
||||
|
||||
# move focused window
|
||||
bindsym $mod+Shift+$left move left
|
||||
bindsym $mod+Shift+$down move down
|
||||
bindsym $mod+Shift+$up move up
|
||||
bindsym $mod+Shift+$right move right
|
||||
|
||||
# alternatively, you can use the cursor keys:
|
||||
bindsym $mod+Shift+Left move left
|
||||
bindsym $mod+Shift+Down move down
|
||||
bindsym $mod+Shift+Up move up
|
||||
bindsym $mod+Shift+Right move right
|
||||
|
||||
# split in horizontal orientation
|
||||
bindsym $mod+c split h
|
||||
|
||||
# split in vertical orientation
|
||||
bindsym $mod+v split v
|
||||
|
||||
# enter fullscreen mode for the focused container
|
||||
bindsym $mod+f fullscreen toggle
|
||||
|
||||
# change container layout
|
||||
bindsym $mod+s layout stacking
|
||||
bindsym $mod+w layout tabbed
|
||||
bindsym $mod+p layout toggle split
|
||||
|
||||
# toggle tiling / floating
|
||||
# bindsym $mod+Shift+space floating toggle
|
||||
|
||||
# change focus between tiling / floating windows
|
||||
# bindsym $mod+space focus mode_toggle
|
||||
|
||||
# focus the parent container
|
||||
bindsym $mod+a focus parent
|
||||
|
||||
# focus the child container
|
||||
bindsym $mod+Shift+a focus child
|
||||
|
||||
# move the currently focused window to the scratchpad
|
||||
bindsym $mod+Shift+minus move scratchpad
|
||||
|
||||
# show the next scratchpad window or hide the focused scratchpad window
|
||||
bindsym $mod+minus scratchpad show
|
||||
|
||||
# move focused floating window to the current position of the cursor
|
||||
bindsym $mod+Shift+m move position mouse
|
||||
|
||||
# set a window to stick to the glass
|
||||
bindsym $mod+Shift+s sticky toggle
|
||||
|
||||
# sticky preview for media
|
||||
bindsym $mod+Shift+p fullscreen disable; floating enable; resize set 350 px 197 px; sticky enable; move window to position 1006 px 537 px
|
||||
|
||||
# shortcut to change window border
|
||||
bindsym $mod+t border normal 0
|
||||
bindsym $mod+y border pixel 1
|
||||
bindsym $mod+u border none
|
||||
|
||||
# switch to workspace
|
||||
|
||||
bindcode $mod+10 workspace $ws1
|
||||
bindcode $mod+11 workspace $ws2
|
||||
bindcode $mod+12 workspace $ws3
|
||||
bindcode $mod+13 workspace $ws4
|
||||
bindcode $mod+14 workspace $ws5
|
||||
bindcode $mod+15 workspace $ws6
|
||||
bindcode $mod+16 workspace $ws7
|
||||
bindcode $mod+17 workspace $ws8
|
||||
bindcode $mod+18 workspace $ws9
|
||||
bindcode $mod+19 workspace $ws10
|
||||
|
||||
# move focused container to workspace
|
||||
bindcode $mod+Shift+10 move container to workspace $ws1
|
||||
bindcode $mod+Shift+11 move container to workspace $ws2
|
||||
bindcode $mod+Shift+12 move container to workspace $ws3
|
||||
bindcode $mod+Shift+13 move container to workspace $ws4
|
||||
bindcode $mod+Shift+14 move container to workspace $ws5
|
||||
bindcode $mod+Shift+15 move container to workspace $ws6
|
||||
bindcode $mod+Shift+16 move container to workspace $ws7
|
||||
bindcode $mod+Shift+17 move container to workspace $ws8
|
||||
bindcode $mod+Shift+18 move container to workspace $ws9
|
||||
bindcode $mod+Shift+19 move container to workspace $ws10
|
||||
|
||||
# shortcut applications
|
||||
bindsym $mod+F1 exec gkamus
|
||||
bindsym $mod+F2 workspace $ws2; exec subl
|
||||
bindsym $mod+F3 workspace $ws3; exec chromium-browser
|
||||
bindsym $mod+F4 workspace $ws4; exec pcmanfm
|
||||
bindsym $mod+F5 workspace $ws5; exec evince
|
||||
bindsym $mod+F6 workspace $ws6; exec audacious
|
||||
bindsym $mod+F7 workspace $ws7; exec gcolor2
|
||||
bindsym $mod+F8 workspace $ws8; exec telegram
|
||||
bindsym $mod+F9 workspace $ws9; exec go-for-it
|
||||
bindsym Print exec --no-startup-id gnome-screenshot
|
||||
bindcode $mod+9 exec swaylock --image ~/.wallpaper.jpg
|
||||
bindsym Ctrl+Shift+Space exec 1password --quick-access
|
||||
bindsym $mod+Space exec rofi-rbw --menu-keybindings ctrl+p:copy:password
|
||||
|
||||
# volume
|
||||
bindsym XF86AudioLowerVolume exec amixer -q sset Master 5%- unmute
|
||||
bindsym XF86AudioRaiseVolume exec amixer -q sset Master 5%+ unmute
|
||||
bindsym XF86AudioMute exec amixer -q sset Master toggle
|
||||
|
||||
# touchpad
|
||||
# bindsym XF86NotificationCenter exec swaymsg input type:touchpad events toggle enabled disabled
|
||||
|
||||
# set brightness logarithmically by factor 1.4
|
||||
# .72 is just slightly bigger than 1 / 1.4
|
||||
bindsym --locked XF86MonBrightnessUp exec light -S "$(light -G | awk '{ print int(($1 + .72) * 1.4) }')"
|
||||
bindsym --locked XF86MonBrightnessDown exec light -S "$(light -G | awk '{ print int($1 / 1.4) }')"
|
||||
|
||||
# reload the configuration file
|
||||
bindsym $mod+Shift+c reload
|
||||
|
||||
# restart i3 inplace
|
||||
bindsym $mod+Shift+r restart
|
||||
|
||||
# manage i3 session
|
||||
bindsym $mod+Shift+e exec swaynag --background f1fa8c --border ffb86c --border-bottom-size 0 --button-background ffb86c --button-text 282a36 -t warning -f "pango:Hack 9" -m "Do you really want to exit?" -B " Exit " "swaymsg exit" -B " Lock " "pkill swaynag && swaylock --image ~/.wallpaper.jpg" -B " Reboot " "pkill swaynag && reboot" -B " Shutdown " "pkill swaynag && shutdown -h now" -B " Suspend " "pkill swaynag && systemctl suspend"
|
||||
|
||||
# resize window
|
||||
bindsym $mod+r mode " "
|
||||
mode " " {
|
||||
# pressing left and up will shrink the window's width and height
|
||||
# pressing right and down will grow the window's width and height
|
||||
bindsym $left resize shrink width 10 px or 10 ppt
|
||||
bindsym $down resize grow height 10 px or 10 ppt
|
||||
bindsym $up resize shrink height 10 px or 10 ppt
|
||||
bindsym $right resize grow width 10 px or 10 ppt
|
||||
|
||||
# same bindings, but for the arrow keys
|
||||
bindsym Left resize shrink width 10 px or 10 ppt
|
||||
bindsym Down resize grow height 10 px or 10 ppt
|
||||
bindsym Up resize shrink height 10 px or 10 ppt
|
||||
bindsym Right resize grow width 10 px or 10 ppt
|
||||
|
||||
# back to normal: Enter or win+r
|
||||
bindsym Return mode "default"
|
||||
bindsym $mod+r mode "default"
|
||||
}
|
||||
|
||||
# set specific windows to floating mode
|
||||
for_window [window_role="app"] floating enable
|
||||
#for_window [window_role="pop-up"] floating enable
|
||||
for_window [window_role="task_dialog"] floating enable
|
||||
for_window [title="Preferences$"] floating enable
|
||||
for_window [class="Gkamus"] floating enable
|
||||
for_window [class="Go-for-it"] floating enable
|
||||
for_window [class="Lightdm-gtk-greeter-settings"] floating enable
|
||||
for_window [class="Lxappearance"] floating enable
|
||||
for_window [class="Menu"] floating enable
|
||||
for_window [class="Nm-connection-editor"] floating enable
|
||||
for_window [class="Software-properties-gtk"] floating enable
|
||||
for_window [app_id="launcher"] floating enable
|
||||
|
||||
# set specific windows to tabbed mode
|
||||
#for_window [class="Rambox"]tabbed
|
||||
#for_window [class="Signal"]tabbed
|
||||
|
||||
# assign program to workspace
|
||||
assign [title="alacritty-sway"] → $ws1
|
||||
assign [app_id="Alacritty" title="^(?!alacritty-sway)$"] → $ws2
|
||||
assign [app_id="chromium"] → $ws3
|
||||
assign [app_id="firefox"] → $ws3
|
||||
assign [app_id="pcmanfm"] → $ws4
|
||||
assign [app_id="libreoffice-calc"] → $ws5
|
||||
assign [app_id="libreoffice-writer"] → $ws5
|
||||
assign [class="vlc"] → $ws6
|
||||
assign [class="Gimp"] → $ws7
|
||||
assign [class="Signal"] → $ws8
|
||||
assign [app_id="social"] → $ws8
|
||||
assign [app_id="thunderbird"] → $ws8
|
||||
assign [class="Lightdm-gtk-greeter-settings"] → $ws10
|
||||
assign [class="Software-properties-gtk"] → $ws10
|
||||
|
||||
# class border backgr. text indicator child_border
|
||||
client.focused #2b83a6 #2b83a6 #ffffff #dddddd #2b83a6
|
||||
client.focused_inactive #212121 #212121 #86888c #292d2e #5a5a5a
|
||||
client.unfocused #212121 #212121 #86888c #292d2e #5a5a5a
|
||||
client.urgent #d64e4e #d64e4e #ffffff #d64e4e #d64e4e
|
||||
client.placeholder #212121 #0c0c0c #ffffff #212121 #262626
|
||||
client.background #212121
|
||||
|
||||
bar {
|
||||
swaybar_command waybar
|
||||
}
|
||||
|
||||
# gaps
|
||||
smart_gaps on
|
||||
gaps inner 12
|
||||
gaps outer 0
|
||||
|
||||
# startup applications
|
||||
exec /run/wrappers/bin/gnome-keyring-daemon --start --daemonize
|
||||
exec dbus-sway-environment
|
||||
exec configure-gtk
|
||||
exec nm-applet --indicator
|
||||
exec alacritty -t alacritty-sway
|
||||
exec signal-desktop
|
||||
exec firefox --name=social -P social
|
||||
exec thunderbird
|
||||
exec firefox
|
||||
exec nextcloud
|
||||
exec owncloud
|
||||
exec swayidle \
|
||||
before-sleep 'loginctl lock-session $XDG_SESSION_ID' \
|
||||
lock 'swaylock --image ~/.wallpaper.jpg' \
|
||||
timeout 180 'swaylock --screenshots --effect-blur 7x5' \
|
||||
timeout 1800 'systemctl suspend'
|
||||
exec dunst
|
||||
#exec --no-startup-id swaybg -c "#000000" -m fill -i ~/.config/wallpaper/wot.jpg
|
||||
# exec --no-startup-id gnome-keyring-daemon --start --components=pkcs11,secrets,ssh
|
||||
exec 'sleep 2; swaymsg workspace $ws8; swaymsg layout tabbed'
|
||||
|
||||
# wallpaper
|
||||
output eDP-1 bg ~/.wallpaper.jpg fill
|
||||
output DP-4 bg ~/.wallpaper.jpg fill
|
||||
output DP-5 bg ~/.wallpaper.jpg fill
|
||||
|
||||
input * xkb_layout "de"
|
||||
input * xkb_variant "colemak,,typewriter"
|
||||
input * xkb_options "grp:win_space_toggle"
|
||||
input "MANUFACTURER1 Keyboard" xkb_model "pc101"
|
||||
|
||||
# notebook
|
||||
set $laptop eDP-1
|
||||
# bindswitch --reload --locked lid:on output $laptop disable
|
||||
# bindswitch --reload lid:off output $laptop enable
|
||||
|
||||
# A lock command used in several places
|
||||
set $lock_script swaylock
|
||||
|
||||
# A sleep command used in several places.
|
||||
# We leave a bit of time for locking to happen before putting the system to sleep
|
||||
set $sleep $lock_script && sleep 3 && systemctl suspend
|
||||
|
||||
# Triggers a short notification
|
||||
set $notify dunstify --timeout 1500
|
||||
|
||||
# Set your laptop screen name
|
||||
set $laptop_screen 'eDP-1'
|
||||
|
||||
# Clamshell mode or lock & sleep
|
||||
# This is a if/else statement: [ outputs_count == 1 ] && true || false
|
||||
#bindswitch --reload --locked lid:on exec '[ $(swaymsg -t get_outputs | grep name | wc -l) == 1 ] && ($sleep) || ($notify "Clamshell mode" "Laptop screen off" && swaymsg output $laptop_screen disable)'
|
||||
|
||||
#bindswitch --reload --locked lid:off output $laptop_screen enable
|
||||
|
||||
# disable xwayland
|
||||
#xwayland disable
|
||||
|
||||
# Touchpad
|
||||
input type:touchpad {
|
||||
tap enabled
|
||||
natural_scroll enabled
|
||||
}
|
||||
|
||||
137
utils/modules/sway/sway.nix
Normal file
137
utils/modules/sway/sway.nix
Normal file
@@ -0,0 +1,137 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
dbus-sway-environment = pkgs.writeTextFile {
|
||||
name = "dbus-sway-environment";
|
||||
destination = "/bin/dbus-sway-environment";
|
||||
executable = true;
|
||||
|
||||
text = ''
|
||||
dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP=sway
|
||||
systemctl --user stop pipewire pipewire-media-session xdg-desktop-portal xdg-desktop-portal-wlr
|
||||
systemctl --user start pipewire pipewire-media-session xdg-desktop-portal xdg-desktop-portal-wlr
|
||||
'';
|
||||
};
|
||||
|
||||
in {
|
||||
imports = [
|
||||
./social.nix
|
||||
./signal-work.nix
|
||||
./thunderbird.nix
|
||||
./parsec.nix
|
||||
];
|
||||
|
||||
hardware.pulseaudio.enable = false;
|
||||
|
||||
services.xserver = {
|
||||
enable = true;
|
||||
excludePackages = [ pkgs.xterm ];
|
||||
displayManager.gdm.enable = true;
|
||||
displayManager.gdm.wayland = true;
|
||||
# displayManager.sddm.enable = true;
|
||||
displayManager.sessionPackages = [ pkgs.sway ];
|
||||
displayManager.defaultSession = "sway";
|
||||
libinput.enable = true;
|
||||
desktopManager.gnome = {
|
||||
enable = true;
|
||||
extraGSettingsOverrides = ''
|
||||
[org.gnome.desktop.interface]
|
||||
gtk-theme='Dracula'
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
services.teamviewer.enable = true;
|
||||
services.gnome.gnome-keyring.enable = true;
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
alsaUtils
|
||||
alacritty
|
||||
bitwarden
|
||||
chromium
|
||||
cryptomator
|
||||
dbeaver
|
||||
dbus-sway-environment
|
||||
dracula-theme
|
||||
gcc
|
||||
git
|
||||
glib
|
||||
gimp
|
||||
gnome.seahorse
|
||||
gnome3.adwaita-icon-theme
|
||||
grim
|
||||
jmeter
|
||||
libreoffice
|
||||
mako
|
||||
networkmanagerapplet
|
||||
nextcloud-client
|
||||
obs-studio
|
||||
pavucontrol
|
||||
pcmanfm
|
||||
pinentry
|
||||
rbw
|
||||
rofi-rbw
|
||||
rustdesk
|
||||
slurp
|
||||
sway
|
||||
sway-launcher-desktop
|
||||
swayidle
|
||||
swaylock
|
||||
# thunderbird
|
||||
tor-browser-bundle-bin
|
||||
unzip
|
||||
vlc
|
||||
waybar
|
||||
wayland
|
||||
wl-clipboard
|
||||
wofi
|
||||
wtype
|
||||
apache-directory-studio
|
||||
firefox
|
||||
|
||||
|
||||
onlyoffice-bin
|
||||
# kexi
|
||||
];
|
||||
|
||||
# nixpkgs.config.permittedInsecurePackages = [
|
||||
# "qtwebkit-5.212.0-alpha4"
|
||||
# "electron-13.6.9"
|
||||
# ];
|
||||
# nixpkgs.config.allowBroken = true;
|
||||
|
||||
programs._1password-gui = {
|
||||
enable = true;
|
||||
polkitPolicyOwners = [ "dominik" ];
|
||||
};
|
||||
|
||||
programs.light.enable = true;
|
||||
|
||||
fonts.fonts = with pkgs; [
|
||||
noto-fonts
|
||||
noto-fonts-cjk
|
||||
noto-fonts-emoji
|
||||
nerdfonts
|
||||
];
|
||||
|
||||
security.rtkit.enable = true;
|
||||
services.pipewire = {
|
||||
enable = true;
|
||||
alsa.enable = true;
|
||||
alsa.support32Bit = true;
|
||||
pulse.enable = true;
|
||||
jack.enable = true;
|
||||
};
|
||||
|
||||
programs.sway = {
|
||||
enable = true;
|
||||
wrapperFeatures.gtk = true;
|
||||
};
|
||||
|
||||
environment.etc = {
|
||||
"sway/config".source = "/etc/nixos/modules/sway/sway.conf";
|
||||
"wofi/style.css".source = "/etc/nixos/modules/sway/wofi.css";
|
||||
"xdg/waybar/config".source = "/etc/nixos/modules/sway/waybar.conf";
|
||||
"xdg/waybar/style.css".source = "/etc/nixos/modules/sway/waybar.css";
|
||||
};
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user