A Working Instance of Nitter on NixOS
With all of the various user and developer-hostile changes introduced to Twitter over the past year, the importance of a user-friendly alternative frontend for Twitter is greater than ever.
After using public instances of Nitter for a while, I wanted to try hosting my own instance. I thought it would be as simple as enabling a service in my NixOS configuration:
{
services.nitter.enable = true;
}
Unfortunately, the only builds of Nitter that currently work are taken from a feature development branch which introduces changes both in build-time dependencies and runtime dependencies. You can read the full issue for the details (including how to generate guest accounts, which you’ll need later).
Here are my steps if you want to have a working instance of Nitter running on your NixOS server as of early November 2023:
{
services.nitter = {
enable = true;
package = pkgs.nitter.overrideAttrs (old: {
version = "guest_accounts";
src = pkgs.fetchFromGitHub {
owner = "zedeus";
repo = "nitter";
rev = "eaedd2aee7be6bc3dd2dceee09dc93052d0046f4";
hash = "sha256-px0wyCYiI03DefIIF9+Xr95ChyASvg9N//cARFyRM5I=";
};
buildInputs =
old.buildInputs
++ [
(pkgs.nimPackages.buildNimPackage
rec {
pname = "oauth";
version = "b8c163b0d9cfad6d29ce8c1fb394e5f47182ee1c";
src = pkgs.fetchFromGitHub {
owner = "CORDEA";
repo = pname;
rev = version;
sha256 = "0k5slyzjngbdr6g0b0dykhqmaf8r8n2klbkg2gpid4ckm8hg62v5";
};
propagatedBuildInputs = [
(pkgs.nimPackages.buildNimPackage
rec {
pname = "sha1";
version = "92ccc5800bb0ac4865b275a2ce3c1544e98b48bc";
src = pkgs.fetchFromGitHub {
owner = "onionhammer";
repo = pname;
rev = version;
sha256 = "sha256-tWHouIa6AFRmbvJaMsoWKNZX7bzqd3Je1kJ4rVHb+wM=";
};
})
];
})
];
});
server.hostname = "subdomain.your.website";
server.port = <CUSTOM_PORT>;
};
}
In the snippet above we:
- Override the package to point to the latest commit on the
guest_accounts
feature branch - Override the
buildInputs
list to include a new Nitter dependency, theoauth
Nim package and its own dependency, thesha1
Nim package - Set our hostname and a custom port (the default port is likely to clash with other services we may have running)
Next, to make it available on that hostname, we can use Caddy (or Nginx, or whatever else you prefer):
{
services.caddy = {
enable = enableWebServer;
virtualHosts = {
"https://subdomain.your.website".extraConfig = ''
reverse_proxy 127.0.0.1:<CUSTOM_PORT>
'';
};
};
}
- Make sure that you add a matching DNS record in your provider which points to the IP address of your server
Finally, we need to tell Nitter where to find the new runtime dependency, guest_accounts.json
:
{
systemd.services.nitter.serviceConfig.Environment = [
"NITTER_CONF_FILE=/var/lib/private/nitter/nitter.conf"
"NITTER_ACCOUNTS_FILE=/var/lib/private/nitter/guest_accounts.json"
];
}
We do this by overriding the Environment
setting on the systemd
service.
The first entry for NITTER_CONF_FILE
is taken from the source file of the
service,
and the second entry is added by us.
I was doing this in a bit of a rush so I didn’t automate the creation of the
guest_accounts.json
file in /var/lib/private/nitter
. You can also do as I
did and open a root shell with sudo su
on the server, navigate to the
directory and create the guest_accounts.json
file filled with your guest
credentials. (If you can suggest a clean way to provision files in
/var/lib/private/*
directories, please reach out!)
If you’re doing it like I did, the first time you apply the changes that enable
the service, the nitter
service will fail to start because the
guest_accounts.json
file doesn’t exist yet.
No problem. Hit sudo systemctl stop nitter
, ensure that the file is in place,
then sudo systemctl start nitter
again when you’re ready.
If you have any questions you can reach out to me on Twitter and Mastodon.
If you’re interested in what I read to come up with solutions like this one, you can subscribe to my Software Development RSS feed.
If you’d like to watch me writing code while explaining what I’m doing, you can also subscribe to my YouTube channel.
Edit 11/11/2023: Some folks reached out with advice on how to automate the
creation of the guest_accounts.json
secret file; check out this
post
for more info!