tldr: I’d like to set up a reverse proxy with a domain and an SSL cert so my partner and I can access a few selfhosted services on the internet but I’m not sure what the best/safest way to do it is. Asking my partner to use tailsclae or wireguard is asking too much unfortunately. I was curious to know what you all recommend.

I have some services running on my LAN that I currently access via tailscale. Some of these services would see some benefit from being accessible on the internet (ex. Immich sharing via a link, switching over from Plex to Jellyfin without requiring my family to learn how to use a VPN, homeassistant voice stuff, etc.) but I’m kind of unsure what the best approach is. Hosting services on the internet has risk and I’d like to reduce that risk as much as possible.

  1. I know a reverse proxy would be beneficial here so I can put all the services on one box and access them via subdomains but where should I host that proxy? On my LAN using a dynamic DNS service? In the cloud? If in the cloud, should I avoid a plan where you share cpu resources with other users and get a dedicated box?

  2. Should I purchase a memorable domain or a domain with a random string of characters so no one could reasonably guess it? Does it matter?

  3. What’s the best way to geo-restrict access? Fail2ban? Realistically, the only people that I might give access to live within a couple hundred miles of me.

  4. Any other tips or info you care to share would be greatly appreciated.

  5. Feel free to talk me out of it as well.

  • @jimmy90
    link
    English
    1
    edit-2
    1 day ago

    this is my container config for element/matrix podman containers do not run as root so you have to get the file privileges right on the volumes mapped into the containers. i used top to find out what user the services were running as. you can see there are some settings there where you can change the user if you are having permissions problems

    
    
    
    { pkgs, modulesPath, ... }:
    
    {
    
      imports = [
        (modulesPath + "/virtualisation/proxmox-lxc.nix")
      ];
    
      security.pki.certificateFiles = [ "/etc/ssl/certs/ca-certificates.crt" ];
    
      system.stateVersion = "23.11";
      system.autoUpgrade.enable = true;
      system.autoUpgrade.allowReboot = false;
    
      nix.gc = {
        automatic = true;
        dates = "weekly";
        options = "--delete-older-than 14d";
      };
    
      services.openssh = {
        enable = true;
        settings.PasswordAuthentication = true;
      };
    
      users.users.XXXXXX = {
        isNormalUser = true;
        home = "/home/XXXXXX";
        extraGroups = [ "wheel" ];
        shell = pkgs.zsh;
      };
    
      programs.zsh.enable = true;
    
      environment.etc = {
        "fail2ban/filter.d/matrix-synapse.local".text = pkgs.lib.mkDefault (pkgs.lib.mkAfter ''
          [Definition]
          failregex = .*POST.* - <HOST> - 8008.*\n.*\n.*Got login request.*\n.*Failed password login.*
                      .*POST.* - <HOST> - 8008.*\n.*\n.*Got login request.*\n.*Attempted to login as.*\n.*Invalid username or password.*
        '');
      };
    
      services.fail2ban = {
        enable = true;
        maxretry = 3;
        bantime = "10m";
        bantime-increment = {
          enable = true;
          multipliers = "1 2 4 8 16 32 64";
          maxtime = "168h";
          overalljails = true;
        };
        jails = {
          matrix-synapse.settings = {
            filter = "matrix-synapse";
            action = "%(known/action)s";
            logpath = "/srv/logs/synapse.json.log";
            backend = "auto";
            findtime = 600;
            bantime  = 600;
            maxretry = 2;
          };
        };
      };
    
      virtualisation.oci-containers = {
        containers = {
    
          postgres = {
            autoStart = false;
            environment = {
              POSTGRES_USER = "XXXXXX";
              POSTGRES_PASSWORD = "XXXXXX";
              LANG = "en_US.utf8";
            };
            image = "docker.io/postgres:14";
            ports = [ "5432:5432" ];
            volumes = [
              "/srv/postgres:/var/lib/postgresql/data"
            ];
            extraOptions = [
              "--label" "io.containers.autoupdate=registry"
              "--pull=newer"
            ];
          };
    
          synapse = {
            autoStart = false;
            environment = {
              LANG = "C.UTF-8";
    #          UID="0";
    #          GID="0";
            };
     #       user = "1001:1000";
            image = "ghcr.io/element-hq/synapse:latest";
            ports = [ "8008:8008" ];
            volumes = [
              "/srv/synapse:/data"
            ];
            log-driver = "json-file";
            extraOptions = [
              "--label" "io.containers.autoupdate=registry"
              "--log-opt" "max-size=10m" "--log-opt" "max-file=1" "--log-opt" "path=/srv/logs/synapse.json.log"
              "--pull=newer"
            ];
            dependsOn = [ "postgres" ];
          };
    
          element = {
            autoStart = true;
            image = "docker.io/vectorim/element-web:latest";
            ports = [ "8009:80" ];
            volumes = [
              "/srv/element/config.json:/app/config.json"
            ];
            extraOptions = [
              "--label" "io.containers.autoupdate=registry"
              "--pull=newer"
            ];
    #        dependsOn = [ "synapse" ];
          };
    
          call = {
            autoStart = true;
            image = "ghcr.io/element-hq/element-call:latest-ci";
            ports = [ "8080:8080" ];
            volumes = [
              "/srv/call/config.json:/app/config.json"
            ];
            extraOptions = [
              "--label" "io.containers.autoupdate=registry"
              "--pull=newer"
            ];
          };
    
          livekit = {
            autoStart = true;
            image = "docker.io/livekit/livekit-server:latest";
            ports = [ "7880:7880" "7881:7881" "50000-60000:50000-60000/udp" "5349:5349" "3478:3478/udp" ];
            cmd = [ "--config" "/etc/config.yaml" ];
            entrypoint = "/livekit-server";
            volumes = [
              "/srv/livekit:/etc"
            ];
            extraOptions = [
              "--label" "io.containers.autoupdate=registry"
              "--pull=newer"
            ];
          };
    
          livekitjwt = {
            autoStart = true;
            image = "ghcr.io/element-hq/lk-jwt-service:latest-ci";
            ports = [ "7980:8080" ];
            environment = {
              LK_JWT_PORT = "8080";
              LIVEKIT_URL = "wss://livekit.XXXXXX.dynu.net";
              LIVEKIT_KEY = "XXXXXX";
              LIVEKIT_SECRET = "XXXXXX";
            };
            entrypoint = "/lk-jwt-service";
            extraOptions = [
              "--label" "io.containers.autoupdate=registry"
              "--pull=newer"
            ];
          };
    
        };
      };
    
    }