Random texts

Hubzilla

#Hubzilla is a jack-of-all-trades. It's a cloud storage, allows pictures, blogging, allows staying in contact with others. The privacy controls are top-notch. It even has pretty much automated channel migration between hubs if you want to move to another server.

Mastodon probably didn't even notice Hubzilla as it steamrolled past Hubzilla's usage numbers and became the de-facto standard. At least it's also using a public protocol, so Hubzilla can exchange messages. I registered on a private Mastodon server a while back to join that community.

Then I had to share a bunch (>1000) pictures with someone and had a closer look at the cloud storage implementation in Hubzilla. It does the job, but the user experience wasn't that great and it was too complicated for my father. I set up Nextcloud a while back to share files, he's happily using it on his own. Only sent him a username and password and asked him to change the password. Pictures are just files and Nextcloud even allows viewing them on a map.

So it's just some blogging left for Hubzilla. Well, until I saw Writefreely. If I set the Firefox Developer Tools to throttle the download speed to GPRS, my channel page takes more than 60 seconds to load. Writefreely is at about 30 seconds and it responds notably faster. Writefreely's interface is a lot more basic, but it offers RSS and ActivityPub subscriptions, which is more than most blogs do.

The only thing left is reading RSS feeds. That never worked well for me, feeds were only updated every couple of weeks and I never figured out why. As far as I can tell it has something to do with my Hubzilla setup and works fine on other hubs. I've used selfoss for maybe 3 years and have recently switched to FreshRSS, so I never used Hubzilla for that.

I've replaced all my needs with other tools now, so I'll be shutting down my hubzilla server soon.

Thank you Hubzilla and thank you Hubzilla Devs, it's awesome what you managed to do.

NOTE: This text describes how I set up #Hubzilla on #NixOS. As I'm no longer using Hubzilla, I've just copied this text over for archival purposes.

PHP webapplications usually ignore all sensible conventions that exist in the unix world. Your typical php webservice needs to be put directly into the document root or a subdirectory of the webserver. That's not a big deal if it is completely static. But usually it is not, it typically needs a somewhat static config.php containing a database password, it may need a temporary directory, a log directory and maybe another directory for long-term storage. This is bad, because you can't just change a link to point to a different version. This is bad in terms of security because the program must reside in a writeable directory. This is bad because config.php with your precious database password is in a directory that's readable by the webserver. Typically you have another problem: all php webservices share a common user that they run as.

NixOS and its package manager Nix completely clashes with that. All derivations are put into /nix/store world-readable and immutable. There's no place for a config.php with a database password in /nix/store. Even root cannot write to /nix/store. The distinction between application and data is enforced by NixOS. You could put the webapplication into /srv/www or a similar directory, but you would lose all of the features that make Nix so good. Instead there's no other sensible option than to split the webapplication into the program and data part. The trick is to set symlinks during the build. I'm going to use hubzilla as an obvious example here.

Building Hubzilla with Nix

Nix first needs some generic information about how and where to download Hubzilla:

{ stdenv, lib, fetchgit, php, dataDir ? null }:
stdenv.mkDerivation rec {
  name = "hubzilla-${version}";
  version = "3.6.1";
  rev = "${version}";

  src = fetchgit {
    inherit rev;
    url = "https://framagit.org/hubzilla/core.git";
    sha256 = "1zaczw4mxxbv7p6xmmf8wpy54jmnf980yd21c4kfncmh3ri0mrf6";
  };

  nativeBuildInputs = [ php ];

  phases = [ "unpackPhase" "installPhase" ];
  installPhase = ''
    cp -Rp ./ $out/
    cd "$out"
    echo Building documentation...
    TEMP=$(mktemp -d)
    ln -s $TEMP/store $out/store
    mkdir -p "$TEMP/store/[data]/smarty3"
    php util/importdoc
    rm -rf "$out/store" "$TEMP/store"
    ${lib.optionalString (dataDir != null) ''
      ln -s ${dataDir}/htconfig.php $out/.htconfig.php
      ln -s ${dataDir}/addon $out/addon
      ln -s ${dataDir}/extend $out/extend
      ln -s ${dataDir}/store $out/store
      mv $out/view/theme $out/view/theme.dist
      ln -s ${dataDir}/view/theme $out/view/theme
      ln -s ${dataDir}/widget $out/widget
    ''}
  '';
}

If you store the above code in default.nix and build it with nix-build -E 'with import <nixpkgs> { }; callPackage ./default.nix { }', you already get the hubzilla source in a /nix/store and even updated documentation in there. Not special so far. Try to build it with nix-build -E 'with import <nixpkgs> { }; callPackage ./default.nix { dataDir = "/var/lib/hubzilla" }'. Now you get a special version that expects its writeable directories and config file in /var/lib/hubzilla. Everytime you change that directory you obviously get a new derivation in /nix/store. The nice thing about this is that a version upgrade is just a change of the version number in the file and thus rollbacks should work – as long as the database is not upgraded. I also like that I can give the dataDir permissions that forbid the webserver any access. Only the php processes can access dataDir.

I haven't noticed any downsides yet, but I haven't delved into themes or addons yet, so there may be some issues later.