<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Technical Things</title>
    <link>https://haxbits.org/technology/</link>
    <description>Software Adjacent Projects and Design</description>
    <pubDate>Wed, 03 Jun 2026 18:11:52 -0700</pubDate>
    <item>
      <title>Looking Deeply into WriteFreely Templates</title>
      <link>https://haxbits.org/technology/looking-deeply-into-writefreely-templates</link>
      <description>&lt;![CDATA[  or potentialy useful information&#xA;&#xA;Work In Process&#xA;&#xA;Template System&#xA;| Detail | Notes |&#xA;|---|---|&#xA;| File Location | /pages |&#xA;| Framework | go text/template through html/template |&#xA;| Template Usage |  pad.go, templates.go, collections.go, read.go, oauth_signup.go, posts.go, handle.go, account.go, app.go |&#xA;| Template Variables | templates, pages, h.errors.InternalServerError, t |&#xA;| Initialization | templates.go:120, file name to the first dot is the template name;  templates.go:137 page name is file name without extension |&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<blockquote><p>or potentialy useful information</p></blockquote>

<h3 id="work-in-process">Work In Process</h3>

<h2 id="template-system">Template System</h2>

<table>
<thead>
<tr>
<th>Detail</th>
<th>Notes</th>
</tr>
</thead>

<tbody>
<tr>
<td>File Location</td>
<td>/pages</td>
</tr>

<tr>
<td>Framework</td>
<td>go text/template through html/template</td>
</tr>

<tr>
<td>Template Usage</td>
<td>pad.go, templates.go, collections.go, read.go, oauth_signup.go, posts.go, handle.go, account.go, app.go</td>
</tr>

<tr>
<td>Template Variables</td>
<td>templates, pages, h.errors.InternalServerError, t</td>
</tr>

<tr>
<td>Initialization</td>
<td>templates.go:120, file name to the first dot is the template name;  templates.go:137 page name is file name without extension</td>
</tr>
</tbody>
</table>
]]></content:encoded>
      <guid>https://haxbits.org/technology/looking-deeply-into-writefreely-templates</guid>
      <pubDate>Fri, 17 Oct 2025 17:59:07 +0000</pubDate>
    </item>
    <item>
      <title>Properly Installing google-drive-ocamlfuse on Raspberry Pi OS</title>
      <link>https://haxbits.org/technology/properly-installing-google-drive-ocamlfuse-on-raspberry-pi-os</link>
      <description>&lt;![CDATA[  or 2TB of readonly cloud storage with minimal fuss&#xA;&#xA;Platform&#xA;Raspberry PI Version 3B&#xA;  4GB Ram&#xA;  Stock clock&#xA;  Raspberry Pi OS Lite, 64 bit&#xA;&#xA;The idea&#xA;&#xA;It would be quite splendiferous to have a large, easy to use data store for my Raspberry Pi home server.  I already pay for Google One, and I basically don&#39;t use it for anything, so that seems like an appealing target.  Let&#39;s just setup an easy mount or something and enjoy.&#xA;&#xA;That was simple, easy, and wrong.&#xA;&#xA;!--more--&#xA;&#xA;The catch&#xA;&#xA;Raspberry Pi OS does not have a build of google-drive-ocamlfuse available; and wouldn&#39;t you know it, the documentation isn&#39;t quite up to snuff either.&#xA;&#xA;The Fix&#xA;&#xA;If brute force doesn&#39;t work, you&#39;re not using it correctly.  So, if they won&#39;t give us a package, we&#39;re going to build our own, and by golly, we&#39;ll make it work.&#xA;&#xA;So, let us start by following the instructions provided by astrada&#39;s installation notes.  It mostly works.&#xA;&#xA;Installing google-drive-ocamlfuse&#xA;&#xA;In order to build google-drive-ocamlfuse on Raspberry Pi OS we need to install some tooling, namely the opam utility and the mccs solver.  We&#39;ll also be removing the legacy package aspcud; I don&#39;t think you&#39;ll miss it.&#xA;&#xA;sudo apt install opam mccs&#xA;sudo apt remove aspcud&#xA;&#xA;Now, let us inform opam that we sould like to use the mccs solver, and switch to the recomended build environment.&#xA;&#xA;opam init --solver=mccs&#xA;opam switch create 4.09.0&#xA;eval $(opam env)&#xA;&#xA;Once that&#39;s taken care of, we can first install the dependencies and finally google-drive-ocamlfuse &#xA;&#xA;opam depext google-drive-ocamlfuse&#xA;opam install google-drive-ocamlfuse&#xA;&#xA;At this point you have a working local installation of google-drive-ocamlfuse.  Now to get the middleware configured.&#xA;&#xA;Obtaining an OAuth2 ID and Secret&#xA;&#xA;In order to proceed any further, we need to obtain some secrets from google; so let us refer to Managing OAuth Clients, and return here once we have an API Client ID and Client Secret.&#xA;&#xA;Connecting to Google Drive&#xA;&#xA;We need to perform the initial authorization flow before we can start using our google drive client.  I&#39;ll be assuming that we are accessing the Pi over ssh and must use the headless flow.&#xA;&#xA;google-drive-ocamlfuse -headless \&#xA;    -id ${APICLIENTID} \&#xA;    -secret ${APICLIENTSECRET}&#xA;&#xA;Roughly follow the instructions given by the tool.  Once you&#39;ve accessed the given link, you will be provided with a confirmation screen along with a verification code (which is also the end of the URL). &#xA;&#xA;Provide the verification to google-drive-ocamlfuse and that&#39;s the hard part done.&#xA;&#xA;Creating your Mountpoint&#xA;&#xA;Because I intend on sharing this connection between users, I need to create a system mount point.  If you only require single-user usage; feel free to create this folder anywhere; it only needs to be owned by the google drive user.&#xA;&#xA;sudo mkdir -p /mnt/Google&#xA;sudo chown $USER /mnt/Google&#xA;&#xA;Configuring the connection&#xA;&#xA;As an insurance against bad actors doing bad things, we&#39;re going to apply the principle of least privilege and configure our connection to be read-only, and to convert documents into LibreOffice documents.&#xA;&#xA;nano ~/.gdfuse/default/config&#xA;&#xA;Set the following settings&#xA;readonly, largefilereadonly to true&#xA;documentformat, drawingformat, presentationformat, spreadsheetformat to libreoffice&#xA;&#xA;  readonly=true&#xA;largefilesreadonly=true&#xA;documentformat=libreoffice&#xA;drawingformat=libreoffice&#xA;presentationformat=libreoffice&#xA;spreadsheetformat=libreoffice&#xA;  ~/.gdfuse/default/config&#xA;&#xA;Modifying /etc/fuse.conf&#xA;&#xA;You can safely skip this if the user accessing the google drive connection is the same as the owner of the connection.  IF you want other users to be able to access your mount, you first need to enable other user access in FUSE by editing fuse.conf.&#xA;&#xA;sudo nano /etc/fuse.conf&#xA;&#xA;Uncomment the line userallowother to enable the allowother mount option.&#xA;&#xA;  userallowother&#xA;  /etc/fuse.conf&#xA;&#xA;Creating the wrapper script&#xA;&#xA;Because we installed google-drive-ocamlfuse from opam; we need to write a wrapper as systemd will not load profile information when starting a unit, so we need to do that ourselves to ensure the proper opam environment.&#xA;&#xA;mkdir -p ~/.bin&#xA;nano ~/.bin/mount-google-drive&#xA;&#xA;The script below simply sources the current users profile and then calls the mount utility.&#xA;&#xA;  #!/bin/bash&#xA;source /home/${USER}/.profile&#xA;google-drive-ocamlfuse -o allowother /mnt/Google/&#xA;  ~/.bin/mount-google-drive&#xA;&#xA;Don&#39;t forget to make your script executable.&#xA;&#xA;chmod +x ~/.bin/mount-google-drive&#xA;&#xA;Writing the User Service&#xA;&#xA;We&#39;re very nearly done; the next step is to tell systemd how to launch our helper.  Let&#39;s start by making sure we have a systemd user unit folder, and editing google-drive.service.&#xA;&#xA;mkdir -p ~/.config/systemd/user&#xA;nano ~/.config/systemd/user/google-drive.service&#xA;&#xA;The contents below describe a forking service (google-drive-ocamlfuse runs as a background process) that will start after networking is up but before a user logs in.&#xA;&#xA;  [Unit]&#xA;Description=FUSE filesystem using Google Drive&#xA;After=network.target&#xA;&#xA;[Service]&#xA;ExecStart=%h/.bin/mount-google-drive&#xA;ExecStop=fusermount -u /mnt/Google&#xA;Restart=always&#xA;Type=forking&#xA;&#xA;[Install]&#xA;WantedBy=default.target&#xA;  ~/.config/systemd/user/google-drive.service&#xA;&#xA;Once your service unit has been saved; we need to instruct systemd to recognize the new unit and to enable it for automatic start.&#xA;&#xA;systemctl --user daemon-reload&#xA;systemctl --user enable google-drive&#xA;systemctl --user start google-drive&#xA;&#xA;Enabling Lingering&#xA;&#xA;Lingering, while perhaps not strictly required is advised for enabling unatended user processes.&#xA;&#xA;sudo loginctl enagle-linger $USER&#xA;&#xA;Fin&#xA;&#xA;Congratulations; you&#39;re all done.  You should now have a persistent read-only google drive connection that will stream your files to you just like a local device, easy.  If you&#39;re impatient; or if the contents do not refresh quickly enough; restart the service and it will flush the caches and present a new view of the drive tree.&#xA;&#xA;But wait; there&#39;s more&#xA;&#xA;If you, like me have an unreasonable number of probably personal files available on your google drive, you can configure google-drive-ocamlfuse to use a subdirectory within google drive as a virtual root.  This is configured using the root_folder configuration option.  &#xA;&#xA;The documentation was a little sparse, but here it expects you to provide a folder ID (which you can obtain from the folder view URI).  Setting this option will configure the connection to only show files in that directory and below.  Don&#39;t bother using the path option as the ID does not change when a folder is moved or renamed.&#xA;&#xA;Tags: #raspberrypi #systemd #loginctl #googledrive]]&gt;</description>
      <content:encoded><![CDATA[<blockquote><p>or 2TB of readonly cloud storage with minimal fuss</p></blockquote>

<h2 id="platform">Platform</h2>
<ul><li><code>Raspberry PI</code> Version 3B
<ul><li>4GB Ram</li>
<li>Stock clock</li>
<li><code>Raspberry Pi OS</code> Lite, 64 bit</li></ul></li></ul>

<h2 id="the-idea">The idea</h2>

<p>It would be quite splendiferous to have a large, easy to use data store for my Raspberry Pi home server.  I already pay for Google One, and I basically don&#39;t use it for anything, so that seems like an appealing target.  Let&#39;s just setup an easy mount or something and enjoy.</p>

<p>That was simple, easy, and wrong.</p>



<h2 id="the-catch">The catch</h2>

<p><code>Raspberry Pi OS</code> <em>does not</em> have a build of <code>google-drive-ocamlfuse</code> available; and wouldn&#39;t you know it, the documentation isn&#39;t quite up to snuff either.</p>

<h2 id="the-fix">The Fix</h2>

<p>If brute force doesn&#39;t work, you&#39;re not using it correctly.  So, if they won&#39;t give us a package, we&#39;re going to build our own, and by golly, <em>we&#39;ll make it work</em>.</p>

<p>So, let us start by following the instructions provided by <a href="https://github.com/astrada/google-drive-ocamlfuse/wiki/Installation#installing-with-opam-on-debianraspbian" rel="nofollow">astrada&#39;s installation notes</a>.  It mostly works.</p>

<h2 id="installing-google-drive-ocamlfuse">Installing <code>google-drive-ocamlfuse</code></h2>

<p>In order to build <code>google-drive-ocamlfuse</code> on <code>Raspberry Pi OS</code> we need to install some tooling, namely the <code>opam</code> utility and the <code>mccs</code> solver.  We&#39;ll also be removing the legacy package <code>aspcud</code>; I don&#39;t think you&#39;ll miss it.</p>

<pre><code class="language-bash">sudo apt install opam mccs
sudo apt remove aspcud
</code></pre>

<p>Now, let us inform <code>opam</code> that we sould like to use the <code>mccs</code> solver, and switch to the recomended build environment.</p>

<pre><code class="language-bash">opam init --solver=mccs
opam switch create 4.09.0
eval $(opam env)
</code></pre>

<p>Once that&#39;s taken care of, we can first install the dependencies and finally <code>google-drive-ocamlfuse</code></p>

<pre><code class="language-bash">opam depext google-drive-ocamlfuse
opam install google-drive-ocamlfuse
</code></pre>

<p>At this point you have a working local installation of <code>google-drive-ocamlfuse</code>.  Now to get the middleware configured.</p>

<h2 id="obtaining-an-oauth2-id-and-secret">Obtaining an OAuth2 ID and Secret</h2>

<p>In order to proceed any further, we need to obtain some secrets from google; so let us refer to <a href="https://support.google.com/cloud/answer/15549257?hl=en&amp;visit_id=638961857206839746-3164857591&amp;rd=1" rel="nofollow">Managing OAuth Clients</a>, and return here once we have an API Client ID and Client Secret.</p>

<h2 id="connecting-to-google-drive">Connecting to Google Drive</h2>

<p>We need to perform the initial authorization flow before we can start using our google drive client.  I&#39;ll be assuming that we are accessing the Pi over <code>ssh</code> and must use the headless flow.</p>

<pre><code class="language-bash">google-drive-ocamlfuse -headless \
    -id ${API_CLIENT_ID} \
    -secret ${API_CLIENT_SECRET}
</code></pre>

<p>Roughly follow the instructions given by the tool.  Once you&#39;ve accessed the given link, you will be provided with a confirmation screen along with a verification code (which is also the end of the URL).</p>

<p>Provide the verification to <code>google-drive-ocamlfuse</code> and that&#39;s the hard part done.</p>

<h2 id="creating-your-mountpoint">Creating your Mountpoint</h2>

<p>Because I intend on sharing this connection between users, I need to create a system mount point.  If you only require single-user usage; feel free to create this folder anywhere; it only needs to be owned by the google drive user.</p>

<pre><code class="language-bash">sudo mkdir -p /mnt/Google
sudo chown $USER /mnt/Google
</code></pre>

<h2 id="configuring-the-connection">Configuring the connection</h2>

<p>As an insurance against bad actors doing bad things, we&#39;re going to apply the principle of least privilege and configure our connection to be read-only, and to convert documents into LibreOffice documents.</p>

<pre><code class="language-bash">nano ~/.gdfuse/default/config
</code></pre>

<p>Set the following settings
– <code>read_only</code>, <code>large_file_readonly</code> to <code>true</code>
– <code>document_format</code>, <code>drawing_format</code>, <code>presentation_format</code>, <code>spreadsheet_format</code> to <code>libreoffice</code></p>

<blockquote><pre><code class="language-inifile">read_only=true
large_files_read_only=true
document_format=libreoffice
drawing_format=libreoffice
presentation_format=libreoffice
spreadsheet_format=libreoffice
</code></pre>

<p>~/.gdfuse/default/config</p></blockquote>

<h2 id="modifying-etc-fuse-conf">Modifying /etc/fuse.conf</h2>

<p>You can safely skip this if the user accessing the google drive connection is the same as the owner of the connection.  IF you want other users to be able to access your mount, you first need to enable other user access in FUSE by editing <code>fuse.conf</code>.</p>

<pre><code class="language-bash">sudo nano /etc/fuse.conf
</code></pre>

<p>Uncomment the line <code>user_allow_other</code> to enable the <code>allow_other</code> mount option.</p>

<blockquote><pre><code>user_allow_other
</code></pre>

<p>/etc/fuse.conf</p></blockquote>

<h2 id="creating-the-wrapper-script">Creating the wrapper script</h2>

<p>Because we installed <code>google-drive-ocamlfuse</code> from <code>opam</code>; we need to write a wrapper as <code>systemd</code> will not load profile information when starting a unit, so we need to do that ourselves to ensure the proper opam environment.</p>

<pre><code class="language-bash">mkdir -p ~/.bin
nano ~/.bin/mount-google-drive
</code></pre>

<p>The script below simply sources the current users profile and then calls the mount utility.</p>

<blockquote><pre><code class="language-bash">#!/bin/bash
source /home/${USER}/.profile
google-drive-ocamlfuse -o allow_other /mnt/Google/
</code></pre>

<p>~/.bin/mount-google-drive</p></blockquote>

<p>Don&#39;t forget to make your script executable.</p>

<pre><code class="language-bash">chmod +x ~/.bin/mount-google-drive
</code></pre>

<h2 id="writing-the-user-service">Writing the User Service</h2>

<p>We&#39;re very nearly done; the next step is to tell systemd how to launch our helper.  Let&#39;s start by making sure we have a systemd user unit folder, and editing <code>google-drive.service</code>.</p>

<pre><code class="language-bash">mkdir -p ~/.config/systemd/user
nano ~/.config/systemd/user/google-drive.service
</code></pre>

<p>The contents below describe a forking service (<code>google-drive-ocamlfuse</code> runs as a background process) that will start <em>after</em> networking is up but <em>before</em> a user logs in.</p>

<blockquote><pre><code class="language-systemd">[Unit]
Description=FUSE filesystem using Google Drive
After=network.target

[Service]
ExecStart=%h/.bin/mount-google-drive
ExecStop=fusermount -u /mnt/Google
Restart=always
Type=forking

[Install]
WantedBy=default.target
</code></pre>

<p>~/.config/systemd/user/google-drive.service</p></blockquote>

<p>Once your service unit has been saved; we need to instruct systemd to recognize the new unit and to enable it for automatic start.</p>

<pre><code class="language-bash">systemctl --user daemon-reload
systemctl --user enable google-drive
systemctl --user start google-drive
</code></pre>

<h2 id="enabling-lingering">Enabling Lingering</h2>

<p>Lingering, while perhaps not strictly required is advised for enabling unatended user processes.</p>

<pre><code class="language-bash">sudo loginctl enagle-linger $USER
</code></pre>

<h2 id="fin">Fin</h2>

<p>Congratulations; you&#39;re all done.  You should now have a persistent read-only google drive connection that will stream your files to you just like a local device, easy.  If you&#39;re impatient; or if the contents do not refresh quickly enough; restart the service and it will flush the caches and present a new view of the drive tree.</p>

<h2 id="but-wait-there-s-more">But wait; there&#39;s more</h2>

<p>If you, like me have an unreasonable number of probably personal files available on <em>your</em> google drive, you can configure <code>google-drive-ocamlfuse</code> to use a subdirectory within google drive as a virtual root.  This is configured using the <code>root_folder</code> configuration option.</p>

<p>The documentation was a little sparse, but here it expects you to provide a folder ID (which you can obtain from the folder view URI).  Setting this option will configure the connection to only show files in that directory and below.  Don&#39;t bother using the path option as the ID does not change when a folder is moved or renamed.</p>

<p>Tags: <a href="/read/t/raspberrypi" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">raspberrypi</span></a> <a href="/read/t/systemd" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">systemd</span></a> <a href="/read/t/loginctl" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">loginctl</span></a> <a href="/read/t/googledrive" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">googledrive</span></a></p>
]]></content:encoded>
      <guid>https://haxbits.org/technology/properly-installing-google-drive-ocamlfuse-on-raspberry-pi-os</guid>
      <pubDate>Wed, 15 Oct 2025 18:12:23 +0000</pubDate>
    </item>
  </channel>
</rss>