{ config, lib, pkgs, ... }: with lib; let domaine = "nyanlout.re"; sendMail = to: subject: message: pkgs.writeShellScriptBin "mail.sh" '' ${pkgs.system-sendmail}/bin/sendmail ${to} < { }; in { imports = [ ../../services/python-ci.nix ../../services/sdtdserver.nix # ../../containers/vsftpd.nix # /mnt/secrets/factorio_secrets.nix ./monitoring.nix ./medias.nix ./web.nix ]; security.acme.certs = { "${domaine}" = { extraDomainNames = [ "mail.${domaine}" ]; postRun = '' systemctl reload dovecot2.service ''; }; }; mailserver = { enable = true; fqdn = "mail.${domaine}"; domains = [ domaine ]; # A list of all login accounts. To create the password hashes, use # mkpasswd -m sha-512 "super secret password" loginAccounts = { "paul@${domaine}" = { hashedPassword = "$6$8wWQbtqVqUoH8$pQKg0bZPcjCbuPvyhjJ1lQy949M/AgfmAye/hDEIVUnCfwtlUxC1yj8CBHpNKeiiXhd8IUqk9r0/IJNvB6okf0"; }; "claire@${domaine}" = { hashedPassword = "$6$Y.vlWP9./DX$NEQQOLzYftbHOvXDkKdBYFAjzIjh8mlpomDuQRq6qkkZijrdy/p6jSbrpBLhoWwVmj4j1OWekHU1f4C9xCNJk."; }; }; # Certificate setup certificateScheme = 1; certificateFile = "/var/lib/acme/${domaine}/fullchain.pem"; keyFile = "/var/lib/acme/${domaine}/key.pem"; # Enable IMAP and POP3 enableImap = true; enablePop3 = true; enableImapSsl = true; enablePop3Ssl = true; # Enable the ManageSieve protocol enableManageSieve = true; }; services = { postfix = { relayHost = "mailvps.nyanlout.re"; relayPort = 587; config = { smtp_tls_cert_file = lib.mkForce "/var/lib/postfix/postfixrelay.crt"; smtp_tls_key_file = lib.mkForce "/var/lib/postfix/postfixrelay.key"; }; }; rspamd.workers.controller.extraConfig = '' secure_ip = ["127.0.0.1", "10.30.135.71"]; ''; redis.enable = true; logrotate = { enable = true; paths = { nginx = { path = "/var/log/nginx/*.log"; user = config.services.nginx.user; group = config.services.nginx.group; keep = 7; extraConfig = '' compress ''; }; }; }; fail2ban.enable = true; fstrim.enable = true; syncthing = { enable = true; dataDir = "/var/lib/syncthing"; openDefaultPorts = true; }; nfs.server = { enable = true; exports = '' /mnt/medias 10.30.0.0/16(ro,no_root_squash) /var/lib/minecraft 10.30.0.0/16(rw,no_root_squash) ''; statdPort = 4000; lockdPort = 4001; mountdPort = 4002; }; matrix-synapse = { enable = true; enable_registration = true; server_name = "nyanlout.re"; listeners = [ { # federation bind_address = ""; port = 8448; resources = [ { compress = true; names = [ "client" "webclient" ]; } { compress = false; names = [ "federation" ]; } ]; tls = true; type = "http"; x_forwarded = false; } { # client bind_address = "127.0.0.1"; port = 8008; resources = [ { compress = true; names = [ "client" "webclient" ]; } ]; tls = false; type = "http"; x_forwarded = true; } ]; max_upload_size = "100M"; database_type = "psycopg2"; database_args = { database = "matrix-synapse"; }; tls_private_key_path = "/var/lib/acme/${domaine}/key.pem"; tls_certificate_path = "/var/lib/acme/${domaine}/fullchain.pem"; url_preview_enabled = true; logConfig = '' version: 1 formatters: journal_fmt: format: '%(name)s: [%(request)s] %(message)s' filters: context: (): synapse.util.logcontext.LoggingContextFilter request: "" handlers: journal: class: systemd.journal.JournalHandler formatter: journal_fmt filters: [context] SYSLOG_IDENTIFIER: synapse root: level: WARNING handlers: [journal] disable_existing_loggers: False ''; app_service_config_files = [ "/var/lib/matrix-synapse/mautrix-telegram-registration.yaml" ]; }; mautrix-telegram = { enable = true; settings = { homeserver = { address = "https://matrix.nyanlout.re"; domain = "nyanlout.re"; }; appservice = { bot_username = "loutrebot"; }; bridge = { relaybot.authless_portals = false; permissions = { "@nyanloutre:nyanlout.re" = "admin"; }; }; }; environmentFile = "/mnt/secrets/mautrix-telegram.env"; serviceDependencies = [ "matrix-synapse.service" ]; }; borgbackup.jobs = { loutre = { paths = [ "/var/certs" "/var/dkim" "/var/lib/jellyfin" "/var/lib/gitea" "/var/lib/grafana" "/var/lib/jackett" "/var/lib/matrix-synapse" "/var/lib/postgresql/.zfs/snapshot/borgsnap" "/var/lib/radarr" "/var/lib/sonarr" "/var/lib/transmission" "/mnt/medias/musique" "/mnt/medias/torrent/lidarr" "/mnt/medias/torrent/musique" "/mnt/paul-home/paul" "/var/sieve" "/var/vmail" ]; exclude = [ "/var/lib/radarr/.config/Radarr/radarr.db-wal" "/var/lib/radarr/.config/Radarr/radarr.db-shm" ]; repo = "/mnt/backup/borg"; encryption = { mode = "repokey-blake2"; passCommand = "cat /mnt/secrets/borgbackup_loutre_encryption_pass"; }; startAt = "weekly"; prune.keep = { within = "1d"; weekly = 4; monthly = 12; }; preHook = "${pkgs.zfs}/bin/zfs snapshot loutrepool/var/postgresql@borgsnap"; readWritePaths = [ "/var/lib/postfix/queue/maildrop" ]; postHook = '' ${pkgs.zfs}/bin/zfs destroy loutrepool/var/postgresql@borgsnap if [[ $exitStatus == 0 ]]; then ${pkgs.rclone}/bin/rclone --config /mnt/secrets/rclone_loutre.conf sync -v $BORG_REPO BackupStorage:default else ${backup_mail_alert}/bin/mail.sh fi ''; }; }; borgbackup.repos = { diskstation = { authorizedKeys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDllbxON66dBju7sMnhX8/E0VRo3+PDYvDsHP0/FK+h8JHol4+pouLmI7KIDKYOJmSuom283OqnyZOMqk+RShTwWIFm9hOd2R9aj45Zrd9jPW2APOCec/Epgogj0bwBnc0l2v6qxkxaBMgL5DnAQ+E00uvL1UQpK8c8j4GGiPlkWJD6Kf+pxmnfH1TIm+J2XCwl0oeCkSK/Frd8eM+wCraMSzoaGiEcfMz2jK8hxDWjDxX7epU0ELF22BVCuyN8cYRoFTnV88E38PlaqsOqD5ePkxk425gDh7j/C06f8QKgnasVH2diixo92kYSd7i/RmfeXDDwAD5xqUvODczEuIdt root@DiskStation" ]; path = "/mnt/backup_loutre/diskstation_borg"; user = "synology"; }; }; sdtdserver.enable = false; factorio = { enable = false; autosave-interval = 10; game-name = "Shame"; public = true; username = "nyanloutre"; }; minecraft-server = { enable = false; jvmOpts = "-Xms512m -Xmx3072m"; eula = true; declarative = true; openFirewall = true; whitelist = { nyanloutre = "db0669ea-e332-4ca3-8d50-f5d1458f5822"; Hautension = "f05677f4-be5a-47df-ad77-21c739180aa2"; LordDarkKiwi = "79290cfc-0b00-484f-9c94-ab0786402de6"; Madahin = "f5f747e3-fac2-43e8-9b9b-a67dc2f368ff"; Hopegcx = "4497f759-2210-48db-8764-307d33011442"; wyrd68 = "127a3021-cdc1-419f-9010-4651df9ae3af"; sparsyateloutre = "d2ff63c1-4e9f-4b21-9bfc-decce5d987b3"; }; serverProperties = { difficulty = 2; gamemode = 0; max-players = 50; motd = "Hi Mark !"; white-list = true; }; }; kresd = { enable = true; }; home-assistant = { enable = true; config = { homeassistant = { elevation = 143; }; influxdb = null; config = null; frontend.themes = "!include ${pkgs.fetchurl { url = "https://raw.githubusercontent.com/bbbenji/synthwave-hass/0.3.3.1/themes/synthwave.yaml"; sha256 = "1n2yhk98cf778z7fdl5bswljhj45nv6bld191rxw7q6ckp235q4h"; }}"; history = null; logbook = null; map = null; mobile_app = null; person = null; script = null; sun = null; system_health = null; yeelight.devices = { "10.40.249.0".name = "Chambre"; "10.40.249.1".name = "Bureau"; "10.40.249.2".name = "Cuisine"; }; zha = null; esphome = null; light = [ { platform = "group"; name = "Salon"; entities = [ "light.bureau" "light.cuisine" ]; } ]; media_player = [ { platform = "squeezebox"; host = "10.30.0.1"; } ]; tplink.switch = [ { host = "10.30.50.7"; } ]; sensor = [ { platform = "template"; sensors = { serveur_amps = { friendly_name_template = "{{ states.switch.serveur.name}} Current"; value_template = ''{{ states.switch.serveur.attributes["current_a"] | float }}''; unit_of_measurement = "A"; }; serveur_watts = { friendly_name_template = "{{ states.switch.serveur.name}} Current Consumption"; value_template = ''{{ states.switch.serveur.attributes["current_power_w"] | float }}''; unit_of_measurement = "W"; }; serveur_total_kwh = { friendly_name_template = "{{ states.switch.serveur.name}} Total Consumption"; value_template = ''{{ states.switch.serveur.attributes["total_energy_kwh"] | float }}''; unit_of_measurement = "kWh"; }; serveur_volts = { friendly_name_template = "{{ states.switch.serveur.name}} Voltage"; value_template = ''{{ states.switch.serveur.attributes["voltage"] | float }}''; unit_of_measurement = "V"; }; serveur_today_kwh = { friendly_name_template = "{{ states.switch.serveur.name}} Today's Consumption"; value_template = ''{{ states.switch.serveur.attributes["today_energy_kwh"] | float }}''; unit_of_measurement = "kWh"; }; }; } ]; switch = [ { platform = "wake_on_lan"; name = "PC Fixe"; mac = "b4:2e:99:ed:24:26"; host = "10.30.135.71"; broadcast_address = "10.30.255.255"; } ]; device_tracker = [ { platform = "ping"; hosts = { telephone_paul = "10.30.50.2"; }; } ]; scene = [ { name = "Movie"; icon = "mdi:movie-open"; entities = { "light.salon" = { state = "on"; xy_color = [0.299 0.115]; brightness = 50; }; "light.bande_led_tv" = { state = "on"; effect = "Movie"; brightness = 180; }; "light.bande_led_bureau" = { state = "on"; xy_color = [0.299 0.115]; brightness = 130; }; }; } { name = "Home"; icon = "mdi:home"; entities = { "light.salon" = { state = "on"; kelvin = 2700; brightness = 255; }; }; } { name = "Night"; icon = "mdi:weather-night"; entities = { "light.salon" = { state = "off"; }; "light.bande_led_tv" = { state = "off"; }; "light.bande_led_bureau" = { state = "off"; }; "light.chambre" = { state = "on"; kelvin = 1900; brightness = 50; }; }; } ]; automation = let min_sun_elevation = 4; switch_chambre = { domain = "zha"; platform = "device"; device_id = "3329ecdcad244e5e8fc0f4b96d52ffe1"; }; switch_entree = { domain = "zha"; platform = "device"; device_id = "7cd814190ec543dba76a7aa7e7996c41"; }; remote = { domain = "zha"; platform = "device"; device_id = "d1230b76264e483388a8fdaad4f44143"; }; in [ # ENTREE { alias = "Aziz lumière"; trigger = [ { platform = "numeric_state"; entity_id = "sun.sun"; value_template = "{{ state.attributes.elevation }}"; below = min_sun_elevation; } ]; condition = [ { condition = "state"; entity_id = "person.paul"; state = "home"; } # Sun below max elevation { condition = "template"; value_template = "{{ state_attr('sun.sun', 'elevation') < ${toString min_sun_elevation} }}"; } ]; action = { scene = "scene.home"; }; } { alias = "Aziz lumière switch"; trigger = { type = "remote_button_short_press"; subtype = "turn_on"; } // switch_entree; action = { scene = "scene.home"; }; } { alias = "Adios"; trigger = [ { platform = "state"; entity_id = "person.paul"; to = "not_home"; } ({ type = "remote_button_short_press"; subtype = "turn_off"; } // switch_entree) ]; action = [ { service = "light.turn_off"; entity_id = "all"; } { service = "media_player.turn_off"; entity_id = "all"; } ]; } # REMOTE { alias = "Button toggle"; trigger = { type = "remote_button_short_press"; subtype = "turn_on"; } // remote; action = { choose = { conditions = { condition = "template"; value_template = '' {% set domain = 'light' %} {% set state = 'off' %} {{ states[domain] | count == states[domain] | selectattr('state','eq',state) | list | count }} ''; }; sequence = { scene = "scene.home"; }; }; default = { service = "light.turn_off"; entity_id = "all"; }; }; } { alias = "Button scene movie"; trigger = { type = "remote_button_short_press"; subtype = "right"; } // remote; action = { scene = "scene.movie"; }; } { alias = "Button scene home"; trigger = { type = "remote_button_short_press"; subtype = "left"; } // remote; action = { scene = "scene.home"; }; } { alias = "Button light up"; trigger = { type = "remote_button_short_press"; subtype = "dim_up"; } // remote; action = { service = "light.turn_on"; entity_id = "light.salon"; data = { brightness_step = 25; }; }; } { alias = "Button light down"; trigger = { type = "remote_button_short_press"; subtype = "dim_down"; } // remote; action = { service = "light.turn_on"; entity_id = "light.salon"; data = { brightness_step = -25; }; }; } # CHAMBRE { alias = "Button scene night"; trigger = { type = "remote_button_short_press"; subtype = "turn_on"; } // switch_chambre; action = { scene = "scene.night"; }; } { alias = "Button scene dodo"; trigger = { type = "remote_button_short_press"; subtype = "turn_off"; } // switch_chambre; action = { service = "light.turn_off"; entity_id = "all"; }; } { alias = "Button scene lumière chambre ON"; trigger = { type = "remote_button_long_press"; subtype = "dim_up"; } // switch_chambre; action = { service = "light.turn_on"; entity_id = "light.chambre"; }; } { alias = "Button scene lumière chambre OFF"; trigger = { type = "remote_button_long_press"; subtype = "dim_down"; } // switch_chambre; action = { service = "light.turn_off"; entity_id = "light.chambre"; }; } ]; }; }; }; systemd.services.dogetipbot-telegram = let dogetipbot-telegram = pkgs.callPackage (pkgs.fetchgit { url = "https://gitlab.com/nyanloutre/dogetipbot-telegram.git"; rev = "18c875a2e4b98221523818515a1eecb9c5aeb093"; sha256 = "0mhv00y1c2py425wxl13if6nlv97xk5k6flf772jj1yaxipjdmpn"; }) { inherit pkgs; }; in { after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; script = "${dogetipbot-telegram}/bin/dogetipbot-telegram --db-path $STATE_DIRECTORY/users.db"; enable = true; serviceConfig = { EnvironmentFile = "/mnt/secrets/dogetipbot-telegram_env"; DynamicUser = true; StateDirectory = "dogetipbot"; }; }; # systemd.services.minecraft-overviewer = # let # clientJar = pkgs.fetchurl { # url = "https://overviewer.org/textures/1.14"; # sha256 = "0fij9wac7vj6h0kd3mfhqpn0w9gl8pbs9vs9s085zajm0szpr44k"; # name = "client.jar"; # }; # configFile = pkgs.runCommand "overviewer-config" { CLIENT_JAR = clientJar; } '' # substitute ${./config-overviewer.py} $out \ # --subst-var CLIENT_JAR # ''; # in # { # script = '' # ${pkgs.minecraft-overviewer}/bin/overviewer.py --config ${configFile} # ${pkgs.minecraft-overviewer}/bin/overviewer.py --config ${configFile} --genpoi # rm /var/www/minecraft-overviewer/progress.json # ''; # serviceConfig = { # User = "nginx"; # Group = "nginx"; # }; # }; # systemd.timers.minecraft-overviewer = { # wantedBy = [ "multi-user.target" ]; # timerConfig = { # OnCalendar = "*-*-* 04:00:00"; # }; # }; # systemd.packages = with pkgs; [ # tgt # ]; # environment.etc."tgt/targets.conf".text = '' # # backing-store /dev/zvol/loutrepool/steam-lun # initiator-address 10.30.50.3 # # ''; users.groups.nginx.members = [ "matrix-synapse" ]; security.pam.services.sshd.text = pkgs.lib.mkDefault( pkgs.lib.mkAfter "session optional ${pkgs.pam}/lib/security/pam_exec.so seteuid ${login_mail_alert}/bin/mail_alert.sh" ); networking = { wireguard.interfaces = { wg0 = { ips = [ "192.168.20.1/24" ]; privateKeyFile = "/mnt/secrets/wireguard/wg0.privatekey"; listenPort = 51820; allowedIPsAsRoutes = true; peers = [ { allowedIPs = [ "192.168.20.2/32" ]; publicKey = "b/SXiqo+GPdNOc54lyEVeUBc6B5AbVMKh+g5EZPGzlE="; } ]; }; }; nat.internalInterfaces = [ "wg0" ]; nat.internalIPs = [ "192.168.20.0/24" ]; firewall.interfaces.eno2.allowedTCPPorts = [ 3260 ]; firewall.allowedTCPPorts = [ 8448 # Matrix federation 20 21 # FTP ]; firewall.allowedTCPPortRanges = [ { from = 64000; to = 65535; } # FTP ]; firewall.allowedUDPPorts = [ config.networking.wireguard.interfaces.wg0.listenPort ]; }; }