{ "id": "https://ryan.freumh.org/remarkable2.html", "title": "Hacking on the Remarkable 2", "link": "https://ryan.freumh.org/remarkable2.html", "updated": "2023-06-07T00:00:00", "published": "2022-12-17T00:00:00", "summary": "
\n \n Published 17 Dec 2022.\n \n \n Last update 7 Jun 2023.\n \n
\n \n \n\n

I’ve recently had the good fortune to come into\npossession of a reMarkable 2 E-Ink\nwriting tablet. This device runs a modified version of Linux, and\ncontains the following message in the copyrights and licenses\ninformation:

\n
\n

GPLv3 Compliance

\n

The General Public License version\n3 and the Lesser General Public License version 3 also requires you as\nan end-user to be able to access your device to be able to modify the\ncopyrighted software licensed under these licenses running on\nit.

\n

To do so, this device acts as an\nUSB ethernet device, and you can connect using the SSH protocol using\nthe username ‘root’ and the password ‘<password>’.

\n
\n

As a result of this, there is a\nvibrant community of hacking for the remarkable. This blog post will\nwalk through the hacks I’ve done on my device.

\n

SSH

\n

As implied in the GPLv3 Compliance statement,\none can SSH into a reMarkable 2 using the Remote Network Driver\nInterface Specification (RNDIS) protocol for Ethernet over USB. The\ndropbear SSH server version v2019.78 shipped appears to only work with\nRSA keys, so if you’re running openssh 8.8 or greater this needs added\nto your SSH configuration (either globally or under a specific host for\nthe reMarkable):

\n
PubkeyAcceptedKeyTypes +ssh-rsa\nHostKeyAlgorithms +ssh-rsa
\n

See also:

\n\n

Once we’re on here, we’re presented with a\nfriendly bash shell:

\n
$ ssh root@10.11.99.1\nreMarkable\n╺━┓┏━╸┏━┓┏━┓   ┏━┓╻ ╻┏━╸┏━┓┏━┓\n┏━┛┣╸ ┣┳┛┃ ┃   ┗━┓┃ ┃┃╺┓┣━┫┣┳┛\n┗━╸┗━╸╹┗╸┗━┛   ┗━┛┗━┛┗━┛╹ ╹╹┗╸\nreMarkable: ~/ ls\nlog.txt\nreMarkable: ~/ ls /\nbin             lib             postinst        tmp\nboot            lost+found      proc            uboot-postinst\ndev             media           run             usr\netc             mnt             sbin            var\nhome            opt             sys
\n

Remote Access

\n

I don’t want to have to be constantly\nplugging my device in, though. We can SSH in over the local network, but\ndealing with firewalling networks or NAT punching across the Internet is\na pain. Instead, we can install a VPN on the reMarkable 2. I installed\ntailscale, but another would work.\nThe headscale OSS\ncontrol server, or just plain WireGuard, would be something to\nlook at.

\n

Toltec is a package repository for\nthe reMarkable. It leverages the Entware package repository and package\nmanager for embedded devices. We can install toltec with:

\n
reMarkable: ~/ wget http://toltec-dev.org/bootstrap\nreMarkable: ~/ echo "04a28483286f88c5c7f39e352afb62adc57f6162a29fd7e124d832205bb0980e  bootstrap" | sha256sum -c && bash bootstrap
\n

(I dislike running random curled bash\nscripts, but when in Rome…)

\n

We can then install tailscale with\ntoltec and set up a systemd service:

\n
reMarkable: ~/ opkg install tailscale\nreMarkable: ~/ cat "[Unit]\nAfter=network.target\nDescription=Tailscale client daemon\nStartLimitBurst=0\nStartLimitIntervalSec=0\nWants=network.target\n[Service]\nEnvironment="HOME=/home/root"\nExecStart=/opt/bin/tailscaled --tun=userspace-networking --state=/opt/var/tailscaled.state\nExecStartPost=/opt/bin/tailscale up\nRestart=on-failure\nRestartSec=5\n[Install]\nWantedBy=multi-user.target" > /lib/systemd/system/tailscaled.service\nreMarkable: ~/ systemctl enable --now tailscaled
\n

NB\n--tun=userspace-networking is required as the reMarkable\ndoesn’t have modules for kernel space networking.

\n

Now we can access our device pretty\nmuch anywhere we have an uplink:

\n
$ ssh root@100.125.211.7\nreMarkable\n╺━┓┏━╸┏━┓┏━┓   ┏━┓╻ ╻┏━╸┏━┓┏━┓\n┏━┛┣╸ ┣┳┛┃ ┃   ┗━┓┃ ┃┃╺┓┣━┫┣┳┛\n┗━╸┗━╸╹┗╸┗━┛   ┗━┛┗━┛┗━┛╹ ╹╹┗╸\nreMarkable: ~/
\n

See:

\n\n

Syncing

\n

Using the USB\nnetworking, there is a web interface\nfor the reMarkable. This allows you to upload and download files from\nthe device. However, as we’ve said, we want to be able to interact with\nthis device without having to plug it in all the time. I tried to proxy\nthis web interface remotely, but didn’t meet with much\nsuccess.

\n

Going back to our SSH connection: we can\nSCP files over. But the reMarkable uses a custom directory\nlayout and file formats in\n/home/root/.local/share/remarkable/xochitl. There is a script\nto copy PDF or EPUB files into this format, but it will not sync them\nback. We could look at using syncthing, or\neven version controlling using git, but this\ndirectory structure is still not the most useable format for\nus.

\n

ReMarkable has a cloud service that would\nsolve this problem for us. However, I don’t particularly want to hand\npotentially sensitive documents over to this company, there are\nrestrictions placed on the size and temporality of documents without a\nsubscription (which I also would rather not pay for - being a\nprice-sensitive PhD student), and I would be reliant on a provider that\ncould cancel their service at any time.

\n

Thankfully there is an open source clone of\nthe reMarkable cloud, rmfakecloud. I deployed\nthis on my existing NixOS server with:

\n
services.rmfakecloud = {\n  enable = true;\n  storageUrl = "https://${cfg.domain}";\n  port = cfg.port;\n  environmentFile = "${config.custom.secretsDir}/rmfakecloud.env";\n  extraSettings = {\n    RM_SMTP_SERVER = "mail.freumh.org:465";\n    RM_SMTP_USERNAME = "misc@${domain}";\n    RM_SMTP_FROM="remarkable@${domain}";\n  };\n};\n\nmailserver.loginAccounts."misc@${domain}".aliases = [ "remarkable@${domain}" ];\n\n# nginx handles letsencrypt\nservices.nginx = {\n  enable = true;\n  recommendedProxySettings = true;\n  # to allow syncing\n  # another option would just be opening a separate port for this\n  clientMaxBodySize = "100M";\n  virtualHosts."${cfg.domain}" = {\n    forceSSL = true;\n    enableACME = true;\n    locations."/".proxyPass = ''\n      http://localhost:${builtins.toString cfg.port}\n    '';\n  };\n};\n\ndns.records = [\n  {\n    name = "rmfakecloud";\n    type = "CNAME";\n    data = "vps";\n  }\n];
\n

Which sets up the rmfakecloud service, a\nHTTP proxy, a mail alias, and DNS records1.\nSee the full module at rmfakecloud.nix.

\n

Note the\nclientMaxBodySize = \"100M\";. I can across an issue where my\nnginx proxy was limiting the maximum body size of a request to 10MB\npreventing the sync service from transferring blobs of around\n30MB:

\n
$ journalctl -u nginx\n...\nDec 16 18:33:41 vps nginx[194956]: 2022/12/16 18:33:41 [error] 194956#194956: *521 client intended to send too large body: 32902724 bytes, client: 131.111.5.246, server: rmfakecloud.freumh.org, request: "PUT /blobstorage?blobid=d245bbed373b5f051c66c567201b5f06875f2714a509d6c69e0f759>\nDec 16 18:33:42 vps nginx[194956]: 2022/12/16 18:33:42 [error] 194956#194956: *521 client intended to send too large body: 32853572 bytes, client: 131.111.5.246, server: rmfakecloud.freumh.org, request: "PUT /blobstorage?blobid=d245bbed373b5f051c66c567201b5f06875f2714a509d6c69e0f759>\nDec 16 18:33:42 vps nginx[194956]: 2022/12/16 18:33:42 [error] 194956#194956: *521 client intended to send too large body: 32788036 bytes, client: 131.111.5.246, server: rmfakecloud.freumh.org, request: "PUT /blobstorage?blobid=d245bbed373b5f051c66c567201b5f06875f2714a509d6c69e0f759>\n...
\n

I set it to 100MB to be safe. Another\noption, as mentioned, would be to open the service on another port to\navoid the proxy. However this may lead to firewalling issues.

\n

Setting it up on the reMarkable was as\nsimple as:

\n
reMarkable: ~/ opkg install rmfakecloud-proxy\nreMarkable: ~/ rmfakecloudctl set-upstream https://rmfakecloud.freumh.org\nreMarkable: ~/ rmfakecloudctl enable
\n

As described at rmfakecloud/docs/remarkable/setup.md.

\n

This allows me to sync all my files to my\nserver, and access them from my device when my reMarkable is offline. It\nalso allows me to email documents with my own mailserver. It even\nsupports handwriting recognition (offloaded to MyScript)

\n

Applications

\n

Xochitl is reMarkable’s proprietary\nGUI for the device. It was xiocthl that imposed the directory layout\nfrom the previous section on us.

\n

There are a wealth of other\napplications out there though:

\n\n

All can be installed through toltec.\nHowever, we need some way to switch between them. There are 3 launchers\nfor the reMarkable. All of them rely on remarkable2-framebuffer\nto render. This, in turn, relies on certain functions from Xochitl to do\nthis. As Xochitl is a binary blob their locations need to be\nreverse-engineered, and likely change every update. This was the cause\nof an error I observed when trying to install a launcher:

\n
Dec 16 23:39:06 reMarkable systemd[1]: Starting reMarkable 2 Framebuffer Server...\nDec 16 23:39:06 reMarkable xochitl[737]: STARTING RM2FB\nDec 16 23:39:06 reMarkable xochitl[737]: Missing address for function 'getInstance'\nDec 16 23:39:06 reMarkable xochitl[737]: PLEASE SEE https://github.com/ddvk/remarkable2-framebuffer/issues/18
\n

Duly following instructions, I decompiled\nmy version\nto find these addresses:

\n
!20220929180236\nversion str 2.14.4.46\nupdate addr 0x4c0a0c\nupdateType str QRect\ncreate addr 0x4c3630\nshutdown addr 0x4c35c8\nwait addr 0x4c25d0\ngetInstance addr 0x4b7594
\n

I could then install remux.

\n

That’s all!

\n

Hopefully this will prove useful to\nsomeone out there.

\n\n\n

2022-01-17 Updated: HTML

\n

I’ve frequently found myself wanting\nto read long-form HTML documents from various web sources like blogs on\nmy device. The simplest option here is to simply print said document to\na PDF file with a browser, transfer it to the device, and read and\nannotate it like any other PDF. However, this is quite restrictive in\nterms of the reading format (it restricts the reading-time text size and\npagination).

\n

An alternative I found useful was to\nsimply SCP the HTML file over and read it with KOReader, which has\nsupport for HTML. We’re able to SCP the file as KOReader doesn’t use the\nxiocthl file format. However, this means annotations aren’t\npossible.

\n

The final thing I tried was installing\na full web browser on the reMarkable, for the hell of it. I use a fork of NetSurf installed with\ntoltec, which works surprisingly well! I’m sticking with\nthe first two options for now though: typing in NetSurf with a stylus is\na pain.

\n

2023-04-28 Updated: VPN

\n

I enabled a headscale control\nserver for tailscale with the following NixOS module on my\nVPS:

\n
{ pkgs, config, lib, ... }:\n\nlet\n  cfg = config.eilean;\nin {\n  options.eilean.headscale = with lib; {\n    enable = mkEnableOption "headscale";\n    zone = mkOption {\n      type = types.str;\n      default = "${config.networking.domain}";\n    };\n    domain = mkOption {\n      type = types.str;\n      default = "headscale.${config.networking.domain}";\n    };\n  };\n\n  config = lib.mkIf cfg.headscale.enable {\n    services.headscale = {\n      enable = true;\n      # address = "127.0.0.1";\n      port = 10000;\n      serverUrl = "https://${cfg.headscale.domain}";\n      dns = {\n        # magicDns = true;\n        nameservers = config.networking.nameservers;\n        baseDomain = "${cfg.headscale.zone}";\n      };\n      settings = {\n        logtail.enabled = false;\n        ip_prefixes = [ "100.64.0.0/10" ];\n      };\n    };\n\n    services.nginx.virtualHosts.${cfg.headscale.domain} = {\n      forceSSL = true;\n      enableACME = true;\n      locations."/" = {\n        proxyPass = with config.services.headscale;\n          "http://${address}:${toString port}";\n        proxyWebsockets = true;\n      };\n    };\n\n    environment.systemPackages = [ config.services.headscale.package ];\n\n    dns.zones.${cfg.headscale.zone}.records = [\n      {\n        name = "${cfg.headscale.domain}.";\n        type = "CNAME";\n        data = "vps";\n      }\n    ];\n  };\n}
\n

(See github.com/RyanGibb/eilean-nix/blob/7383eb/modules/headscale.nix)

\n

To initialize a namespace, on the\nserver we run:

\n
headscale namespaces create <namespace_name>
\n

Then on our remarkable we can\nrun:

\n
$ sudo /opt/bin/tailscale up --login-server headscale.freumh.org --hostname remarkable
\n

Which will give us a URL to a webpage\nthat gives a command to register the device, which will look something\nlike:

\n
headscale --namespace <namespace_name> nodes register --key <machine_key>
\n

And now we’re in!

\n\n\n\n\n
    \n
  1. See github.com/RyanGibb/eilean-nix/tree/0b4213/modules/dns/default.nix↩︎

  2. \n
", "content": "
\n \n Published 17 Dec 2022.\n \n \n Last update 7 Jun 2023.\n \n
\n \n \n\n

I’ve recently had the good fortune to come into\npossession of a reMarkable 2 E-Ink\nwriting tablet. This device runs a modified version of Linux, and\ncontains the following message in the copyrights and licenses\ninformation:

\n
\n

GPLv3 Compliance

\n

The General Public License version\n3 and the Lesser General Public License version 3 also requires you as\nan end-user to be able to access your device to be able to modify the\ncopyrighted software licensed under these licenses running on\nit.

\n

To do so, this device acts as an\nUSB ethernet device, and you can connect using the SSH protocol using\nthe username ‘root’ and the password ‘<password>’.

\n
\n

As a result of this, there is a\nvibrant community of hacking for the remarkable. This blog post will\nwalk through the hacks I’ve done on my device.

\n

SSH

\n

As implied in the GPLv3 Compliance statement,\none can SSH into a reMarkable 2 using the Remote Network Driver\nInterface Specification (RNDIS) protocol for Ethernet over USB. The\ndropbear SSH server version v2019.78 shipped appears to only work with\nRSA keys, so if you’re running openssh 8.8 or greater this needs added\nto your SSH configuration (either globally or under a specific host for\nthe reMarkable):

\n
PubkeyAcceptedKeyTypes +ssh-rsa\nHostKeyAlgorithms +ssh-rsa
\n

See also:

\n\n

Once we’re on here, we’re presented with a\nfriendly bash shell:

\n
$ ssh root@10.11.99.1\nreMarkable\n╺━┓┏━╸┏━┓┏━┓   ┏━┓╻ ╻┏━╸┏━┓┏━┓\n┏━┛┣╸ ┣┳┛┃ ┃   ┗━┓┃ ┃┃╺┓┣━┫┣┳┛\n┗━╸┗━╸╹┗╸┗━┛   ┗━┛┗━┛┗━┛╹ ╹╹┗╸\nreMarkable: ~/ ls\nlog.txt\nreMarkable: ~/ ls /\nbin             lib             postinst        tmp\nboot            lost+found      proc            uboot-postinst\ndev             media           run             usr\netc             mnt             sbin            var\nhome            opt             sys
\n

Remote Access

\n

I don’t want to have to be constantly\nplugging my device in, though. We can SSH in over the local network, but\ndealing with firewalling networks or NAT punching across the Internet is\na pain. Instead, we can install a VPN on the reMarkable 2. I installed\ntailscale, but another would work.\nThe headscale OSS\ncontrol server, or just plain WireGuard, would be something to\nlook at.

\n

Toltec is a package repository for\nthe reMarkable. It leverages the Entware package repository and package\nmanager for embedded devices. We can install toltec with:

\n
reMarkable: ~/ wget http://toltec-dev.org/bootstrap\nreMarkable: ~/ echo "04a28483286f88c5c7f39e352afb62adc57f6162a29fd7e124d832205bb0980e  bootstrap" | sha256sum -c && bash bootstrap
\n

(I dislike running random curled bash\nscripts, but when in Rome…)

\n

We can then install tailscale with\ntoltec and set up a systemd service:

\n
reMarkable: ~/ opkg install tailscale\nreMarkable: ~/ cat "[Unit]\nAfter=network.target\nDescription=Tailscale client daemon\nStartLimitBurst=0\nStartLimitIntervalSec=0\nWants=network.target\n[Service]\nEnvironment="HOME=/home/root"\nExecStart=/opt/bin/tailscaled --tun=userspace-networking --state=/opt/var/tailscaled.state\nExecStartPost=/opt/bin/tailscale up\nRestart=on-failure\nRestartSec=5\n[Install]\nWantedBy=multi-user.target" > /lib/systemd/system/tailscaled.service\nreMarkable: ~/ systemctl enable --now tailscaled
\n

NB\n--tun=userspace-networking is required as the reMarkable\ndoesn’t have modules for kernel space networking.

\n

Now we can access our device pretty\nmuch anywhere we have an uplink:

\n
$ ssh root@100.125.211.7\nreMarkable\n╺━┓┏━╸┏━┓┏━┓   ┏━┓╻ ╻┏━╸┏━┓┏━┓\n┏━┛┣╸ ┣┳┛┃ ┃   ┗━┓┃ ┃┃╺┓┣━┫┣┳┛\n┗━╸┗━╸╹┗╸┗━┛   ┗━┛┗━┛┗━┛╹ ╹╹┗╸\nreMarkable: ~/
\n

See:

\n\n

Syncing

\n

Using the USB\nnetworking, there is a web interface\nfor the reMarkable. This allows you to upload and download files from\nthe device. However, as we’ve said, we want to be able to interact with\nthis device without having to plug it in all the time. I tried to proxy\nthis web interface remotely, but didn’t meet with much\nsuccess.

\n

Going back to our SSH connection: we can\nSCP files over. But the reMarkable uses a custom directory\nlayout and file formats in\n/home/root/.local/share/remarkable/xochitl. There is a script\nto copy PDF or EPUB files into this format, but it will not sync them\nback. We could look at using syncthing, or\neven version controlling using git, but this\ndirectory structure is still not the most useable format for\nus.

\n

ReMarkable has a cloud service that would\nsolve this problem for us. However, I don’t particularly want to hand\npotentially sensitive documents over to this company, there are\nrestrictions placed on the size and temporality of documents without a\nsubscription (which I also would rather not pay for - being a\nprice-sensitive PhD student), and I would be reliant on a provider that\ncould cancel their service at any time.

\n

Thankfully there is an open source clone of\nthe reMarkable cloud, rmfakecloud. I deployed\nthis on my existing NixOS server with:

\n
services.rmfakecloud = {\n  enable = true;\n  storageUrl = "https://${cfg.domain}";\n  port = cfg.port;\n  environmentFile = "${config.custom.secretsDir}/rmfakecloud.env";\n  extraSettings = {\n    RM_SMTP_SERVER = "mail.freumh.org:465";\n    RM_SMTP_USERNAME = "misc@${domain}";\n    RM_SMTP_FROM="remarkable@${domain}";\n  };\n};\n\nmailserver.loginAccounts."misc@${domain}".aliases = [ "remarkable@${domain}" ];\n\n# nginx handles letsencrypt\nservices.nginx = {\n  enable = true;\n  recommendedProxySettings = true;\n  # to allow syncing\n  # another option would just be opening a separate port for this\n  clientMaxBodySize = "100M";\n  virtualHosts."${cfg.domain}" = {\n    forceSSL = true;\n    enableACME = true;\n    locations."/".proxyPass = ''\n      http://localhost:${builtins.toString cfg.port}\n    '';\n  };\n};\n\ndns.records = [\n  {\n    name = "rmfakecloud";\n    type = "CNAME";\n    data = "vps";\n  }\n];
\n

Which sets up the rmfakecloud service, a\nHTTP proxy, a mail alias, and DNS records1.\nSee the full module at rmfakecloud.nix.

\n

Note the\nclientMaxBodySize = \"100M\";. I can across an issue where my\nnginx proxy was limiting the maximum body size of a request to 10MB\npreventing the sync service from transferring blobs of around\n30MB:

\n
$ journalctl -u nginx\n...\nDec 16 18:33:41 vps nginx[194956]: 2022/12/16 18:33:41 [error] 194956#194956: *521 client intended to send too large body: 32902724 bytes, client: 131.111.5.246, server: rmfakecloud.freumh.org, request: "PUT /blobstorage?blobid=d245bbed373b5f051c66c567201b5f06875f2714a509d6c69e0f759>\nDec 16 18:33:42 vps nginx[194956]: 2022/12/16 18:33:42 [error] 194956#194956: *521 client intended to send too large body: 32853572 bytes, client: 131.111.5.246, server: rmfakecloud.freumh.org, request: "PUT /blobstorage?blobid=d245bbed373b5f051c66c567201b5f06875f2714a509d6c69e0f759>\nDec 16 18:33:42 vps nginx[194956]: 2022/12/16 18:33:42 [error] 194956#194956: *521 client intended to send too large body: 32788036 bytes, client: 131.111.5.246, server: rmfakecloud.freumh.org, request: "PUT /blobstorage?blobid=d245bbed373b5f051c66c567201b5f06875f2714a509d6c69e0f759>\n...
\n

I set it to 100MB to be safe. Another\noption, as mentioned, would be to open the service on another port to\navoid the proxy. However this may lead to firewalling issues.

\n

Setting it up on the reMarkable was as\nsimple as:

\n
reMarkable: ~/ opkg install rmfakecloud-proxy\nreMarkable: ~/ rmfakecloudctl set-upstream https://rmfakecloud.freumh.org\nreMarkable: ~/ rmfakecloudctl enable
\n

As described at rmfakecloud/docs/remarkable/setup.md.

\n

This allows me to sync all my files to my\nserver, and access them from my device when my reMarkable is offline. It\nalso allows me to email documents with my own mailserver. It even\nsupports handwriting recognition (offloaded to MyScript)

\n

Applications

\n

Xochitl is reMarkable’s proprietary\nGUI for the device. It was xiocthl that imposed the directory layout\nfrom the previous section on us.

\n

There are a wealth of other\napplications out there though:

\n\n

All can be installed through toltec.\nHowever, we need some way to switch between them. There are 3 launchers\nfor the reMarkable. All of them rely on remarkable2-framebuffer\nto render. This, in turn, relies on certain functions from Xochitl to do\nthis. As Xochitl is a binary blob their locations need to be\nreverse-engineered, and likely change every update. This was the cause\nof an error I observed when trying to install a launcher:

\n
Dec 16 23:39:06 reMarkable systemd[1]: Starting reMarkable 2 Framebuffer Server...\nDec 16 23:39:06 reMarkable xochitl[737]: STARTING RM2FB\nDec 16 23:39:06 reMarkable xochitl[737]: Missing address for function 'getInstance'\nDec 16 23:39:06 reMarkable xochitl[737]: PLEASE SEE https://github.com/ddvk/remarkable2-framebuffer/issues/18
\n

Duly following instructions, I decompiled\nmy version\nto find these addresses:

\n
!20220929180236\nversion str 2.14.4.46\nupdate addr 0x4c0a0c\nupdateType str QRect\ncreate addr 0x4c3630\nshutdown addr 0x4c35c8\nwait addr 0x4c25d0\ngetInstance addr 0x4b7594
\n

I could then install remux.

\n

That’s all!

\n

Hopefully this will prove useful to\nsomeone out there.

\n\n\n

2022-01-17 Updated: HTML

\n

I’ve frequently found myself wanting\nto read long-form HTML documents from various web sources like blogs on\nmy device. The simplest option here is to simply print said document to\na PDF file with a browser, transfer it to the device, and read and\nannotate it like any other PDF. However, this is quite restrictive in\nterms of the reading format (it restricts the reading-time text size and\npagination).

\n

An alternative I found useful was to\nsimply SCP the HTML file over and read it with KOReader, which has\nsupport for HTML. We’re able to SCP the file as KOReader doesn’t use the\nxiocthl file format. However, this means annotations aren’t\npossible.

\n

The final thing I tried was installing\na full web browser on the reMarkable, for the hell of it. I use a fork of NetSurf installed with\ntoltec, which works surprisingly well! I’m sticking with\nthe first two options for now though: typing in NetSurf with a stylus is\na pain.

\n

2023-04-28 Updated: VPN

\n

I enabled a headscale control\nserver for tailscale with the following NixOS module on my\nVPS:

\n
{ pkgs, config, lib, ... }:\n\nlet\n  cfg = config.eilean;\nin {\n  options.eilean.headscale = with lib; {\n    enable = mkEnableOption "headscale";\n    zone = mkOption {\n      type = types.str;\n      default = "${config.networking.domain}";\n    };\n    domain = mkOption {\n      type = types.str;\n      default = "headscale.${config.networking.domain}";\n    };\n  };\n\n  config = lib.mkIf cfg.headscale.enable {\n    services.headscale = {\n      enable = true;\n      # address = "127.0.0.1";\n      port = 10000;\n      serverUrl = "https://${cfg.headscale.domain}";\n      dns = {\n        # magicDns = true;\n        nameservers = config.networking.nameservers;\n        baseDomain = "${cfg.headscale.zone}";\n      };\n      settings = {\n        logtail.enabled = false;\n        ip_prefixes = [ "100.64.0.0/10" ];\n      };\n    };\n\n    services.nginx.virtualHosts.${cfg.headscale.domain} = {\n      forceSSL = true;\n      enableACME = true;\n      locations."/" = {\n        proxyPass = with config.services.headscale;\n          "http://${address}:${toString port}";\n        proxyWebsockets = true;\n      };\n    };\n\n    environment.systemPackages = [ config.services.headscale.package ];\n\n    dns.zones.${cfg.headscale.zone}.records = [\n      {\n        name = "${cfg.headscale.domain}.";\n        type = "CNAME";\n        data = "vps";\n      }\n    ];\n  };\n}
\n

(See github.com/RyanGibb/eilean-nix/blob/7383eb/modules/headscale.nix)

\n

To initialize a namespace, on the\nserver we run:

\n
headscale namespaces create <namespace_name>
\n

Then on our remarkable we can\nrun:

\n
$ sudo /opt/bin/tailscale up --login-server headscale.freumh.org --hostname remarkable
\n

Which will give us a URL to a webpage\nthat gives a command to register the device, which will look something\nlike:

\n
headscale --namespace <namespace_name> nodes register --key <machine_key>
\n

And now we’re in!

\n\n\n\n\n
    \n
  1. See github.com/RyanGibb/eilean-nix/tree/0b4213/modules/dns/default.nix↩︎

  2. \n
", "content_type": "html", "categories": [], "source": "https://ryan.freumh.org/atom.xml" }