Tailscale and immich on new system: port not responding?

Hi! I am very new with NixOS. I installed the minimal version and have been having a lot of fun turning on only what I need, as I need it. I am experimenting with hosting some services from a local computer on tailscale. I got an instance of jellyfin working and accessible through tailscale really easily, but immich will not work when trying to access from a remote computer.

I’m familiar working with (non-NixOS) Linux, but not with much networking terminology! I’ve been banging my head against the wall about this for a while. Does anyone have any suggestions, either for a fix or how to gather more information?

information

  • Typing in http://[tailscale ip]:2283 from another computer refuses connection.
  • sudo systemctl status immich-server says it’s running, with the most recent log message Immich Server is listening on http://[::1]:2283 [v1.123.0] [production]
  • sudo netstat -tunlpn | grep immich gives two entries:
tcp6   0   0 :::34153   :::*    LISTEN    1016/immich         
tcp6   0   0 ::1:2283   :::*    LISTEN    1087/immich-api
  • wget -i localhost:2283 downloads files that look like a functioning web page.
  • Tailscale doesn’t list the 2283 port in the admin dashboard list of services for the machine
  • That other port 34153 does work from another computer, but just loads a 404 JSON message: {"message":"Cannot GET /","error":"Not Found","statusCode":404}

So it seems like Immich is running happily locally and listening to the correct port, but something fails when trying to access it from another computer.

things I’ve tried

  • I rebuilt with networking.nftables.enable = true; and now instead of refusing connection to http://[tailscale ip]:2283, it times out.
  • I tried disabling jellyfin in case there was a conflict.
  • I tried turning magicDNS off.
  • I’ve seen a lot of examples that use an additional tool (like caddy or ngnix… a proxy?) to manage this kind of thing. My understanding is that if I want to keep my services locked down to only devices connected to my tailscale network, it’s not necessary. I don’t want to add additional complexity to have to troubleshoot if I don’t have to, and it wasn’t necessary for jellyfin.
  • I temporarily opened the port in the firewall with networking.firewall.allowedTCPPorts = [ 2283 ];, turned off tailscale, and tried connecting with the computer’s wifi IP. The ping went through, but the port still refused. (I think nftables.enable was still set during this test.)
config.nix

Truncated to hide irrelevant lines. Left in comments from the default config about networking that I haven’t ever uncommented because I think I don’t need them or don’t understand them.

{

  networking.hostName = "name"; # Define your hostname.
  networking.networkmanager.enable = true;  # Easiest to use and most distros use this by default.

  # Configure network proxy if necessary
  # networking.proxy.default = "http://user:password@proxy:port/";
  # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";

  # networking.nftables.enable = true;

  services.jellyfin = {
    enable = true;
    user = "admin"; # TODO change this back to default
  };

  services.immich = {
    enable = true;
#    port = 2283;
  };

  services.tailscale.enable = true;

  services.resolved.enable = true; # possible fix for tailscale?

  # List packages installed in system profile. To search, run:
  # $ nix search wget
  environment.systemPackages = with pkgs; [
    wget
    tailscale
    jellyfin
    jellyfin-web
    jellyfin-ffmpeg
  ];

  # Some programs need SUID wrappers, can be configured further or are
  # started in user sessions.
  # programs.mtr.enable = true;
  # programs.gnupg.agent = {
  #   enable = true;
  #   enableSSHSupport = true;
  # };

  # List services that you want to enable:

  # Enable the OpenSSH daemon.
  services.openssh.enable = true;

  # Open ports in the firewall.
  # networking.firewall.allowedTCPPorts = [ 2283 ];
  # networking.firewall.allowedUDPPorts = [ ... ];
  # Or disable the firewall altogether.
  # networking.firewall.enable = false;

}

You have to set services.immich.host as it’s set to "localhost" by default".

I set it to "0.0.0.0" and locked it down via systemd hardening, but you could take another approach if you’re always going to connect to it via the tailnet. Possibly even use the immich-public-proxy options.

Also, remove tailscale from your systemPackages, the tailscale module already adds that and you really don’t want to define the same package twice in a package list.

Thank you so much!! I guess I had thought localhost would somehow alias to the right thing, but it makes sense that you wouldn’t always want that.

I set services.immich.host to 0.0.0.0 and that is working. I still have to read about those other options you mentioned, but now that I have something working, I can do incremental changes as I learn more.

localhost points at (generally) 127.0.0.1, which is an IP that’s only routable on the current machine. See localhost - Wikipedia.
So if you tried to connect to your immich instance on the machine that’s running the server, it would’ve worked.

Meanwhile, binding to 0.0.0.0 generally includes all addresses.

1 Like