Skip to content



Folders and files

Last commit message
Last commit date

Latest commit


Repository files navigation


Forked from Ingo Blechschmidt's excellent Minlogpad.

Live demo at


  • Graphical mode (using TigerVNC/NoVNC) and text mode (using ttyd)
  • Nix flake for easy access of the preconfigured emacs
  • Hot spares for fresh sessions (with emacs already prestarted)
  • Cold spares for already existing sessions (with X, but not emacs, already prestarted)
  • Robust container acquisition – people accessing the same Minlogpad URL will be connected to the same session even in case of bad timing
  • Löb-like nested containers
  • WebDAV access to user files for easy up- and downloading
  • Rudimentary load control (background autoconnect is disabled if server load is high)
  • Building on awesome open source technology: GNU/Linux, Perl, NixOS, TigerVNC, nginx, NoVNC, systemd, dufs
  • AGPLv3+ licensed

Self-hosting the backend

Self-hosting the backend is easiest if you are running NixOS. This is not strictly necessary though, instructions for self-hosting the backend on any flavor of Linux will be forthcoming.

Instructions for a quick minlog session

  1. Install nix from

  2. Run the preconfigured emacs on your favorite minlogfile

    $ nix run github:vherrmann/minlogpad -- \$FILE

Instructions for a quick non-permanent setup

  1. Create and start the container:

    $ sudo nixos-container create flake-test --flake ./
    $ nixos-container start box
  2. Inside the container, create the directory /home/.skeleton so that the scripts know that everything has been correctly set up. Files put in that directory are copied into the home directory of newly-created sessions.

    $ machinectl shell box mkdir /home/.skeleton
  3. That's it. Test that text-mode access works:

    $ xdg-open http://box:7681/__tty/?arg=CuriousSessionName

    Test that graphical access works:

    $ websocat -E --binary tcp-l: ws://box:6080/__vnc/CuriousSessionName &
    $ vncviewer localhost:1

    There will also be a webserver running at http://box/. However, do not expect this to work -- browsers establish websocket connections only over TLS.

Instructions for a permanent setup

  1. Create a directory in which the homes of all Minlogpad sessions will be stored, for instance /minlogpad-homes.

  2. Populate the directory /minlogpad-homes/.skeleton as you wish, for instance put exercise files there which you want to be available in every session. This directory may also be empty, but it has to exist.

  3. Add this to your /etc/nixos/configuration.nix:

    users.users.guest = { isNormalUser = true; description = "Guest"; home = "/minlogpad-homes"; uid = 995; }; = {
      config =
        { config, pkgs, ... }:
        { imports = [ /tmp/minlogpad/backend/container.nix ]; };
      ephemeral = true;
      autoStart = true;
      privateNetwork = true;
      hostAddress = "";
      localAddress = "";
      bindMounts = { "/home" = { hostPath = "/minlogpad-homes"; isReadOnly = false; }; };
  4. Switch to the new configuration.

Reverse proxying for TLS support

Add something like this to the http block in your nginx.conf to redirect traffic (including https traffic) to the host to the container.

# important to prevent annoying reconnects
proxy_send_timeout 600;
proxy_read_timeout 600;

proxy_http_version 1.1;

server {
    listen [::]:80;
    location /.well-known/acme-challenge {
        root /var/lib/acme/acme-challenge;
        auth_basic off;
    location / {
        return 301 https://$host$request_uri;

server {
    listen ssl http2;
    listen [::]:443 ssl http2;
    location /.well-known/acme-challenge {
        root /var/lib/acme/acme-challenge;
        auth_basic off;
    ssl_certificate /var/lib/acme/;
    ssl_certificate_key /var/lib/acme/;
    ssl_trusted_certificate /var/lib/acme/;
    location / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

If you are running NixOS, these settings can be achieved by the following entry to /etc/nixos/configuration.nix.

services.nginx = {
  enable = true;
  recommendedTlsSettings = true;
  recommendedOptimisation = true;
  appendHttpConfig = ''
     # important to prevent annoying reconnects
     proxy_send_timeout 600;
     proxy_read_timeout 600;
     proxy_http_version 1.1;
  virtualHosts."" = {
    forceSSL = true;
    enableACME = true;
    locations."/" = {
      proxyPass = "";
      proxyWebsockets = true;


  • Browsers support websockets only over https. Hence for testing the frontend, you will have to set up a https reverse proxy.

  • The scripts check for the presence of the directory /home/.skeleton (in the container) to gauge whether /home has been set up correctly.

  • If you encounter weird problems, check that the permissions in /home/.skeleton are set correctly.

  • Because of the nested containers, you may run into limitations regarding open filehandles. Lift these limitations by something like:

    boot.kernel.sysctl = {
      "fs.inotify.max_user_watches" = 163840;
      "fs.inotify.max_user_instances" = 2048;
      "fs.file-max" = 655360;


  • We use our own build of ttyd because the version provided in nixpkgs doesn't compile the html bundle from source, instead using a prepackaged binary blob for convenience (pull request awaiting review). We want to patch the html a bit to better tailor it to our needs (disable the confirmation dialog when leaving the site and beautifying the title bar).

To do

  • bundle and minify JS
  • upload and download buttons
  • virtual keypad on mobile
  • system image for offline work
  • ssh access
  • document viewonly mode
  • document /dufs/foo/bar.scm http read-only access and read-write access using WebDAV


Minlog as a collaborative multiplayer game






No releases published


No packages published


  • JavaScript 32.9%
  • Nix 19.6%
  • HTML 18.1%
  • Perl 13.0%
  • Emacs Lisp 9.9%
  • Shell 3.7%
  • Other 2.8%