Cannot access a port on same network

Issue:
I’m running NixOS and have set up an application that serves on a specific port (let’s say 4321). However, I cannot access this application from another device on the same local network. The application runs fine and is accessible locally on the NixOS machine itself, but when I try to connect from another device, the connection times out.

Steps I’ve Taken:

  1. Verified that the application is running and accessible on localhost:4321.
  2. Checked that the NixOS firewall is disabled using services.firewall.enable = false; in my configuration.
  3. Confirmed that the network devices are connected to the same network and can ping each other.
  4. Ensured that the application is bound to 0.0.0.0 to accept connections from any network interface.
  5. Tried accessing the application using the NixOS machine’s local IP address (e.g., 192.168.x.x:4321) from another device on the network, but still unable to connect.
My Config
# Edit this configuration file to define what should be installed on
# your system.  Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ‘nixos-help’).

{ config, pkgs, ... }:

{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix

      ./nix-flatpak/modules/nixos.nix
    ];

  # Bootloader.
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  # NTFS Support
  boot.supportedFilesystems = [ "ntfs" ];
  fileSystems."/windisk" = {
    device = "/dev/sda2";
    fsType = "ntfs-3g";
    options = [ "rw" "uid=1000" ];
  };

  networking.hostName = "ac"; # Define your hostname.
  # networking.wireless.enable = true;  # Enables wireless support via wpa_supplicant.

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

  # Enable networking
  networking.networkmanager.enable = true;

  # Set your time zone.
  time.timeZone = "Europe/Istanbul";

  # Select internationalisation properties.
  i18n.defaultLocale = "en_US.UTF-8";

  i18n.extraLocaleSettings = {
    LC_ADDRESS = "tr_TR.UTF-8";
    LC_IDENTIFICATION = "tr_TR.UTF-8";
    LC_MEASUREMENT = "tr_TR.UTF-8";
    LC_MONETARY = "tr_TR.UTF-8";
    LC_NAME = "tr_TR.UTF-8";
    LC_NUMERIC = "tr_TR.UTF-8";
    LC_PAPER = "tr_TR.UTF-8";
    LC_TELEPHONE = "tr_TR.UTF-8";
    LC_TIME = "tr_TR.UTF-8";
  };

  # Enable the X11 windowing system.
  # You can disable this if you're only using the Wayland session.
  services.xserver.enable = true;

  # Enable the KDE Plasma Desktop Environment.
  services.displayManager.sddm.enable = true;
  services.desktopManager.plasma6.enable = true;

  # Configure keymap in X11
  services.xserver = {
    xkb = {
      layout = "us";
    };
  };

  # Enable CUPS to print documents.
  services.printing.enable = true;

  # Enable sound with pipewire.
  hardware.pulseaudio.enable = false;
  security.rtkit.enable = true;
  services.pipewire = {
    enable = true;
    alsa.enable = true;
    alsa.support32Bit = true;
    pulse.enable = true;
    # If you want to use JACK applications, uncomment this
    #jack.enable = true;

    # use the example session manager (no others are packaged yet so this is enabled by default,
    # no need to redefine it in your config for now)
    #media-session.enable = true;
  };

  # Enable touchpad support (enabled default in most desktopManager).
  # services.xserver.libinput.enable = true;

  # Define a user account. Don't forget to set a password with ‘passwd’.
  users.users.acnix = {
    isNormalUser = true;
    description = "Ahmet";
    extraGroups = [ "networkmanager" "wheel"
#     "libvirtd"
      "docker"
    ];
    packages = with pkgs; [
      kdePackages.kate
    ];
  };

  # Nvidia
  # Enable OpenGL
  hardware.graphics.enable = true;

  # Load nvidia driver for Xorg and Wayland
  services.xserver.videoDrivers = ["nvidia"];

  hardware.nvidia = {

    # Modesetting is required.
    modesetting.enable = true;

    # Nvidia power management. Experimental, and can cause sleep/suspend to fail.
    # Enable this if you have graphical corruption issues or application crashes after waking
    # up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead
    # of just the bare essentials.
    powerManagement.enable = false;

    # Fine-grained power management. Turns off GPU when not in use.
    # Experimental and only works on modern Nvidia GPUs (Turing or newer).
    powerManagement.finegrained = false;

    # Use the NVidia open source kernel module (not to be confused with the
    # independent third-party "nouveau" open source driver).
    # Support is limited to the Turing and later architectures. Full list of
    # supported GPUs is at:
    # https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus
    # Only available from driver 515.43.04+
    # Currently alpha-quality/buggy, so false is currently the recommended setting.
    open = false;

    # Enable the Nvidia settings menu,
	# accessible via `nvidia-settings`.
    nvidiaSettings = true;

    # Optionally, you may need to select the appropriate driver version for your specific GPU.
    package = config.boot.kernelPackages.nvidiaPackages.beta;
  };

  # Bluetooth
  hardware.bluetooth.enable = true; # enables support for Bluetooth
  hardware.bluetooth.powerOnBoot = true; # powers up the default Bluetooth controller on boot

  # ZSH
  programs.zsh = {
    enable = true;
    shellAliases = {
      update = "echo \"sudo nixos-rebuild switch\" && sudo nixos-rebuild switch";
      code = "codium";
    };
  };

  # Flatpak
  services.flatpak = {
    enable = true;
    remotes = [
      {
        name = "flathub"; location = "https://flathub.org/repo/flathub.flatpakrepo";
      }
      {
        name = "flathub-beta"; location = "https://flathub.org/beta-repo/flathub-beta.flatpakrepo";
      }
    ];
    packages = [
      "org.kde.kalk"

      "com.github.tchx84.Flatseal"
      "io.github.dvlv.boxbuddyrs"

      "com.github.wwmm.easyeffects"

      "one.ablaze.floorp"

      "org.mozilla.Thunderbird"
      "com.ulduzsoft.Birdtray"
      "com.tutanota.Tutanota"

      "org.libreoffice.LibreOffice"

      "dev.vencord.Vesktop"

      "com.github.KRTirtho.Spotube"

      "com.github.finefindus.eyedropper"

      "com.obsproject.Studio"
      "io.mpv.Mpv"
      "fr.handbrake.ghb"
      "org.audacityteam.Audacity"
      "com.stremio.Stremio"
      "org.kde.kdenlive"

      "org.qbittorrent.qBittorrent"

      "org.blender.Blender"

      "rest.insomnia.Insomnia"
      "org.godotengine.GodotSharp"
      "io.podman_desktop.PodmanDesktop"
      # Install Manually "flatpak install https://gitlab.com/projects261/firefox-dev-flatpak/-/raw/main/firefox-dev.flatpakref"
      "org.filezillaproject.Filezilla"
      "org.apache.directory.studio"

      "com.ultimaker.cura"
      { appId = "org.openrgb.OpenRGB"; origin = "flathub-beta";  }

      "org.bleachbit.BleachBit"
      "org.gnome.baobab"
      "com.anydesk.Anydesk"
      "com.prusa3d.PrusaSlicer"
    ];
  };

  # Allow unfree packages
  nixpkgs.config.allowUnfree = true;

  # VM
  #   virtualisation.libvirtd = {
  #   enable = true;
  #   qemu = {
  #     package = pkgs.qemu_kvm;
  #     runAsRoot = true;
  #     swtpm.enable = true;
  #     ovmf = {
  #       enable = true;
  #       packages = [(pkgs.OVMF.override {
  #         secureBoot = true;
  #         tpmSupport = true;
  #         }).fd];
  #       };
  #     };
  #   };
  #   programs.virt-manager.enable = true;

  users.extraGroups.vboxusers.members = [ "user-with-access-to-virtualbox" ];
  virtualisation.virtualbox = {
    host = {
      enable = true;
      enableExtensionPack = true;
    };
    guest = {
    enable = true;
    dragAndDrop = true;
    };
  };

  # List packages installed in system profile. To search, run:
  # $ nix search wget
  environment.systemPackages = with pkgs; [
    nixpkgs-fmt

    neovim
    fastfetch
    unzip

    starship
    eza
    inshellisense
    zoxide

    git
    gitui
    dotnetCorePackages.dotnet_8.sdk
    nodejs_20
    vscodium
    fzf ripgrep bat
    yarn
    bun
    typescript
    nodePackages."\@angular/cli"
    jdk22
    flutter323
    android-tools
    android-studio
    android-studio-tools

    anytype

    docker-compose
    distrobox

    gparted

    openfortivpn
    openldap

    pkgs.firefoxpwa
  ];

  programs.firefox = {
    enable = true;
    package = pkgs.firefox;
    nativeMessagingHosts.packages = [ pkgs.firefoxpwa ];
  };

  programs.nix-ld.enable = true;
  programs.nix-ld.package = pkgs.nix-ld-rs;

  # Docker
  virtualisation.docker.enable = true;

  # OpenLDAP
  services.openldap.enable = true;

  # 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 = [ ... ];
  # networking.firewall.allowedUDPPorts = [ ... ];
#  networking.firewall.extraCommands = ''
#iptables -A nixos-fw -p tcp --source 192.0.2.0/24 --dport 4000:6000 -j nixos-fw-accept
#iptables -A nixos-fw -p udp --source 192.0.2.0/24 --dport 4000:6000 -j nixos-fw-accept
#'';
  # Or disable the firewall altogether.
  networking.firewall.enable = false;

  # This value determines the NixOS release from which the default
  # settings for stateful data, like file locations and database versions
  # on your system were taken. It‘s perfectly fine and recommended to leave
  # this value at the release version of the first install of this system.
  # Before changing this value read the documentation for this option
  # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
  system.stateVersion = "24.05"; # Did you read the comment?
}

Did you restart after making the firewall changes?

Yes, I tried rebooting.

I have been trying to solve this problem for a long time.

Are you running NixOS on a virtual machine or a physical one? Is there a firewall or anything that could block communication between hosts in your network?

The config looks OK at a glance (provided there’s nothing funky in the imports, like networking.forewall.enable = lib.mkForce true). But for the record – there doesn’t seem to be a service defined, so I presume you’re starting whatever listens on 4321 from a shell.

How are you starting this application? Does it have any command line arguments or configuration file that mention 127.0.0.1 ?

One possible and simple explanation for this problem is that the application is bound to 127.0.0.1 and not 0.0.0.0. For example if you were to run

python3 -m http.server -b 127.0.0.1 4321

that would start up an http server on port 4321 that is only accessibly from the same host. If you run

ss -ln -A tcp 

You’ll see

127.0.0.1:4321

as the local address.

Change that to

python3 -m http.server 4321

And you’ll see

0.0.0.0:4321

in the ss output and the service will be accessible from other machines.

They already mentioned that

Oh, derp, so they did.

If that’s the case, and ss does confirm that it’s listening on 0.0.0.0, I would run

sudo tcpdump -n -i any port 4321

While the other host is trying to connect and see if you even see the inbound syn packets (Flags [S]) for the service.

I run nixos my personal physical machine. I even turned off the firewall through the modem interface.
For example, I run the same project on a Windows machine on another physical computer, and I can access it from other devices with the local ip and application port.

I think it’s listening on the port:

> netstat -tuln                   
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:389             0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:8080          0.0.0.0:*               LISTEN     
tcp6       0      0 :::389                  :::*                    LISTEN     
tcp6       0      0 ::1:4321                :::*                    LISTEN     
tcp6       0      0 ::1:631                 :::*                    LISTEN


I tried this for researching.

I run http server on my nixos machine. And I can access, of course.

> python3 -m http.server -b 127.0.0.1 4321
Serving HTTP on 127.0.0.1 port 4321 (http://127.0.0.1:4321/)
> nc -zv 127.0.0.1 4321
Connection to 127.0.0.1 4321 port [tcp/rwhois] succeeded!

I tried another debian physical machine.

> nc -zv 192.168.0.7 4321
192.168.0.7: inverse host lookup failed: Unkown host
(UNKOWN) [192.168.0.7] 4321 (?) : Connection refused

I run http server on my nixos machine via:

> python3 -m http.server 4321
Serving HTTP on 0.0.0.0 port 4321 (http://0.0.0.0:4321/) 

On my nixos machine:

> nc -zv 127.0.0.1 4321
Connection to 127.0.0.1 4321 port [tcp/rwhois] succeeded!

> nc -zv 0.0.0.0 4321
Connection to 0.0.0.0 4321 port [tcp/rwhois] succeeded!

On my another debian machine, but same error.

> nc -zv 192.168.0.7 4321
192.168.0.7: inverse host lookup failed: Unkown host
(UNKOWN) [192.168.0.7] 4321 (?) : Connection refused


My nixos machine:

> sudo tcpdump -n -i any port 4321
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode

Another debian machine:

> nc -zv 192.168.0.7 4321
192.168.0.7: inverse host lookup failed: Unkown host
(UNKOWN) [192.168.0.7] 4321 (?) : Connection refused

My nixos machine:

> sudo tcpdump -n -i any port 4321
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
17:15:37.840540 eno1  In  IP 192.168.0.5.54318 > 192.168.0.7.4321: Flags [S], seq 3071785173, win 64240, options [mss 1460,sackOK,TS val 573283215 ecr 0,nop,wscale 7], length 0
17:15:37.840579 eno1  Out IP 192.168.0.7.4321 > 192.168.0.5.54318: Flags [S.], seq 2088861052, ack 3071785174, win 65160, options [mss 1460,sackOK,TS val 995502091 ecr 573283215,nop,wscale 7], length 0
17:15:37.841592 eno1  In  IP 192.168.0.5.54318 > 192.168.0.7.4321: Flags [.], ack 1, win 502, options [nop,nop,TS val 573283217 ecr 995502091], length 0
17:15:37.841593 eno1  In  IP 192.168.0.5.54318 > 192.168.0.7.4321: Flags [F.], seq 1, ack 1, win 502, options [nop,nop,TS val 573283217 ecr 995502091], length 0
17:15:37.841885 eno1  Out IP 192.168.0.7.4321 > 192.168.0.5.54318: Flags [F.], seq 1, ack 2, win 510, options [nop,nop,TS val 995502092 ecr 573283217], length 0
17:15:37.842793 eno1  In  IP 192.168.0.5.54318 > 192.168.0.7.4321: Flags [.], ack 2, win 502, options [nop,nop,TS val 573283218 ecr 995502092], length 0

Hi,

That’s interesting, the nixos side showed a normal connection setup, but then the client ended the connection 1 microsecond later. Your client side is showing “Connection refused” which does not match those packets.

I suspect you may have an IP conflict on your network. Can you also run

sudo tcpdump -e -n -i any port 4321

(note the addition of -e)

on the debian machine while you make the connection attempt. Does it show you receiving a reset packet (Flags [R]) from a different mac address? Do the mac addresses you see match what you expect?

Running

arp -an

and comparing it to what

ip link

shows may have some unexpected output.

Looks like it’s listening only on ipv6(no just tcp line). Have you tried explicitly specifying the ipv4 address instead of 0.0.0.0? This may also be a symptom of ip conflict as @Justinsaccount is suggesting

My nixos machine:

> python3 -m http.server 4321
Serving HTTP on 0.0.0.0 port 4321 (http://0.0.0.0:4321/) 

My debian machine:

> sudo tcpdump -e -n -i any port 4321
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
> nc -zv 192.168.0.7 4321
192.168.0.7: inverse host lookup failed: Unknown host
(UNKNOWN) [192.168.0.7] 4321 (?) open
> sudo tcpdump -e -n -i any port 4321
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
18:25:23.878312 wlo1  Out ifindex 2 34:6f:24:74:b4:09 ethertype IPv4 (0x0800), length 80: 192.168.0.5.56052 > 192.168.0.7.4321: Flags [S], seq 14064141, win 64240, options [mss 1460,sackOK,TS val 577469307 ecr 0,nop,wscale 7], length 0
18:25:23.879246 wlo1  In  ifindex 2 c8:7f:54:57:58:c8 ethertype IPv4 (0x0800), length 80: 192.168.0.7.4321 > 192.168.0.5.56052: Flags [S.], seq 1149021401, ack 14064142, win 65160, options [mss 1460,sackOK,TS val 999688148 ecr 577469307,nop,wscale 7], length 0
18:25:23.879286 wlo1  Out ifindex 2 34:6f:24:74:b4:09 ethertype IPv4 (0x0800), length 72: 192.168.0.5.56052 > 192.168.0.7.4321: Flags [.], ack 1, win 502, options [nop,nop,TS val 577469308 ecr 999688148], length 0
18:25:23.879412 wlo1  Out ifindex 2 34:6f:24:74:b4:09 ethertype IPv4 (0x0800), length 72: 192.168.0.5.56052 > 192.168.0.7.4321: Flags [F.], seq 1, ack 1, win 502, options [nop,nop,TS val 577469308 ecr 999688148], length 0
18:25:23.880478 wlo1  In  ifindex 2 c8:7f:54:57:58:c8 ethertype IPv4 (0x0800), length 72: 192.168.0.7.4321 > 192.168.0.5.56052: Flags [F.], seq 1, ack 2, win 510, options [nop,nop,TS val 999688149 ecr 577469308], length 0
18:25:23.880511 wlo1  Out ifindex 2 34:6f:24:74:b4:09 ethertype IPv4 (0x0800), length 72: 192.168.0.5.56052 > 192.168.0.7.4321: Flags [.], ack 2, win 502, options [nop,nop,TS val 577469309 ecr 999688149], length 0


I’ll be trying to assign a static local ip from the modem interface.

That attempt looked normal… and I didn’t catch you were using nc -z before, which closes the connection immediately - that explains the immediate Fin packets. Note that this time you got a

(UNKNOWN) [192.168.0.7] 4321 (?) open

and not

(UNKOWN) [192.168.0.7] 4321 (?) : Connection refused

like before.

This could still fit with there being an ip conflict, as the arp table entry will flip back and forth between the right host and the wrong host.

Can you use

curl -v http://192.168.0.7:4321/

for testing instead of nc -z? Even better would be to have it pull down a 1GB file like

curl -v -o /dev/null http://192.168.0.7:4321/some.file

You could also use iperf3 for testing.

When the problem is something like an ip conflict, a short connection (like nc -z) may work sometimes, but anything that requires a connection to say open for more than a few seconds will eventually fail.

I assigned static local IPs:

2 192.168.0.2 C8:7F:54:57:58:C8 acnix
3 192.168.0.3 34:6F:24:74:B4:09 acdebian

I have started an HTTP server on 0.0.0.0 via python3 -m http.server 4321 and can download a file on the Debian machine from the NixOS machine.

> curl -v -o ./test.tar.gz http://192.168.0.2:4321/test.tar.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 192.168.0.2:4321...
* Connected to 192.168.0.2 (192.168.0.2) port 4321 (#0)
> GET /test.tar.gz HTTP/1.1
> Host: 192.168.0.2:4321
> User-Agent: curl/7.88.1
> Accept: */*
> 
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.12.4
< Date: Sat, 10 Aug 2024 16:22:25 GMT
< Content-type: application/gzip
< Content-Length: 717261726
< Last-Modified: Sat, 10 Aug 2024 16:18:39 GMT
< 
{ [5792 bytes data]
100  684M  100  684M    0     0  18.5M      0  0:00:36  0:00:36 --:--:-- 18.5M
* Closing connection 0

How can I create a proxy from 0.0.0.0 to 127.0.0.1?

Hi,

neat… so it works now with new ips?

What do you mean by this exactly? 0.0.0.0 is an alias for “all interfaces” and 127.0.0.1 means just the loopback interface. If something is bound to 127.0.0.1 and you want to make it available on all interfaces, usually that’s fixed by making it bind to 0.0.0.0, not by adding a proxy.

For example, I have applications running in Docker, such as a database that is working on localhost:5432. I can’t access it using 192.168.0.2:5432. I probably need to pass a configuration through Docker and set it up again. But there are many applications, and while they are running on localhost, can’t we make them accessible simultaneously via 0.0.0.0? Like on Windows, when I start any application, I want it to be accessible from both localhost and 0.0.0.0.