1

I was having trouble running the nitter package in nixos. It complained about rate limits. So I used the source package code to try to grab the latest release off of git and still ran into the same error:

Starting Nitter
Starting Nitter at http://mymachine
Connected to Redis at localhost:7777
fetching token failed: No SSL/TLS CA certificates found.
RateLimitError: rate limited

After doing some digging, it seemed like nim couldn't find the ca certs. I added the cacerts nixos package and even the openssl package, but nitter still fails to load the default cacerts. My services/nitter.nix is setup like the following:

{ pkgs, lib, nimPackages, fetchFromGitHub, ... }:
with pkgs;
let

  nitter-git = nimPackages.buildNimPackage {
  pname = "nitter";
  version = "unstable-2022-10-17";
 
  src = fetchFromGitHub {
    owner = "zedeus";
    repo = "nitter";
    rev = "2ac3afa5b273a502d7632e9346c7c3bc9283fb48";
    hash = "sha256-fdzVfzmEFIej6Kb/K9MQyvbN8aN3hO7RetHL53cD59k=";
  };
 
  buildInputs = with nimPackages; [
    flatty
    jester
    jsony
    karax
    markdown
    nimcrypto
    packedjson
    redis
    redpool
    sass
    supersnappy
    zippy
  ];
 
  nimBinOnly = true;

  nimFlags = ["-d:ssl"];
 
  postBuild = ''
    nim c --hint[Processing]:off -r tools/gencss
    nim c --hint[Processing]:off -r tools/rendermd
  '';
 
  postInstall = ''
    mkdir -p $out/share/nitter
    cp -r public $out/share/nitter/public
  '';
 
  meta = with lib; {
    homepage = "https://github.com/zedeus/nitter";
    description = "Alternative Twitter front-end";
    license = licenses.agpl3Only;
    maintainers = with maintainers; [ erdnaxe ];
    mainProgram = "nitter";
  };
};

  redis-run = writeTextFile {
      name = "redis-run";
      executable = true;
      destination = "/etc/s6/redis/run";
      text = ''
      #!/bin/sh
      echo "Starting Redis on 7777"
      exec redis-server --port 7777
      '';
  };
  redis-finish = writeTextFile {
      name = "redis-finish";
      executable = true;
      destination = "/etc/s6/redis/finish";
      text = ''
      #!/bin/sh
      echo "Stopping Redis"
      '';
  };
  nitter-run = writeTextFile {
      name = "nitter-run";
      executable = true;
      destination = "/etc/s6/nitter/run";
      text = ''
      #!/bin/sh
      echo "Starting Nitter"
      exec nitter
      '';
  };
  nitter-finish = writeTextFile {
      name = "nitter-finish";
      executable = true;
      destination = "/etc/s6/nitter/finish";
      text = ''
      #!/bin/sh
      echo "Stopping Nitter"
      '';
  };
  nitter-conf = writeTextFile {
      name = "nitter-conf";
      executable = true;
      destination = "/etc/nitter.conf";
      text = ''
        [Server]
        address = "0.0.0.0"
        port = 8182
        https = false  # disable to enable cookies when not using https
        httpMaxConnections = 100
        staticDir = "/share/nitter/public"
        title = "nitter"
        hostname = "myhost"

        [Cache]
        listMinutes = 240  # how long to cache list info (not the tweets, so keep it high)
        rssMinutes = 10  # how long to cache rss queries
        redisHost = "localhost"  # Change to "nitter-redis" if using docker-compose
        redisPort = 7777
        redisPassword = ""
        redisConnections = 20  # connection pool size
        redisMaxConnections = 30
        # max, new connections are opened when none are available, but if the pool size
        # goes above this, they're closed when released. don't worry about this unless
        # you receive tons of requests per second

        [Config]
        hmacKey = "somereallylongrandomkeyhere"  # random key for cryptographic signing of video urls
        base64Media = false  # use base64 encoding for proxied media urls
        enableRSS = true  # set this to false to disable RSS feeds
        enableDebug = false  # enable request logs and debug endpoints
        proxy = ""  # http/https url, SOCKS proxies are not supported
        proxyAuth = ""
        tokenCount = 10
        # minimum amount of usable tokens. tokens are used to authorize API requests,
        # but they expire after ~1 hour, and have a limit of 187 requests.
        # the limit gets reset every 15 minutes, and the pool is filled up so there's
        # always at least $tokenCount usable tokens. again, only increase this if
        # you receive major bursts all the time

        # Change default preferences here, see src/prefs_impl.nim for a complete list
        [Preferences]
        theme = "Nitter"
        replaceTwitter = ""
        replaceYouTube = "piped.kavin.rocks"
        replaceReddit = "teddit.net"
        replaceInstagram = ""
        proxyVideos = true
        hlsPlayback = false
        infiniteScroll = false
      '';
  };
in
  dockerTools.buildLayeredImage {
    name = "nitter";
    contents = [ nitter-git s6 redis git busybox cacert openssl
                 redis-run redis-finish nitter-run nitter-finish
                 nitter-conf ];
    config = {
      Entrypoint = [ "/bin/s6-svscan" "/etc/s6" ];
      Env = [ "NITTER_CONF_FILE=/etc/nitter.conf" ];
      Volumes = {};
    };
  }

and I call this module using the following services.nix:

let
  config = import ./config.nix;
  pkgs = config.pkgs;
  nitter = import ./services/nitter.nix;
in rec {
  serviceimages = pkgs.writeText "images.ini" ''
    nitter=${nitter(pkgs)}
  '';
}

and I use nixos 20.05 for my config:

{
  # nixos-22.05 / https://status.nixos.org/
  pkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/8de8b98839d1f20089582cfe1a81207258fcc1f1.tar.gz") {};
}

I run nix-build services.nix, take the resulting path for nitter in result and run docker load < [tar.gz file path] or alternatively zcat [tar.gz file path] | podman load and run it using [docker|podman] run --rm --name nitter -p 8182:8182 -it localhost/nitter:<thelonghashthatgetsreturnedfromload>

If I set the --entrypoint to /bin/sh, I do see there is a cert bundle installed from the nix store.

# ls /etc/ssl/certs/ca-bundle.crt  -l
lrwxrwxrwx    1 0        0               87 Jan  1  1980 /etc/ssl/certs/ca-bundle.crt -> /nix/store/rqiiybq5hryzyk3v84mi8cgwjcxm9bi4-nss-cacert-3.83/etc/ssl/certs/ca-bundle.crt

As you can see from the nitter build file, I tried setting nimFlags = ["-d:ssl"]; as well as including openssl as a dependency, but nitter still can't seem to load the CA certs.

djsumdog
  • 2,560
  • 1
  • 29
  • 55
  • Not related to your question, but as a random nitpicky aside, options should come _before_ positional arguments. The GNU version of `ls` does support `ls file -l`, but baseline POSIX-standard `ls` only supports `ls -l file`; see guideline 9 in https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02 – Charles Duffy Oct 17 '22 at 20:49
  • 1
    Anyhow -- I'd probably reach for sysdig (much less performance overhead than strace, and more convenient to use when trying to get syscall-level tracing of what's going on inside a Docker container since it can be run from the host) to see if the executable is ever actually opening that `ca-bundle.crt` file, and/or what locations it's looking in instead. – Charles Duffy Oct 17 '22 at 20:54

1 Answers1

1

Thanks to the comments on the question, I discovered some things. Looking at strace nitter, I discovered the application was looking explicitly for the libssl library:

newfstatat(AT_FDCWD, "libssl.so.1.1", 0x7ffd42493590, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "libssl.so.1.1", 0x7ffd42493590, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "libssl.so.1.0.2", 0x7ffd42493590, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "libssl.so.1.1", 0x7ffd42493590, 0) = -1 ENOENT (No such file or directory)
...
...
...
newfstatat(AT_FDCWD, "libssl.so.38", 0x7ffd424935f0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "libssl.so.10", 0x7ffd424935f0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "libssl.so", 0x7ffd424935f0, 0) = -1 ENOENT (No such file or directory) 

Running ldd on the binary itself confirms that libssl is dynamically loaded, which means it won't be loaded from the nix store:

ldd /nix/store/yg7y3bmyr4xni78mqf71jq8apxsrj3mv-nitter-unstable-2022-06-04/bin/nitter 
    linux-vdso.so.1 (0x00007ffd575a1000)
    libm.so.6 => /nix/store/c6f52mvbv0d8rd3rlslsvy7v4g3pmm7p-glibc-2.35-163/lib/libm.so.6 (0x00007f331a054000)
    librt.so.1 => /nix/store/c6f52mvbv0d8rd3rlslsvy7v4g3pmm7p-glibc-2.35-163/lib/librt.so.1 (0x00007f331a04f000)
    libdl.so.2 => /nix/store/c6f52mvbv0d8rd3rlslsvy7v4g3pmm7p-glibc-2.35-163/lib/libdl.so.2 (0x00007f331a04a000)
    libc.so.6 => /nix/store/c6f52mvbv0d8rd3rlslsvy7v4g3pmm7p-glibc-2.35-163/lib/libc.so.6 (0x00007f3319e41000)
    /nix/store/c6f52mvbv0d8rd3rlslsvy7v4g3pmm7p-glibc-2.35-163/lib/ld-linux-x86-64.so.2 => /nix/store/c6f52mvbv0d8rd3rlslsvy7v4g3pmm7p-glibc-2.35-163/lib64/ld-linux-x86-64.so.2 (0x00007f331a136000)

Not being able to load libssl, the application runtime then just goes through a list of known paths to find the certificate store. None of them are where nix places its bundle symbolic link into the nix store.

newfstatat(AT_FDCWD, "/etc/ssl/certs/ca-certificates.crt", 0x7ffd42492e20, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/etc/ssl/ca-bundle.pem", 0x7ffd42492e20, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/etc/pki/tls/certs/ca-bundle.crt", 0x7ffd42492e20, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/share/ssl/certs/ca-bundle.crt", 0x7ffd42492e20, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/etc/pki/tls/certs", 0x7ffd42492e20, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/data/data/com.termux/files/usr/etc/tls/cert.pem", 0x7ffd42492e20, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/system/etc/security/cacerts", 0x7ffd42492e20, 0) = -1 ENOENT (No such file or directory)
write(1, "fetching token failed: No SSL/TL"..., 57fetching token failed: No SSL/TLS CA certificates found.

I changed the nitter-run startup script to create a symbolic link to where the nix cacert package places its link (so a link to a link to the nix store):

#!/bin/sh
ln -s /etc/ssl/certs/ca-bundle.crt /etc/ssl/ca-bundle.pem
echo "Starting Nitter"
exec nitter

..and now Nitter starts up and works! This is obviously a hack solution. I'll try to find a solution to the nitter nix package and submit a pull request.

djsumdog
  • 2,560
  • 1
  • 29
  • 55