diff --git a/config/hosts/athame/configuration.nix b/config/hosts/athame/configuration.nix index a32a5eeb..c2f297ab 100644 --- a/config/hosts/athame/configuration.nix +++ b/config/hosts/athame/configuration.nix @@ -3,26 +3,22 @@ { imports = [ ./hardware.nix - # db + # host-specific services ./postgres.nix - # nginx - ../../services/nginx.nix ./virtualhosts.nix - # security ./fail2ban.nix - # services - ./mail.nix - ./asterisk.nix - ./gitea.nix - ./syncplay.nix - ./nextcloud.nix - ./bitwarden.nix - ./taskserver.nix - # comms - ./murmur.nix - ./znc.nix - ./weechat.nix - ./matrix.nix + # services + ../../services/nginx.nix + ../../services/mail.nix + ../../services/asterisk.nix + ../../services/gitea.nix + ../../services/syncplay.nix + ../../services/bitwarden.nix + ../../services/taskserver.nix + ../../services/murmur.nix + ../../services/znc.nix + ../../services/weechat.nix + ../../services/matrix.nix ]; deploy.profiles = [ "kat" ]; diff --git a/config/hosts/boline/configuration.nix b/config/hosts/boline/configuration.nix index 9249c4c8..45ab91be 100644 --- a/config/hosts/boline/configuration.nix +++ b/config/hosts/boline/configuration.nix @@ -4,7 +4,6 @@ imports = [ ./hardware.nix ../../services/nginx.nix - #./wireguard.nix ]; deploy.profiles = [ "kat" ]; diff --git a/config/hosts/samhain/vm/default.nix b/config/hosts/samhain/vm/default.nix index 9c92658e..ce74221d 100644 --- a/config/hosts/samhain/vm/default.nix +++ b/config/hosts/samhain/vm/default.nix @@ -59,6 +59,7 @@ pkgs.arc.pkgs.scream-arc # for audio forwarding pkgs.screenstub # for input handling pkgs.ddcutil # for diagnostics on DDC/CI + pkgs.virt-manager # hmm ]; systemd.services.libvirtd-guest-win10 = { diff --git a/config/services/asterisk.nix b/config/services/asterisk.nix new file mode 100644 index 00000000..638b65ff --- /dev/null +++ b/config/services/asterisk.nix @@ -0,0 +1,201 @@ +{ config, pkgs, witch, ... }: + +{ + services.asterisk = { + enable = true; + confFiles = { + "rtp.conf" = '' + [general] + rtpstart=10000 + rtpend=20000 + ''; + "extensions.conf" = '' + [from-twilio] + exten => _.,1,Dial(SIP/1337,20) + + [from-signalwire] + exten => s,1,Set(numb=''${CUT(CUT(PJSIP_HEADER(read,To),@,1),:,2)}) + same => n,Dial(SIP/1337,20) + + [from-internal] + exten => _1X.,1,Set(CALLERID(all)="kat" <+${witch.secrets.hosts.athame.phone.number.us}>) + same => n,Dial(PJSIP/''${EXTEN:1}@signalwire) + same => n(end),Hangup() + exten => _2X.,1,Set(CALLERID(all)="kat" <+${witch.secrets.hosts.athame.phone.number.canada}>) + same => n,Dial(PJSIP/''${EXTEN:1}@signalwire) + same => n(end),Hangup() + exten => _3X.,1,Set(CALLERID(all)="kat" <+${witch.secrets.hosts.athame.phone.number.uk}>) + same => n,Dial(PJSIP/+''${EXTEN:1}@twilio-ie) + same => n(end),Hangup() + ''; + "pjproject.conf" = '' + ; Common pjproject options + ; + + ;========================LOG_MAPPINGS SECTION OPTIONS=============================== + ;[log_mappings] + ; SYNOPSIS: Provides pjproject to Asterisk log level mappings. + ; NOTES: The name of this section in the pjproject.conf configuration file must + ; remain log_mappings or the configuration will not be applied. + ; The defaults mentioned below only apply if this file or the 'log_mappings' + ; object can'tbe found. If the object is found, there are no defaults. If + ; you don't specify an entry, nothing will be logged for that level. + ; + ;asterisk_error = ; A comma separated list of pjproject log levels to map to + ; Asterisk errors. + ; (default: "0,1") + ;asterisk_warning = ; A comma separated list of pjproject log levels to map to + ; Asterisk warnings. + ; (default: "2") + ;asterisk_notice = ; A comma separated list of pjproject log levels to map to + ; Asterisk notices. + ; (default: "") + ;asterisk_verbose = ; A comma separated list of pjproject log levels to map to + ; Asterisk verbose. + ; (default: "") + ;asterisk_debug = ; A comma separated list of pjproject log levels to map to + ; Asterisk debug + ; (default: "3,4,5") + ;type= ; Must be of type log_mappings (default: "") + + ''; + "sip.conf" = '' + [general] + ;; Only uncomment this if you want to connect to a different SIP server and receive calls from it + context=public + allowguest=no + udpbindaddr=0.0.0.0:5160 + tcpbindaddr=0.0.0.0:5160 + tcpenable=yes + transport=udp,tcp + disallow=all + allow=speex32 + allow=g722 + allow=ulaw + allow=alaw + allow=gsm + allow=g726 + + [1337] + type=friend + context=from-internal + host=dynamic + secret=${witch.secrets.hosts.athame.phone.password} + nat=force_rport,comedia + ''; + "pjsip_wizard.conf" = '' + [user_defaults](!) + type = wizard + accepts_registrations = yes + sends_registrations = no + accepts_auth = yes + sends_auth = no + endpoint/context = from-internal + endpoint/tos_audio=ef + endpoint/tos_video=af41 + endpoint/cos_audio=5 + endpoint/cos_video=4 + endpoint/allow = !all,ulaw + endpoint/dtmf_mode= rfc4733 + endpoint/aggregate_mwi = yes + endpoint/use_avpf = no + endpoint/rtcp_mux = no + endpoint/bundle = no + endpoint/ice_support = no + endpoint/media_use_received_transport = no + endpoint/trust_id_inbound = yes + endpoint/media_encryption = no + endpoint/timers = yes + endpoint/media_encryption_optimistic = no + endpoint/send_pai = yes + endpoint/rtp_symmetric = yes + endpoint/rewrite_contact = yes + endpoint/force_rport = yes + endpoint/language = en + + [trunk_defaults](!) + type = wizard + endpoint/transport=0.0.0.0-udp + endpoint/allow = !all,ulaw + endpoint/t38_udptl=no + endpoint/t38_udptl_ec=none + endpoint/fax_detect=no + endpoint/trust_id_inbound=no + endpoint/t38_udptl_nat=no + endpoint/direct_media=no + endpoint/rewrite_contact=yes + endpoint/rtp_symmetric=yes + endpoint/dtmf_mode=rfc4733 + endpoint/allow_subscribe = no + aor/qualify_frequency = 60 + + [twilio-ie](trunk_defaults) + sends_auth = yes + sends_registrations = no + remote_hosts = kat-asterisk.pstn.dublin.twilio.com + outbound_auth/username = asterisk + outbound_auth/password = ${witch.secrets.hosts.athame.phone.endpoint.password.twilio} + endpoint/context = from-twilio + aor/qualify_frequency = 60 + ''; + "pjsip.conf" = '' + [global] + type=global + + [0.0.0.0-udp] + type=transport + protocol=udp + bind=0.0.0.0:5060 + allow_reload=no + tos=cs3 + cos=3 + + [signalwire] + type=auth + auth_type=userpass + username=asterisk ; Your username + password=${witch.secrets.hosts.athame.phone.endpoint.password.signalwire} + + [signalwire] + type=aor + contact=sip:${witch.secrets.hosts.athame.phone.endpoint.url} + + [signalwire] + type=endpoint + transport=transport-udp + outbound_auth=signalwire ; Note that there is only an outbound_auth, as we do not challenge when a call arrives inbound + aors=signalwire + disallow=all + allow=speex32 + allow=g722 + allow=ulaw + allow=alaw + allow=gsm + allow=g726 + from_user=asterisk + from_domain=${witch.secrets.hosts.athame.phone.endpoint.url} + media_encryption=sdes ; Note that we are using encryption + context=from-signalwire + + [signalwire] + type=registration + server_uri=sip:${witch.secrets.hosts.athame.phone.endpoint.url} + client_uri=sip:asterisk@${witch.secrets.hosts.athame.phone.endpoint.url}; Your full SIP URI + outbound_auth=signalwire + + [signalwire] + type=identify + endpoint=signalwire + match=${witch.secrets.hosts.athame.phone.endpoint.url} + ''; + "logger.conf" = '' + [general] + dateformat=%F %T + [logfiles] + ; Add debug output to log + messages => security, notice,warning,error + syslog.local0 => notice,warning,error,debug + ''; + }; + }; +} diff --git a/config/services/bitwarden.nix b/config/services/bitwarden.nix new file mode 100644 index 00000000..4e40f948 --- /dev/null +++ b/config/services/bitwarden.nix @@ -0,0 +1,24 @@ +{ config, pkgs, witch, ... }: + +{ + services.bitwarden_rs = { + enable = true; + config = { + rocketPort = 4000; + websocketEnabled = true; + signupsAllowed = false; + adminToken = witch.secrets.hosts.athame.bitwarden_secret; + domain = "https://vault.kittywit.ch"; + }; + }; + + services.nginx.virtualHosts."vault.kittywit.ch" = { + enableACME = true; + forceSSL = true; + locations = { + "/".proxyPass = "http://127.0.0.1:4000"; + "/notifications/hub".proxyPass = "http://127.0.0.1:3012"; + "/notifications/hub/negotiate".proxyPass = "http://127.0.0.1:80"; + }; + }; +} diff --git a/config/services/gitea.nix b/config/services/gitea.nix new file mode 100644 index 00000000..90ed5956 --- /dev/null +++ b/config/services/gitea.nix @@ -0,0 +1,17 @@ +{ config, pkgs, ... }: + +{ + services.gitea = { + enable = true; + disableRegistration = true; + domain = "git.kittywit.ch"; + rootUrl = "https://git.kittywit.ch"; + httpAddress = "127.0.0.1"; + }; + + services.nginx.virtualHosts."git.kittywit.ch" = { + enableACME = true; + forceSSL = true; + locations = { "/".proxyPass = "http://127.0.0.1:3000"; }; + }; +} diff --git a/config/services/mail.nix b/config/services/mail.nix new file mode 100644 index 00000000..4f868f69 --- /dev/null +++ b/config/services/mail.nix @@ -0,0 +1,49 @@ +{ config, pkgs, witch, sources, ... }: + +{ + imports = [ sources.nixos-mailserver.outPath ]; + + mailserver = { + enable = true; + fqdn = "kittywit.ch"; + domains = [ "kittywit.ch" ]; + + # A list of all login accounts. To create the password hashes, use + # nix run nixpkgs.apacheHttpd -c htpasswd -nbB "" "super secret password" | cut -d: -f2 + loginAccounts = { + "kat@kittywit.ch" = { + hashedPasswordFile = config.secrets.files.kat-pw-hash.path; + + aliases = [ "postmaster@kittywit.ch" ]; + + # Make this user the catchAll address for domains kittywit.ch and + # example2.com + catchAll = [ "kittywit.ch" ]; + }; + }; + + # Extra virtual aliases. These are email addresses that are forwarded to + # loginAccounts addresses. + extraVirtualAliases = { + # address = forward address; + "abuse@kittywit.ch" = "kat@kittywit.ch"; + }; + + # Use Let's Encrypt certificates. Note that this needs to set up a stripped + # down nginx and opens port 80. + certificateScheme = 3; + + # Enable IMAP and POP3 + enableImap = true; + enablePop3 = true; + enableImapSsl = true; + enablePop3Ssl = true; + + # Enable the ManageSieve protocol + enableManageSieve = true; + + # whether to scan inbound emails for viruses (note that this requires at least + # 1 Gb RAM for the server. Without virus scanning 256 MB RAM should be plenty) + virusScanning = false; + }; +} diff --git a/config/services/matrix.nix b/config/services/matrix.nix new file mode 100644 index 00000000..99190c18 --- /dev/null +++ b/config/services/matrix.nix @@ -0,0 +1,119 @@ +{ config, pkgs, witch, ... }: + +{ + environment.systemPackages = + [ pkgs.arc.pkgs.mx-puppet-discord pkgs.mautrix-whatsapp ]; + + services.matrix-synapse = { + enable = true; + registration_shared_secret = witch.secrets.hosts.athame.matrix_secret; + max_upload_size = "512M"; + server_name = "kittywit.ch"; + app_service_config_files = [ + "/var/lib/matrix-synapse/telegram-registration.yaml" + "/var/lib/matrix-synapse/discord-registration.yaml" + "/var/lib/matrix-synapse/whatsapp-registration.yaml" + ]; + listeners = [{ + port = 8008; + bind_address = "::1"; + type = "http"; + tls = false; + x_forwarded = true; + resources = [{ + names = [ "client" "federation" ]; + compress = false; + }]; + }]; + }; + + services.mautrix-telegram = { + enable = true; + settings = { + homeserver = { + address = "http://localhost:8008"; + domain = "kittywit.ch"; + }; + appservice = { + provisioning.enabled = false; + id = "telegram"; + public = { + enabled = false; + prefix = "/public"; + external = "https://kittywit.ch/public"; + }; + }; + bridge = { + relaybot.authless_portals = false; + permissions = { "@kat:kittywit.ch" = "admin"; }; + }; + }; + environmentFile = "/etc/secrets/mautrix-telegram.env"; + }; + + systemd.services.mx-puppet-discord = { + serviceConfig = { + Type = "simple"; + Restart = "always"; + ExecStart = + "${pkgs.arc.pkgs.mx-puppet-discord}/bin/mx-puppet-discord -c /var/lib/mx-puppet-discord/config.yaml -f /var/lib/mx-puppet-discord/discord-registration.yaml"; + WorkingDirectory = "/var/lib/mx-puppet-discord"; + DynamicUser = true; + StateDirectory = "mx-puppet-discord"; + UMask = 27; + PrivateTmp = true; + ProtectSystem = "strict"; + ProtectHome = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + }; + requisite = [ "matrix-synapse.service" ]; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + }; + + systemd.services.mautrix-whatsapp = { + serviceConfig = { + Type = "simple"; + Restart = "always"; + ExecStart = + "${pkgs.mautrix-whatsapp}/bin/mautrix-whatsapp -c /var/lib/mautrix-whatsapp/config.yaml -r /var/lib/mautrix-whatsapp/registration.yaml"; + WorkingDirectory = "/var/lib/mautrix-whatsapp"; + DynamicUser = true; + StateDirectory = "mautrix-whatsapp"; + UMask = 27; + PrivateTmp = true; + ProtectSystem = "strict"; + ProtectHome = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + }; + requisite = [ "matrix-synapse.service" ]; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + }; + + services.nginx.virtualHosts."kittywit.ch" = { + locations = { + "/_matrix" = { proxyPass = "http://[::1]:8008"; }; + "= /.well-known/matrix/server".extraConfig = + let server = { "m.server" = "kittywit.ch:443"; }; + in '' + add_header Content-Type application/json; + return 200 '${builtins.toJSON server}'; + ''; + "= /.well-known/matrix/client".extraConfig = let + client = { + "m.homeserver" = { "base_url" = "https://kittywit.ch"; }; + "m.identity_server" = { "base_url" = "https://vector.im"; }; + }; + in '' + add_header Content-Type application/json; + add_header Access-Control-Allow-Origin *; + return 200 '${builtins.toJSON client}'; + ''; + }; + }; +} diff --git a/config/services/murmur.nix b/config/services/murmur.nix new file mode 100644 index 00000000..46b2b849 --- /dev/null +++ b/config/services/murmur.nix @@ -0,0 +1,18 @@ +{ config, pkgs, ... }: + +{ + security.acme = { certs."kittywit.ch" = { group = "kittywit-ch"; }; }; + + users.groups."kittywit-ch".members = [ "murmur" "nginx" "syncplay" ]; + + services.murmur = { + enable = true; + + hostName = "kittywit.ch"; + + extraConfig = '' + sslCert=/var/lib/acme/kittywit.ch/fullchain.pem + sslKey=/var/lib/acme/kittywit.ch/key.pem + ''; + }; +} diff --git a/config/services/syncplay.nix b/config/services/syncplay.nix new file mode 100644 index 00000000..d9919110 --- /dev/null +++ b/config/services/syncplay.nix @@ -0,0 +1,12 @@ +{ config, pkgs, ... }: + +{ + users.users.syncplay = { isSystemUser = true; }; + + services.syncplay = { + enable = true; + user = "syncplay"; + group = "kittywit-ch"; + certDir = "/var/lib/acme/kittywit.ch/"; + }; +} diff --git a/config/services/syncserver.nix b/config/services/syncserver.nix new file mode 100644 index 00000000..d4647110 --- /dev/null +++ b/config/services/syncserver.nix @@ -0,0 +1,16 @@ +{ config, pkgs, ... }: + +{ + services.firefox.syncserver = { + enable = true; + listen.port = 5001; + allowNewUsers = false; + publicUrl = "https://sync.kittywit.ch"; + }; + + services.nginx.virtualHosts."sync.kittywit.ch" = { + enableACME = true; + forceSSL = true; + locations = { "/".proxyPass = "http://127.0.0.1:5001"; }; + }; +} diff --git a/config/services/taskserver.nix b/config/services/taskserver.nix new file mode 100644 index 00000000..f5a3889d --- /dev/null +++ b/config/services/taskserver.nix @@ -0,0 +1,8 @@ +{ config, lib, ... }: + +{ + services.taskserver.enable = true; + services.taskserver.fqdn = "kittywit.ch"; + services.taskserver.listenHost = "::"; + services.taskserver.organisations.kittywitch.users = [ "kat" ]; +} diff --git a/config/services/weechat.nix b/config/services/weechat.nix new file mode 100644 index 00000000..b37f7861 --- /dev/null +++ b/config/services/weechat.nix @@ -0,0 +1,39 @@ +{ config, pkgs, ... }: + +let + sources = import ../../../../nix/sources.nix; + unstable = import sources.nixpkgs-unstable { inherit (pkgs) config; }; +in { + services.weechat = { + binary = let + new-weechat = pkgs.arc.pkgs.wrapWeechat pkgs.arc.pkgs.weechat-unwrapped { + configure = { availablePlugins, ... }: { + scripts = [ pkgs.arc.pkgs.weechatScripts.weechat-matrix ]; + plugins = [ + availablePlugins.perl + (availablePlugins.python.withPackages + (ps: [ ps.potr ps.weechat-matrix ])) + ]; + }; + }; + in "${new-weechat}/bin/weechat"; + enable = true; + }; + + programs.screen.screenrc = '' + multiuser on + acladd kat + ''; + + services.nginx.virtualHosts."irc.kittywit.ch" = { + enableACME = true; + forceSSL = true; + locations = { + "/" = { root = pkgs.glowing-bear; }; + "^~ /weechat" = { + proxyPass = "http://127.0.0.1:9000"; + proxyWebsockets = true; + }; + }; + }; +} diff --git a/config/services/znc.nix b/config/services/znc.nix new file mode 100644 index 00000000..518b4406 --- /dev/null +++ b/config/services/znc.nix @@ -0,0 +1,25 @@ +{ config, pkgs, witch, ... }: + +{ + services.znc = { + enable = true; + mutable = false; + useLegacyConfig = false; + openFirewall = false; + config = { + Listener.l = { + Port = 5000; + SSL = false; + AllowWeb = true; + }; + modules = [ "webadmin" "adminlog" ]; + User = witch.secrets.hosts.athame.znc; + }; + }; + + services.nginx.virtualHosts."znc.kittywit.ch" = { + enableACME = true; + forceSSL = true; + locations = { "/".proxyPass = "http://127.0.0.1:5000"; }; + }; +}