diff --git a/machines/helix.nix b/machines/helix.nix
new file mode 100644
index 00000000..88fe3172
--- /dev/null
+++ b/machines/helix.nix
@@ -0,0 +1,52 @@
+{ config, pkgs, ... }:
+{
+ imports =
+ [ # Include the results of the hardware scan.
+ ./hardware-configuration.nix
+ ./wireguard.nix
+ ./matrix.nix
+ ];
+
+ # Use the GRUB 2 boot loader.
+ boot.loader.grub.enable = true;
+ boot.loader.grub.version = 2;
+ boot.loader.grub.device = "/dev/vda"; # or "nodev" for efi only
+
+ networking.hostName = "helix"; # Define your hostname.
+
+ networking.useDHCP = false;
+ networking.interfaces.ens3.useDHCP = true;
+
+ # Configure network proxy if necessary
+ # networking.proxy.default = "http://user:password@proxy:port/";
+ # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
+
+ # Enable the OpenSSH daemon.
+ services.openssh.enable = true;
+ #services.openssh.passwordAuthentication = false;
+ services.openssh.permitRootLogin = "no";
+
+ # Open ports in the firewall.
+ # networking.firewall.allowedTCPPorts = [ ... ];
+ # networking.firewall.allowedUDPPorts = [ ... ];
+ # Or disable the firewall altogether.
+ # networking.firewall.enable = false;
+
+ # Define a user account. Don't forget to set a password with ‘passwd’.
+ users.users.anish = {
+ isNormalUser = true;
+ extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user
+ openssh.authorizedKeys.keys = [
+ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDM8kTdMGGmr6mv/zv+K9qVjhzqwivyyN5IV04R7/kcWKw1c6ZEzzqqmsnJ/hci6IIxZ/VEUzMhYz0iBCL0wJHHMxYoNCgISWePtDlVJdyrzm9OWjJNcRStZBW3XcY9dELJsCVcQ4LAVYE4vA+MdmbwM2FZgJhAH6qUzujpfNrj/YIVG7MTN6tbUd63uZF57F43c8WUjgRJx2o7Wl9bSe6v3PZ4fAgEO+wQPso+W+pEXLZ3hBNrHdybwdoGvG9tHlBDbLid11BxtpzmwR9CydDfpbyOXB2+tJkkNXhsHB22mN/2+vGWYhDKYPTFqbDW7McDfQChySyYDdZWmg5WHIGz anish@curve"
+ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCeWQsf9rbE+KBrWLkLkg1PMKx0jPfDP8xyv+XtddIQzAskRTN+JSSQp1GpoRgfQij7bx6f6DfjkwSQK5NWDQNQ+klGhcdEwEdptWUzpRAvKHMImjyIwFHmRKKEgcfH8+DSHVM93nRSQKrLezX4PzPkHF9f3TLxFdGeQDeY0J2oP2Oa97hRtuTJZW9BwUojyvDYUbg7F3fxf+pdFCvIAFaayiLkhOYdTXnjLt1Ks6NOhSzM78ZibHv4pFYI9r6dhflkFP/SzyLeSSm1aVAtxqE7vF5HnnORAg0byDsiOv/9RXxiDx7gkAAw3xENDSpp9TRj54M7iz1OSsRMhmD6orHjZFIRejlE4DIn+PBPm3PH+U5ILKTogE6n5MfPT28V0QdtHuqq3b5tSWiDcFpnjxbIUmEIo5hLzMR0tXZoNLQhBCSNfxjE8CYzpk7mHbvhSs2GPfG+NI1vvldbw2EF8beJFQHNYTqJw8y7p8RXpCwZqqpSitJX6v9DiYdLVG1hWvE= nix-on-droid@localhost"
+ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKN8/SH55DBiwVoSnTU8k2Pen+wmovL9QaMyehxGEsJJv/8fzwsswGalD4C/4O51LOvdu4UKkZW5hG02uVSK+58p3UV3pOPyoqsu/aDeIsWsqmTeTzUrBIWOlNzcDKnohLz2oGC5YO+wyTJ9Iteq6aGJDjErsW7sG3h5lXCs551EmJNNGhtBQaaoytMNnWqSdlVjDNCijurH7WUpp40U/RjEp532l4rX6eIIj3jBKEFbhZkFSSjqbj4xM4SyFt+Jmigb1RMjsQjmpfY1vDtM84RcYfpTUte/T5w2dkD5H6kccmWnwKSJpm9wXfx4E7lR9APdUGnau2U1+XxiD3ytGl anish@box" ];
+ };
+
+ # This value determines the NixOS release with which your system is to be
+ # compatible, in order to avoid breaking some software such as database
+ # servers. You should change this only after NixOS release notes say you
+ # should.
+ system.stateVersion = "19.09"; # Did you read the comment?
+
+}
+
diff --git a/matrix-slack.nix b/matrix-slack.nix
new file mode 100644
index 00000000..b3b071c2
--- /dev/null
+++ b/matrix-slack.nix
@@ -0,0 +1,153 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+ dataDir = "/var/lib/matrix-appservice-slack";
+ registrationFile = "${dataDir}/slack-registration.yaml";
+ #appDir = "${pkgs.matrix-appservice-slack}/${pkgs.matrix-appservice-slack.passthru.nodeAppDir}";
+ cfg = config.services.matrix-appservice-slack;
+ # TODO: switch to configGen.json once RFC42 is implemented
+ settingsFile = pkgs.writeText "matrix-appservice-slack-settings.json" (builtins.toJSON cfg.settings);
+
+in {
+ options = {
+ services.matrix-appservice-slack = {
+ enable = mkEnableOption "a bridge between Matrix and Slack";
+
+ settings = mkOption rec {
+ # TODO: switch to types.config.json as prescribed by RFC42 once it's implemented
+ type = types.attrs;
+ apply = recursiveUpdate default;
+ default = {
+ # empty values necessary for registration file generation
+ # actual values defined in environmentFile
+ auth = {
+ clientID = "";
+ botToken = "";
+ };
+ };
+ example = literalExample ''
+ {
+ bridge = {
+ domain = "public-domain.tld";
+ homeserverUrl = "http://public-domain.tld:8008";
+ };
+ }
+ '';
+ description = ''
+ config.yaml configuration as a Nix attribute set.
+
+
+
+ Configuration options should match those described in
+
+ config.sample.yaml.
+
+
+
+ and
+ should be set to match the public host name of the Matrix homeserver for webhooks and avatars to work.
+
+
+
+ Secret tokens should be specified using
+ instead of this world-readable attribute set.
+ '';
+ };
+
+ environmentFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ description = ''
+ File containing environment variables to be passed to the matrix-appservice-discord service,
+ in which secret tokens can be specified securely by defining values for
+ APPSERVICE_SLACK_AUTH_CLIENT_I_D and
+ APPSERVICE_SLACK_AUTH_BOT_TOKEN.
+ '';
+ };
+
+ url = mkOption {
+ type = types.str;
+ default = "http://localhost:${toString cfg.port}";
+ description = ''
+ The URL where the application service is listening for HS requests.
+ '';
+ };
+
+ port = mkOption {
+ type = types.port;
+ default = 9898; # from https://github.com/matrix-org/matrix-appservice-slack/blob/develop/config/config.sample.yaml#L70
+ description = ''
+ Port number on which the bridge should listen for internal communication with the Matrix homeserver.
+ '';
+ };
+
+ localpart = mkOption {
+ type = with types; nullOr str;
+ default = null;
+ description = ''
+ The user_id localpart to assign to the AS.
+ '';
+ };
+
+ serviceDependencies = mkOption {
+ type = with types; listOf str;
+ default = optional config.services.matrix-synapse.enable "matrix-synapse.service";
+ description = ''
+ List of Systemd services to require and wait for when starting the application service,
+ such as the Matrix homeserver if it's running on the same host.
+ '';
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ systemd.services.matrix-appservice-slack = {
+ description = "A bridge between Matrix and Slack.";
+
+ wantedBy = [ "multi-user.target" ];
+ wants = [ "network-online.target" ] ++ cfg.serviceDependencies;
+ after = [ "network-online.target" ] ++ cfg.serviceDependencies;
+
+ preStart = ''
+ if [ ! -f '${registrationFile}' ]; then
+ ${pkgs.matrix-appservice-slack}/bin/matrix-appservice-slack \
+ --generate-registration \
+ --url=${escapeShellArg cfg.url} \
+ ${optionalString (cfg.localpart != null) "--localpart=${escapeShellArg cfg.localpart}"} \
+ --config='${settingsFile}' \
+ --file='${registrationFile}'
+ fi
+ '';
+
+ serviceConfig = {
+ Type = "simple";
+ Restart = "always";
+
+ ProtectSystem = "strict";
+ ProtectHome = true;
+ ProtectKernelTunables = true;
+ ProtectKernelModules = true;
+ ProtectControlGroups = true;
+
+ DynamicUser = true;
+ PrivateTmp = true;
+ #WorkingDirectory = appDir;
+ StateDirectory = baseNameOf dataDir;
+ UMask = 0027;
+ EnvironmentFile = cfg.environmentFile;
+
+ ExecStart = ''
+ ${pkgs.matrix-appservice-slack}/bin/matrix-appservice-slack \
+ --file='${registrationFile}' \
+ --config='${settingsFile}' \
+ --port='${toString cfg.port}'
+ '';
+ };
+ };
+ };
+
+ meta.maintainers = with maintainers; [ chickensoupandrice ];
+}
+
diff --git a/matrix.nix b/matrix.nix
new file mode 100644
index 00000000..32330aac
--- /dev/null
+++ b/matrix.nix
@@ -0,0 +1,258 @@
+{ config, lib, pkgs, ... }:
+
+{
+ imports = [ ./matrix-slack.nix ./mautrix-whatsapp.nix ];
+ security.acme.email = "anish+acme@lakhwara.com";
+ security.acme.acceptTerms = true;
+ services.matrix-synapse = {
+ enable = true;
+ app_service_config_files = [
+ # # The registration file is automatically generated after starting the appservice for the first time.
+ # # cp /var/lib/matrix-appservice-discord/discord-registration.yaml /var/lib/matrix-synapse/
+ # # chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/discord-registration.yaml
+ # "/var/lib/matrix-synapse/discord-registration.yaml"
+ "/var/lib/matrix-synapse/telegram-registration.yaml"
+ "/var/lib/matrix-synapse/slack-registration.yaml"
+ "/var/lib/matrix-synapse/whatsapp-registration.yaml"
+ ];
+ server_name = "sealight.xyz";
+ registration_shared_secret = "hD9HQGTTDxp0mQsQ5JDsfudWMDiubmZENOgPchIvfBvUlPxlvQSvjoO4wn2L1seU";
+ enable_metrics = true;
+ enable_registration = true;
+ database_type = "psycopg2";
+ database_args = {
+ database = "matrix-synapse";
+ };
+ listeners = [
+ {
+ port = 8448;
+ tls = false;
+ resources = [
+ {
+ compress = true;
+ names = ["client" "federation"];
+ }
+ ];
+ }
+ ];
+ extraConfig = ''
+ max_upload_size: "50M"
+ '';
+ };
+
+ services.mautrix-telegram = {
+ enable = true;
+ environmentFile = /etc/secrets/telegram.env; # file containing the appservice and telegram tokens
+ # The appservice is pre-configured to use SQLite by default. It's also possible to use PostgreSQL.
+ settings = {
+ homeserver = {
+ address = "https://chat.sealight.xyz";
+ domain = "sealight.xyz";
+ };
+ appservice = {
+ provisioning.enabled = false;
+ id = "telegram";
+ public = {
+ enabled = false;
+ prefix = "/public";
+ external = "https://chat.sealight.xyz/public";
+ };
+ # The service uses SQLite by default, but it's also possible to use PostgreSQL instead:
+ #database = "postgresql:///mautrix-telegram?host=/run/postgresql";
+ };
+ bridge = {
+ relaybot.authless_portals = false;
+ permissions = {
+ "@aynish:sealight.xyz" = "admin";
+ };
+ };
+ };
+ };
+
+ services.mautrix-whatsapp = {
+ enable = true;
+ # The appservice is pre-configured to use SQLite by default. It's also possible to use PostgreSQL.
+ configOptions = {
+ homeserver = {
+ address = "https://chat.sealight.xyz";
+ domain = "sealight.xyz";
+ };
+ appservice = {
+ id = "whatsapp";
+ address = http://localhost:9897;
+ hostname = "0.0.0.0";
+ port = 9897;
+ database = {
+ type = "sqlite3";
+ uri = "/var/lib/mautrix-whatsapp/mautrix-whatsapp.db";
+ };
+ state_store_path = "/var/lib/mautrix-whatsapp/mx-state.json";
+ bot = {
+ username = "whatsappbot";
+ displayname = "WhatsApp bridge bot";
+ avatar = "mxc://maunium.net/NeXNQarUbrlYBiPCpprYsRqr";
+ };
+ as_token = "";
+ hs_token = "";
+ };
+ bridge = {
+ username_template = "whatsapp_{{.}}";
+ displayname_template = "{{if .Notify}}{{.Notify}}{{else}}{{.Jid}}{{end}} (WA)";
+ command_prefix = "!wa";
+ permissions = {
+ "@aynish:sealight.xyz" = 100;
+ };
+ };
+ logging = {
+ directory = "/var/lib/mautrix-whatsapp/logs";
+ file_name_format = "{{.Date}}-{{.Index}}.log";
+ file_date_format = "\"2006-01-02\"";
+ file_mode = 384;
+ timestamp_format = "Jan _2, 2006 15:04:05";
+ print_level = "debug";
+ };
+ metrics = {
+ enabled = true;
+ listen = "http://localhost:5070";
+ };
+ };
+ };
+
+ services.matrix-appservice-slack = {
+ enable = true;
+ #environmentFile = /etc/secrets/matrix-appservice-slack.env;
+ settings = {
+ homeserver = {
+ server_name = "sealight.xyz";
+ url = "https://chat.sealight.xyz";
+ };
+ db = {
+ engine = "postgres";
+ connectionString = "postgres://slackbridge_user:somethingverysecret@localhost/slack_bridge?sslmode=require";
+ };
+ matrix_admin_room = "!ikEWOHCcmoZtVzSmPF:sealight.xyz";
+ username_prefix = "slack_";
+ rtm = {
+ enable = true;
+ logging = "silent";
+ };
+ slack_hook_port = 9899;
+ enable_metrics = true;
+ puppeting = {
+ enabled = true;
+ onboard_users = true;
+ };
+ oauth2 = {
+ client_id = "2832868673.1609454840563";
+ client_secret = "079a7ca42b192e66a9ff32740a69cb9d";
+ redirect_prefix = "https://sealight.xyz/slackbridge/";
+ };
+ #team_sync = {
+ # T02QGRJKT = {
+ # users = {
+ # enabled = false;
+ # };
+ # channels = {
+ # enabled = true;
+ # alias_prefix = "qf_";
+ # };
+ # };
+ #};
+ };
+ };
+
+ services.postgresql = {
+ enable = true;
+ ## postgresql user and db name remains in the
+ ## service.matrix-synapse.database_args setting which
+ ## by default is matrix-synapse
+ initialScript = pkgs.writeText "synapse-init.sql" ''
+ CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD "Da0?H*9i{x?,]|'kq@iBwlIzu";
+ CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ '';
+ };
+
+ networking.firewall = {
+ enable = true;
+ allowedTCPPorts = [
+ 22 # SSH
+ 8448 # Matrix federation
+ 8008
+ 80
+ 443
+ 9899 # Matrix <-> Slack Bridge Puppeting
+ ];
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ element-web = super.element-web.override {
+ conf = {
+ default_server_config = {
+ "m.homeserver" = {
+ "base_url" = "https://chat.sealight.xyz";
+ "server_name" = "sealight.xyz";
+ };
+ "m.identity_server" = {
+ "base_url" = "https://vector.im";
+ };
+ };
+
+ ## jitsi will be setup later,
+ ## but we need to add to Riot configuration
+ #jitsi.preferredDomain = "jitsi.dangerousdemos.net";
+ };
+ };
+ })
+ ];
+
+ services.nginx = {
+ enable = true;
+ virtualHosts = {
+
+ "sealight.xyz" = {
+ forceSSL = true;
+ enableACME = true;
+ locations."/" = {
+ root = "/var/www/sealight.xyz";
+ };
+ locations."/_matrix" = {
+ proxyPass = "http://localhost:8448";
+ };
+ locations."/slackbridge" = {
+ proxyPass = "http://localhost:9899";
+ };
+ };
+ ## virtual host for Synapse
+ "chat.sealight.xyz" = {
+ forceSSL = true;
+ enableACME = true;
+ #useACMEHost = "sealight.xyz";
+ locations."/" = {
+ proxyPass = "http://localhost:8448";
+ };
+ };
+
+ ## virtual host for Riot/Web
+ "element.sealight.xyz" = {
+ forceSSL = true;
+ enableACME = true;
+ #useACMEHost = "sealight.xyz";
+
+ ## root points to the riot-web package content, also configured via Nix
+ locations."/" = {
+ root = pkgs.element-web;
+ };
+ };
+ };
+ ## other nginx specific best practices
+ recommendedGzipSettings = true;
+ recommendedOptimisation = true;
+ recommendedTlsSettings = true;
+ };
+
+ environment.systemPackages = with pkgs; [ matrix-appservice-slack ];
+}
diff --git a/mautrix-whatsapp.nix b/mautrix-whatsapp.nix
new file mode 100644
index 00000000..beaaa6f0
--- /dev/null
+++ b/mautrix-whatsapp.nix
@@ -0,0 +1,96 @@
+{ lib, config, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.mautrix-whatsapp;
+
+ configFile = pkgs.runCommand "mautrix-whatsapp" {
+ buildInputs = [ pkgs.mautrix-whatsapp pkgs.remarshal ];
+ preferLocalBuild = true;
+ } ''
+ mkdir -p $out
+ ${pkgs.remarshal}/bin/json2yaml -i ${pkgs.writeText "config.json" (builtins.toJSON cfg.configOptions)} \
+ -o $out/config.yaml
+
+ ${pkgs.mautrix-whatsapp}/bin/mautrix-whatsapp -c $out/config.yaml -g -r $out/registration.yaml
+ '';
+
+in
+{
+ options.services.mautrix-whatsapp = {
+ enable = mkEnableOption "Mautrix-whatsapp, a puppeting bridge between Matrix and WhatsApp.";
+
+ configOptions = mkOption {
+ type = types.attrs;
+ description = ''
+ This options will be transform in YAML configuration file for the bridge
+
+ Look here for documentation.
+ '';
+ example = {
+ configOptions = {
+ homeserver = {
+ address = https://matrix.org;
+ domain = "matrix.org";
+ };
+ appservice = {
+ address = http://localhost:8080;
+ hostname = "0.0.0.0";
+ port = 8080;
+ database = {
+ type = "sqlite3";
+ uri = "/var/lib/mautrix-whatsapp/mautrix-whatsapp.db";
+ };
+ state_store_path = "/var/lib/mautrix-whatsapp/mx-state.json";
+ id = "whatsapp";
+ bot = {
+ username = "whatsappbot";
+ displayname = "WhatsApp bridge bot";
+ avatar = "mxc://maunium.net/NeXNQarUbrlYBiPCpprYsRqr";
+ };
+ as_token = "";
+ hs_token = "";
+ };
+ bridge = {
+ username_template = "whatsapp_{{.}}";
+ displayname_template = "{{if .Notify}}{{.Notify}}{{else}}{{.Jid}}{{end}} (WA)";
+ command_prefix = "!wa";
+ permissions = {
+ "@example:matrix.org" = 100;
+ };
+ };
+ logging = {
+ directory = "/var/lib/mautrix-whatsapp/logs";
+ file_name_format = "{{.Date}}-{{.Index}}.log";
+ file_date_format = "\"2006-01-02\"";
+ file_mode = 384;
+ timestamp_format = "Jan _2, 2006 15:04:05";
+ print_level = "debug";
+ };
+ };
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ systemd.services.mautrix-whatsapp = {
+ description = "Mautrix-WhatsApp Service - A WhatsApp bridge for Matrix";
+ after = [ "network.target" "matrix-synapse.service" ];
+ wantedBy = [ "multi-user.target" ];
+
+ serviceConfig = {
+ DynamicUser = true;
+ StateDirectory = "mautrix-whatsapp";
+ LoggingDir = "mautrix-whatsapp";
+ ExecStart = ''
+ ${pkgs.mautrix-whatsapp}/bin/mautrix-whatsapp -c "${configFile}/config.yaml"
+ '';
+ Restart = "on-failure";
+ };
+ };
+
+ #services.matrix-synapse.app_service_config_files = [ "${configFile}/registration.yaml" ];
+
+ };
+}
diff --git a/monitoring.nix b/monitoring.nix
new file mode 100644
index 00000000..b7b0c6ca
--- /dev/null
+++ b/monitoring.nix
@@ -0,0 +1,17 @@
+{ config, pkgs, ... }: {
+ # grafana configuration
+ services.grafana = {
+ enable = true;
+ domain = "grafana.sealight.xyz";
+ port = 2342;
+ addr = "127.0.0.1";
+ };
+
+ # nginx reverse proxy
+ services.nginx.virtualHosts.${config.services.grafana.domain} = {
+ locations."/" = {
+ proxyPass = "http://127.0.0.1:${toString config.services.grafana.port}";
+ proxyWebsockets = true;
+ };
+ };
+}
diff --git a/sealight.nix b/sealight.nix
new file mode 100644
index 00000000..ed882042
--- /dev/null
+++ b/sealight.nix
@@ -0,0 +1,14 @@
+{
+ services.nginx = {
+ enable = true;
+ vhost = {
+ "sealight.xyz" = {
+ forceSSL = true;
+ enableACME = true;
+ locations."/" = {
+ root = "/var/www/sealight.xyz"
+ };
+ };
+ };
+ };
+}
diff --git a/wireguard.nix b/wireguard.nix
new file mode 100644
index 00000000..d4c3a84a
--- /dev/null
+++ b/wireguard.nix
@@ -0,0 +1,27 @@
+{ config, pkgs, lib, ... }:
+{
+ environment.systemPackages = [ pkgs.wireguard pkgs.mosh ];
+ networking.nat = {
+ enable = true;
+ externalInterface = "ens3";
+ internalInterfaces = [ "wg0" ];
+ };
+ networking.firewall = {
+ allowedUDPPorts = [ 60990 ];
+ };
+
+ networking.wireguard.interfaces.wg0 = {
+ ips = [ "10.0.69.1/24" ];
+ listenPort = 60990;
+ privateKeyFile = "/var/lib/wireguard/priv";
+ peers = [{ # bowl
+ publicKey = "EzvDUmHXo95S2jKRv/LkH5ItUNOBgM7aQQsaq1WfCRw=";
+ allowedIPs = [ "10.0.69.2/32" ];
+ }
+ { # line
+ publicKey = "ViRabGV2Mv0SZUVWnoAUhIzaHEvqRXAZJLq3Bp1oN1k=";
+ allowedIPs = [ "10.0.69.3/32" ];
+ }
+];
+ };
+}