My wife brought home a TV from a thrift store. So I took the easy route of setting up a media center to make it play videos. I already had a headless Jellyfin server running on a small Beelink computer. I connected that to the TV, installed Kodi, installed the Yatse remote control app on my phone, and we’re all set.

It took me some research and trial and error to get the remote control app connected with Zeroconf auto discovery working. So I thought I’d share what I learned. Here is my entire Kodi module:

{ pkgs, ... }:

{
  # Enable a graphical shell
  services.xserver.enable = true;

  services.xserver.desktopManager.kodi = {
    enable = true;
    package = pkgs.kodi.withPackages (
      kodiPackages: with kodiPackages; [
        jellyfin
        netflix
      ]
    );
  };

  # To view plugins available in nixpkgs run:
  #
  # $ nix repl
  # > pkgs = import <nixpkgs> {}
  # > builtins.attrNames pkgs.kodiPackages
  #
  # Or search for plugins on https://search.nixos.org/, and in the left-sidebar
  # under "Package sets" click "kodiPackages"

  services.displayManager.autoLogin = {
    enable = true;
    user = "kodi";
  };

  users.users.kodi.isNormalUser = true;

  # Allow reboot and shut down from Kodi UI
  security.polkit = {
    enable = true;
    extraConfig = /* javascript */ ''
      polkit.addRule(function(action, subject) {
        if (
          (
            action.id == "org.freedesktop.login1.reboot" ||
            action.id == "org.freedesktop.login1.reboot-multiple-sessions" ||
            action.id == "org.freedesktop.login1.power-off" ||
            action.id == "org.freedesktop.login1.power-off-multiple-sessions"
          )
          && subject.user == "kodi"
        ) {
          return polkit.Result.YES;
        }
      });
    '';
  };

  # Allow access to web UI & remote control API
  networking.firewall = {
    allowedTCPPorts = [
      8010 # the port I configured for "allow remote control via HTTP"
      9090 # also event server?
    ];
    allowedUDPPorts = [
      9777 # event server
    ];
  };

  # Allows Kodi to advertise to remote control apps using Zeroconf.
  services.avahi = {
    enable = true;
    publish.enable = true;
    publish.userServices = true;
  };
}

Kodi is a graphical shell. Like I said, this box was previously headless; so I enabled Kodi as my DE and set it up to automatically log in.

To make the remote control work there are some necessary settings changes to make in the Kodi UI. I had to connect a keyboard temporarily to set this up:

  • Go to Settings > Services
  • Enable General > Announce services to other systems (for Zeroconf auto discovery)
  • In Control enable:
    • Allow remote control via HTTP (match port number in NixOS firewall settings)
    • Allow remote control from applications on this system
    • Allow remote control from applications on other systems
  • I’m not sure if this is needed, but the Yatse docs recommend these settings in UPnP / DLNA for “some streaming cases”:
    • Share my libraries
    • Allow remote control via UPnP

Declarative settings would be nicer, but there doesn’t seem to be a NixOS module that does that yet. It’s the same situation with Jellyfin.