Thicket data repository for the EEG
1{
2 "id": "https://ryan.freumh.org/remarkable2.html",
3 "title": "Hacking on the Remarkable 2",
4 "link": "https://ryan.freumh.org/remarkable2.html",
5 "updated": "2023-06-07T00:00:00",
6 "published": "2022-12-17T00:00:00",
7 "summary": "<div>\n \n <span>Published 17 Dec 2022.</span>\n \n \n <span>Last update 7 Jun 2023.</span>\n \n </div>\n \n \n\n <p><span>I’ve recently had the good fortune to come into\npossession of a <a href=\"https://remarkable.com/store/remarkable-2\">reMarkable 2</a> E-Ink\nwriting tablet. This device runs a modified version of Linux, and\ncontains the following message in the copyrights and licenses\ninformation:</span></p>\n<blockquote>\n<h3>GPLv3 Compliance</h3>\n<p><span>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.</span></p>\n<p><span>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>’.</span></p>\n</blockquote>\n<p><span>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.</span></p>\n<h3>SSH</h3>\n<p><span>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):</span></p>\n<pre><code>PubkeyAcceptedKeyTypes +ssh-rsa\nHostKeyAlgorithms +ssh-rsa</code></pre>\n<p><span>See also:</span></p>\n<ul>\n<li><a href=\"https://remarkablewiki.com/tech/ssh\">https://remarkablewiki.com/tech/ssh</a></li>\n<li><a href=\"https://remarkablewiki.com/tech/usb_network\">https://remarkablewiki.com/tech/usb_network</a></li>\n</ul>\n<p><span>Once we’re on here, we’re presented with a\nfriendly bash shell:</span></p>\n<pre><code>$ 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</code></pre>\n<h3>Remote Access</h3>\n<p><span>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\n<a href=\"https://tailscale.com/\">tailscale</a>, but another would work.\nThe <a href=\"https://github.com/juanfont/headscale\">headscale</a> OSS\ncontrol server, or just plain <a href=\"https://www.wireguard.com/\">WireGuard</a>, would be something to\nlook at.</span></p>\n<p><span><a href=\"https://toltec-dev.org/\">Toltec</a> is a package repository for\nthe reMarkable. It leverages the <a href=\"https://entware.net/\">Entware</a> package repository and package\nmanager for embedded devices. We can install toltec with:</span></p>\n<pre><code>reMarkable: ~/ wget http://toltec-dev.org/bootstrap\nreMarkable: ~/ echo "04a28483286f88c5c7f39e352afb62adc57f6162a29fd7e124d832205bb0980e bootstrap" | sha256sum -c && bash bootstrap</code></pre>\n<p><span>(I dislike running random curled bash\nscripts, but when in Rome…)</span></p>\n<p><span>We can then install tailscale with\ntoltec and set up a systemd service:</span></p>\n<pre><code>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</code></pre>\n<p><span>NB\n<code>--tun=userspace-networking</code> is required as the reMarkable\ndoesn’t have modules for kernel space networking.</span></p>\n<p><span>Now we can access our device pretty\nmuch anywhere we have an uplink:</span></p>\n<pre><code>$ ssh root@100.125.211.7\nreMarkable\n╺━┓┏━╸┏━┓┏━┓ ┏━┓╻ ╻┏━╸┏━┓┏━┓\n┏━┛┣╸ ┣┳┛┃ ┃ ┗━┓┃ ┃┃╺┓┣━┫┣┳┛\n┗━╸┗━╸╹┗╸┗━┛ ┗━┛┗━┛┗━┛╹ ╹╹┗╸\nreMarkable: ~/</code></pre>\n<p><span>See:</span></p>\n<ul>\n<li><a href=\"https://remarkablewiki.com/tips/tailscale\">https://remarkablewiki.com/tips/tailscale</a></li>\n<li><a href=\"https://addcnin.blue/2021/10/26/remarkable-tailscale/\">https://addcnin.blue/2021/10/26/remarkable-tailscale/</a></li>\n</ul>\n<h3>Syncing</h3>\n<p><span>Using the <a href=\"#ssh\">USB\nnetworking</a>, there is a <a href=\"https://remarkablewiki.com/tech/webinterface\">web interface</a>\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.</span></p>\n<p><span>Going back to our SSH connection: we can\nSCP files over. But the reMarkable uses a custom <a href=\"https://remarkablewiki.com/tech/filesystem#user_data_directory_structure\">directory\nlayout and file formats</a> in\n<code>/home/root/.local/share/remarkable/xochitl</code>. There is a <a href=\"https://github.com/adaerr/reMarkableScripts/blob/master/pdf2remarkable.sh\">script</a>\nto copy PDF or EPUB files into this format, but it will not sync them\nback. We could look at using <a href=\"https://github.com/evidlo/remarkable_syncthing\">syncthing</a>, or\neven version controlling using <a href=\"https://github.com/after-eight/regitable\">git</a>, but this\ndirectory structure is still not the most useable format for\nus.</span></p>\n<p><span>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.</span></p>\n<p><span>Thankfully there is an open source clone of\nthe reMarkable cloud, <a href=\"https://github.com/ddvk/rmfakecloud\">rmfakecloud</a>. I deployed\nthis on my existing NixOS server with:</span></p>\n<pre><code>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];</code></pre>\n<p><span>Which sets up the rmfakecloud service, a\nHTTP proxy, a mail alias, and DNS records<a href=\"#fn1\">1</a>.\nSee the full module at <a href=\"https://github.com/RyanGibb/nixos/tree/0b4213b0d234b4b683cbac0cc4e132ca5a6489bb/modules/hosting/rmfakecloud.nix\">rmfakecloud.nix</a>.</span></p>\n<p><span>Note the\n<code>clientMaxBodySize = \"100M\";</code>. 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:</span></p>\n<pre><code>$ 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...</code></pre>\n<p><span>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.</span></p>\n<p><span>Setting it up on the reMarkable was as\nsimple as:</span></p>\n<pre><code>reMarkable: ~/ opkg install rmfakecloud-proxy\nreMarkable: ~/ rmfakecloudctl set-upstream https://rmfakecloud.freumh.org\nreMarkable: ~/ rmfakecloudctl enable</code></pre>\n<p><span>As described at <a href=\"https://github.com/ddvk/rmfakecloud/blob/master/docs/remarkable/setup.md\">rmfakecloud/docs/remarkable/setup.md</a>.</span></p>\n<p><span>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 <a href=\"https://www.myscript.com/\">MyScript</a>)</span></p>\n<h3>Applications</h3>\n<p><span>Xochitl is reMarkable’s proprietary\nGUI for the device. It was xiocthl that imposed the directory layout\nfrom <a href=\"#syncing\">the previous section</a> on us.</span></p>\n<p><span>There are a wealth of other\napplications out there though:</span></p>\n<ul>\n<li><a href=\"https://github.com/koreader/koreader\">KOReader</a> turns\nour device into an oversized ebook reader.</li>\n<li><a href=\"https://github.com/dixonary/fingerterm-reMarkable\">fingerterm</a>\nis a terminal emulator for the device. It means on the go we can fix\nthings and install packages. And it’s cool as hell to have a command\nline on your ‘digital paper’.</li>\n<li><a href=\"https://github.com/dps/remarkable-keywriter\">keywriter</a>\nallows us to write with a keyboard in the sun with our\ndevice[Pending IO issues: <a href=\"https://github.com/dps/remarkable-keywriter/issues/14\">https://github.com/dps/remarkable-keywriter/issues/14</a>][As\nof 2023-04-28 reMarkable have release their own case with a built-in\nkeyboard: <a href=\"https://remarkable.com/store/remarkable-2/type-folio\">remarkable.com/store/remarkable-2/type-folio</a>].</li>\n</ul>\n<p><span>All can be installed through toltec.\nHowever, we need some way to switch between them. There are 3 <a href=\"https://toltec-dev.org/stable/#section-launchers\">launchers</a>\nfor the reMarkable. All of them rely on <a href=\"https://github.com/ddvk/remarkable2-framebuffer\">remarkable2-framebuffer</a>\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:</span></p>\n<pre><code>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</code></pre>\n<p><span>Duly following instructions, I <a href=\"https://github.com/ddvk/remarkable2-framebuffer/blob/b8f381615302eb3922f5ab8f50fd0af14da96f85/tutorial/README.md\">decompiled</a>\nmy <a href=\"https://github.com/ddvk/remarkable2-framebuffer/issues/18#issuecomment-1355861460\">version</a>\nto find these addresses:</span></p>\n<pre><code>!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</code></pre>\n<p><span>I could then install <a href=\"https://rmkit.dev/apps/remux\">remux</a>.</span></p>\n<h3>That’s all!</h3>\n<p><span>Hopefully this will prove useful to\nsomeone out there.</span></p>\n\n\n<h3>2022-01-17 Updated: HTML</h3>\n<p><span>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).</span></p>\n<p><span>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.</span></p>\n<p><span>The final thing I tried was installing\na full web browser on the reMarkable, for the hell of it. I use a <a href=\"https://github.com/alex0809/netsurf-reMarkable\">fork</a> of <a href=\"https://www.netsurf-browser.org/\">NetSurf</a> installed with\n<code>toltec</code>, which works surprisingly well! I’m sticking with\nthe first two options for now though: typing in NetSurf with a stylus is\na pain.</span></p>\n<h3>2023-04-28 Updated: VPN</h3>\n<p><span>I enabled a <a href=\"https://github.com/juanfont/headscale\">headscale</a> control\nserver for tailscale with the following NixOS module on my\nVPS:</span></p>\n<pre><code>{ 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}</code></pre>\n<p><span>(See <a href=\"https://github.com/RyanGibb/eilean-nix/blob/7383eb02798ff04d8a83ee7759393da113f50f79/modules/headscale.nix\">github.com/RyanGibb/eilean-nix/blob/7383eb/modules/headscale.nix</a>)</span></p>\n<p><span>To initialize a namespace, on the\nserver we run:</span></p>\n<pre><code>headscale namespaces create <namespace_name></code></pre>\n<p><span>Then on our remarkable we can\nrun:</span></p>\n<pre><code>$ sudo /opt/bin/tailscale up --login-server headscale.freumh.org --hostname remarkable</code></pre>\n<p><span>Which will give us a URL to a webpage\nthat gives a command to register the device, which will look something\nlike:</span></p>\n<pre><code>headscale --namespace <namespace_name> nodes register --key <machine_key></code></pre>\n<p><span>And now we’re in!</span></p>\n\n\n\n\n<ol>\n<li><p><span>See <a href=\"https://github.com/RyanGibb/eilean-nix/tree/0b4213b0d234b4b683cbac0cc4e132ca5a6489bb/modules/dns/default.nix\">github.com/RyanGibb/eilean-nix/tree/0b4213/modules/dns/default.nix</a></span><a href=\"#fnref1\">↩︎</a></p></li>\n</ol>",
8 "content": "<div>\n \n <span>Published 17 Dec 2022.</span>\n \n \n <span>Last update 7 Jun 2023.</span>\n \n </div>\n \n \n\n <p><span>I’ve recently had the good fortune to come into\npossession of a <a href=\"https://remarkable.com/store/remarkable-2\">reMarkable 2</a> E-Ink\nwriting tablet. This device runs a modified version of Linux, and\ncontains the following message in the copyrights and licenses\ninformation:</span></p>\n<blockquote>\n<h3>GPLv3 Compliance</h3>\n<p><span>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.</span></p>\n<p><span>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>’.</span></p>\n</blockquote>\n<p><span>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.</span></p>\n<h3>SSH</h3>\n<p><span>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):</span></p>\n<pre><code>PubkeyAcceptedKeyTypes +ssh-rsa\nHostKeyAlgorithms +ssh-rsa</code></pre>\n<p><span>See also:</span></p>\n<ul>\n<li><a href=\"https://remarkablewiki.com/tech/ssh\">https://remarkablewiki.com/tech/ssh</a></li>\n<li><a href=\"https://remarkablewiki.com/tech/usb_network\">https://remarkablewiki.com/tech/usb_network</a></li>\n</ul>\n<p><span>Once we’re on here, we’re presented with a\nfriendly bash shell:</span></p>\n<pre><code>$ 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</code></pre>\n<h3>Remote Access</h3>\n<p><span>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\n<a href=\"https://tailscale.com/\">tailscale</a>, but another would work.\nThe <a href=\"https://github.com/juanfont/headscale\">headscale</a> OSS\ncontrol server, or just plain <a href=\"https://www.wireguard.com/\">WireGuard</a>, would be something to\nlook at.</span></p>\n<p><span><a href=\"https://toltec-dev.org/\">Toltec</a> is a package repository for\nthe reMarkable. It leverages the <a href=\"https://entware.net/\">Entware</a> package repository and package\nmanager for embedded devices. We can install toltec with:</span></p>\n<pre><code>reMarkable: ~/ wget http://toltec-dev.org/bootstrap\nreMarkable: ~/ echo "04a28483286f88c5c7f39e352afb62adc57f6162a29fd7e124d832205bb0980e bootstrap" | sha256sum -c && bash bootstrap</code></pre>\n<p><span>(I dislike running random curled bash\nscripts, but when in Rome…)</span></p>\n<p><span>We can then install tailscale with\ntoltec and set up a systemd service:</span></p>\n<pre><code>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</code></pre>\n<p><span>NB\n<code>--tun=userspace-networking</code> is required as the reMarkable\ndoesn’t have modules for kernel space networking.</span></p>\n<p><span>Now we can access our device pretty\nmuch anywhere we have an uplink:</span></p>\n<pre><code>$ ssh root@100.125.211.7\nreMarkable\n╺━┓┏━╸┏━┓┏━┓ ┏━┓╻ ╻┏━╸┏━┓┏━┓\n┏━┛┣╸ ┣┳┛┃ ┃ ┗━┓┃ ┃┃╺┓┣━┫┣┳┛\n┗━╸┗━╸╹┗╸┗━┛ ┗━┛┗━┛┗━┛╹ ╹╹┗╸\nreMarkable: ~/</code></pre>\n<p><span>See:</span></p>\n<ul>\n<li><a href=\"https://remarkablewiki.com/tips/tailscale\">https://remarkablewiki.com/tips/tailscale</a></li>\n<li><a href=\"https://addcnin.blue/2021/10/26/remarkable-tailscale/\">https://addcnin.blue/2021/10/26/remarkable-tailscale/</a></li>\n</ul>\n<h3>Syncing</h3>\n<p><span>Using the <a href=\"#ssh\">USB\nnetworking</a>, there is a <a href=\"https://remarkablewiki.com/tech/webinterface\">web interface</a>\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.</span></p>\n<p><span>Going back to our SSH connection: we can\nSCP files over. But the reMarkable uses a custom <a href=\"https://remarkablewiki.com/tech/filesystem#user_data_directory_structure\">directory\nlayout and file formats</a> in\n<code>/home/root/.local/share/remarkable/xochitl</code>. There is a <a href=\"https://github.com/adaerr/reMarkableScripts/blob/master/pdf2remarkable.sh\">script</a>\nto copy PDF or EPUB files into this format, but it will not sync them\nback. We could look at using <a href=\"https://github.com/evidlo/remarkable_syncthing\">syncthing</a>, or\neven version controlling using <a href=\"https://github.com/after-eight/regitable\">git</a>, but this\ndirectory structure is still not the most useable format for\nus.</span></p>\n<p><span>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.</span></p>\n<p><span>Thankfully there is an open source clone of\nthe reMarkable cloud, <a href=\"https://github.com/ddvk/rmfakecloud\">rmfakecloud</a>. I deployed\nthis on my existing NixOS server with:</span></p>\n<pre><code>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];</code></pre>\n<p><span>Which sets up the rmfakecloud service, a\nHTTP proxy, a mail alias, and DNS records<a href=\"#fn1\">1</a>.\nSee the full module at <a href=\"https://github.com/RyanGibb/nixos/tree/0b4213b0d234b4b683cbac0cc4e132ca5a6489bb/modules/hosting/rmfakecloud.nix\">rmfakecloud.nix</a>.</span></p>\n<p><span>Note the\n<code>clientMaxBodySize = \"100M\";</code>. 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:</span></p>\n<pre><code>$ 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...</code></pre>\n<p><span>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.</span></p>\n<p><span>Setting it up on the reMarkable was as\nsimple as:</span></p>\n<pre><code>reMarkable: ~/ opkg install rmfakecloud-proxy\nreMarkable: ~/ rmfakecloudctl set-upstream https://rmfakecloud.freumh.org\nreMarkable: ~/ rmfakecloudctl enable</code></pre>\n<p><span>As described at <a href=\"https://github.com/ddvk/rmfakecloud/blob/master/docs/remarkable/setup.md\">rmfakecloud/docs/remarkable/setup.md</a>.</span></p>\n<p><span>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 <a href=\"https://www.myscript.com/\">MyScript</a>)</span></p>\n<h3>Applications</h3>\n<p><span>Xochitl is reMarkable’s proprietary\nGUI for the device. It was xiocthl that imposed the directory layout\nfrom <a href=\"#syncing\">the previous section</a> on us.</span></p>\n<p><span>There are a wealth of other\napplications out there though:</span></p>\n<ul>\n<li><a href=\"https://github.com/koreader/koreader\">KOReader</a> turns\nour device into an oversized ebook reader.</li>\n<li><a href=\"https://github.com/dixonary/fingerterm-reMarkable\">fingerterm</a>\nis a terminal emulator for the device. It means on the go we can fix\nthings and install packages. And it’s cool as hell to have a command\nline on your ‘digital paper’.</li>\n<li><a href=\"https://github.com/dps/remarkable-keywriter\">keywriter</a>\nallows us to write with a keyboard in the sun with our\ndevice[Pending IO issues: <a href=\"https://github.com/dps/remarkable-keywriter/issues/14\">https://github.com/dps/remarkable-keywriter/issues/14</a>][As\nof 2023-04-28 reMarkable have release their own case with a built-in\nkeyboard: <a href=\"https://remarkable.com/store/remarkable-2/type-folio\">remarkable.com/store/remarkable-2/type-folio</a>].</li>\n</ul>\n<p><span>All can be installed through toltec.\nHowever, we need some way to switch between them. There are 3 <a href=\"https://toltec-dev.org/stable/#section-launchers\">launchers</a>\nfor the reMarkable. All of them rely on <a href=\"https://github.com/ddvk/remarkable2-framebuffer\">remarkable2-framebuffer</a>\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:</span></p>\n<pre><code>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</code></pre>\n<p><span>Duly following instructions, I <a href=\"https://github.com/ddvk/remarkable2-framebuffer/blob/b8f381615302eb3922f5ab8f50fd0af14da96f85/tutorial/README.md\">decompiled</a>\nmy <a href=\"https://github.com/ddvk/remarkable2-framebuffer/issues/18#issuecomment-1355861460\">version</a>\nto find these addresses:</span></p>\n<pre><code>!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</code></pre>\n<p><span>I could then install <a href=\"https://rmkit.dev/apps/remux\">remux</a>.</span></p>\n<h3>That’s all!</h3>\n<p><span>Hopefully this will prove useful to\nsomeone out there.</span></p>\n\n\n<h3>2022-01-17 Updated: HTML</h3>\n<p><span>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).</span></p>\n<p><span>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.</span></p>\n<p><span>The final thing I tried was installing\na full web browser on the reMarkable, for the hell of it. I use a <a href=\"https://github.com/alex0809/netsurf-reMarkable\">fork</a> of <a href=\"https://www.netsurf-browser.org/\">NetSurf</a> installed with\n<code>toltec</code>, which works surprisingly well! I’m sticking with\nthe first two options for now though: typing in NetSurf with a stylus is\na pain.</span></p>\n<h3>2023-04-28 Updated: VPN</h3>\n<p><span>I enabled a <a href=\"https://github.com/juanfont/headscale\">headscale</a> control\nserver for tailscale with the following NixOS module on my\nVPS:</span></p>\n<pre><code>{ 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}</code></pre>\n<p><span>(See <a href=\"https://github.com/RyanGibb/eilean-nix/blob/7383eb02798ff04d8a83ee7759393da113f50f79/modules/headscale.nix\">github.com/RyanGibb/eilean-nix/blob/7383eb/modules/headscale.nix</a>)</span></p>\n<p><span>To initialize a namespace, on the\nserver we run:</span></p>\n<pre><code>headscale namespaces create <namespace_name></code></pre>\n<p><span>Then on our remarkable we can\nrun:</span></p>\n<pre><code>$ sudo /opt/bin/tailscale up --login-server headscale.freumh.org --hostname remarkable</code></pre>\n<p><span>Which will give us a URL to a webpage\nthat gives a command to register the device, which will look something\nlike:</span></p>\n<pre><code>headscale --namespace <namespace_name> nodes register --key <machine_key></code></pre>\n<p><span>And now we’re in!</span></p>\n\n\n\n\n<ol>\n<li><p><span>See <a href=\"https://github.com/RyanGibb/eilean-nix/tree/0b4213b0d234b4b683cbac0cc4e132ca5a6489bb/modules/dns/default.nix\">github.com/RyanGibb/eilean-nix/tree/0b4213/modules/dns/default.nix</a></span><a href=\"#fnref1\">↩︎</a></p></li>\n</ol>",
9 "content_type": "html",
10 "categories": [],
11 "source": "https://ryan.freumh.org/atom.xml"
12}