<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Matthias Portzel]]></title><description><![CDATA[Matthias Portzel is a programmer, web developer, and writer. ]]></description><link>https://matthiasportzel.com/</link><image><url>https://matthiasportzel.com/favicon.png</url><title>Matthias Portzel</title><link>https://matthiasportzel.com/</link></image><generator>Ghost 5.53</generator><lastBuildDate>Sun, 05 Apr 2026 18:57:56 GMT</lastBuildDate><atom:link href="https://matthiasportzel.com/ideas/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Editing remote files over SSH by pretending to use rmate]]></title><description><![CDATA[TextMate might have invented the best way of editing remote files 11 years ago.]]></description><link>https://matthiasportzel.com/rmate/</link><guid isPermaLink="false">654f936f83de18f4b8b0905e</guid><category><![CDATA[idea]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Wed, 27 Mar 2024 02:35:51 GMT</pubDate><content:encoded><![CDATA[<p>Today, many developers edit files on a remote computer by using VSCode&apos;s remote editing functionality, or by opening an in-terminal editor like Nano or Vim. However, these are not your only options. There&apos;s another elegant and easy-to-use alternative, which was invented by TextMate over 10 years ago. </p><h2 id="easy-usage">Easy Usage</h2><p>I have my remote VPS configured such that I can edit files on it simply by SSHing to it and issuing <code>sl &lt;filepath&gt;</code>. This command returns instantly, placing me back at the shell, but not before opening the specified file in Sublime Text on my local computer. I can edit the file in Sublime, and when I press Save, the file changes are magically written back to the file on my server.</p><p>If the file requires root access to edit, I can still do something similar. I can run <code>sudoedit &lt;filepath&gt;</code>, which will again open and edit the file in Sublime on my computer, but it will wait for me to close the file locally before the command exits and results are written to the remote server.</p><p>These options are super easy to use for editing files if I&apos;m already at a console on the remote machine. I can initiate the editing session on the remote computer, but then I can do my editing on my computer. This means that I have the editing experience that I&apos;m used to, with zero latency and my Sublime configuration.</p><h2 id="how">How</h2><p>This is made possible because of a tool developed for TextMate called <code>rmate</code>. This was a companion to the <code>mate</code> command, which was the CLI tool for opening files in TextMate (on the same computer). You could instead run <code>rmate</code> on a remote computer and it would work as described above, opening the file in your local instance of TextMate for local editing.</p><p><a href="https://macromates.com/blog/2011/mate-and-rmate/?ref=matthiasportzel.com">https://macromates.com/blog/2011/mate-and-rmate/</a> mate and rmate, from the TextMate blog</p><p>Today, I don&apos;t use rmate on the server and I don&apos;t use TextMate on my laptop, but I can still take advantage of this workflow.</p><blockquote>Note on terminology:<br>I&apos;m going to use &quot;server&quot; and &quot;server-side&quot; to refer to my VPS, the machine I&apos;m connecting to over SSH. This is technically the &quot;rmate client,&quot; since it initiates the rmate connection. But I&apos;ll avoid this confusing terminology.</blockquote><p>On the server, I use Harald Lapp&apos;s re-implementation of the <code>rmate</code> script in pure bash. (The original version was written in Ruby, which I don&apos;t have globally installed on my VPS.) This project&apos;s README is also an excellent reference&#x2014;it has links and instructions which I drew from when writing this post.</p><p><a href="https://github.com/aurora/rmate?ref=matthiasportzel.com">https://github.com/aurora/rmate</a> </p><p>On my computer, I use the Sublime Text plugin RemoteSubl, which implements the local side of the rmate connection. If you don&apos;t use Sublime Text, there are plugins for other editors like VSCode and Pulsar (the editor formerly known as Atom).</p><p><a href="https://github.com/randy3k/RemoteSubl?ref=matthiasportzel.com">https://github.com/randy3k/RemoteSubl</a></p><p>I find it amusing that I&#x2019;m not using the original rmate technology on the client or the server; yet, both of them think that the other one is. In this way, even though TextMate is not as relevant as it once was, its name and innovations live on.</p><h2 id="configuration">Configuration</h2><p>If you&apos;re a CLI pro, this configuration will be trivial. However, if you&apos;re a CLI pro, you probably have a method for editing remote files that you&apos;re happy with. So I&apos;m going to walk through this slowly so that you can follow along, provided you&apos;re already familiar with SSH.</p><p>This configuration is in-depth so that, at the end of it, you&apos;ll have the best remote editing experience possible. There are simpler instructions in the repositories for the tools linked above, but I&apos;ve found a little bit more configuration is required to remove the pain points and make it so that you don&apos;t have to fall back to <code>vi</code>.</p><h3 id="remote-configuration">Remote configuration</h3><p>The first step is installing the rmate bash script on your remote server. Since this is a simple script, we just need to download it, mark it as executable, and make sure it is on the path. I personally place it in ~/bin and then add that directory to my path, to avoid globally installing with sudo.</p><pre><code>mkdir -p ~/bin
curl -Lo ~/bin/rmate https://raw.githubusercontent.com/aurora/rmate/master/rmate
chmod +x ~/bin/rmate</code></pre><p>Then we need a few simple changes to the remote .bashrc (or equivalent if you&apos;re using a different shell):</p><pre><code># Set PATH to include ~/bin
export PATH=&quot;$HOME/bin:$PATH&quot;

# Set $EDITOR so other tools know what editor to use
# This should be an absolute path, not `rmate` or `~/bin/rmate`
export EDITOR=&quot;$HOME/bin/rmate -w&quot;

# Create an alias for our use
alias sl=&quot;rmate&quot;</code></pre><p>The first change adds <code>~/bin</code> to the <code>PATH</code>, as we discussed.</p><p>The second change sets <code>$EDITOR</code>. This is used by tools like <code>git commit</code> and <code>sudoedit</code>. <code>sudoedit</code> in particular is tricky to configure since it looks up the editor without your modified <code>PATH</code> or aliases, so it should be an absolute path to the editor executable. The <code>-w</code> at the end of the <code>EDITOR</code> tells <code>rmate</code> to wait until the file has been closed on your remote computer&#x2014;this is the behavior that most tools expect from <code>$EDITOR</code>.</p><blockquote><code>sudoedit</code> is a helper provided by <code>sudo</code> &#xA0;for editing files which require root access, without running your editor as the root user.</blockquote><p>The third change is a simple alias so that you don&apos;t have to type <code>rmate</code> if you don&apos;t want to. I use <code>sl</code> since that&apos;s the alias I have on my local computer to open Sublime Text, and it makes for seamless transitions between the local and remote CLI.</p><h3 id="local-configuration">Local Configuration</h3><p>There are also a couple of things to set up locally in order for this to work.</p><p>First, you need an editor plugin, as discussed above. Check the settings for your plugin, you may need to turn it on or make sure that it&apos;s using the default <code>rmate</code> port (52698). However, subsequent times that you open your editor, it will start automatically and will not require further action, which is very convenient. </p><p>Second, you need to configure SSH to forward the <code>rmate</code> port when you connect to the remote computer. This can be done by passing an option at the command line, but this is cumbersome if you, like me, are using this as your default strategy for editing remote files.</p><p>Instead, I highly recommend creating a rule in your SSH config. On Mac, my SSH config lives in <code>~/.ssh/config</code>, and the rule that I&apos;ve added looks like:</p><pre><code># rmate forwarding
RemoteForward 52698 localhost:52698</code></pre><p>This means that when you open an ssh connection to a remote computer, it automatically creates a connection between port 52698 on the remote and local machines which <code>rmate</code> can use for communication.</p><blockquote>It&apos;s overkill to explain in this post, but you can of course configure this forwarding rule on a per-host basis, which is what I do in practice.</blockquote><h2 id="conclusion">Conclusion</h2><p>There are a couple of drawbacks to this.</p><ul><li>As you saw, there&apos;s a little bit of manual configuration involved.</li><li>Your editor has to be open locally, <code>rmate</code> can&apos;t open the editor application on your local computer.</li><li>There&apos;s no overwrite protection if the file you&apos;re editing with <code>rmate</code> is modified as you&apos;re editing it</li></ul><p>However, these are all very minor and understandable issues.</p><p>In my experience, this workflow is much more convenient than opening the file in Vim or Nano on the remote machine, and it&apos;s a lot simpler than mounting the remote filesystem or installing VSCode remote editing tools to edit a config file. Not to mention that these solutions rarely play well with <code>sudo</code>.<code>rmate</code> is a really impressive piece of engineering from the TextMate team, and I hope that I can continue using it for a long time.</p>]]></content:encoded></item><item><title><![CDATA[Declarative package management with a Brewfile]]></title><description><![CDATA[I love macOS and Brew, but my workflow looks very different from most Brew users.]]></description><link>https://matthiasportzel.com/brewfile/</link><guid isPermaLink="false">64ab3f017feb2e7b723d8803</guid><category><![CDATA[idea]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Sun, 01 Oct 2023 23:26:00 GMT</pubDate><content:encoded><![CDATA[<p>I&#x2019;m a big fan of macOS, and I&#x2019;m a big fan of the most popular package manager on macOS, Homebrew. It&#x2019;s one of the first things I install on a new Mac, and I use it for managing both casks (applications) as well as normal packages.</p>
<p>However, my Brew workflow looks very different from most people. In this post, I&#x2019;m going to describe my workflow and then give examples of what benefits this gives me.</p>
<p>My package management workflow revolves around a Brewfile. This is a text file that lets me declaratively list what packages I want to be installed. Instead of imperatively issuing commands like <code>install</code> and <code>uninstall</code>, I edit this text file to include the package that I want, then run a single command that syncs my system with the text file (installing missing packages and uninstalling extra packages), as well as upgrading any out-of-date packages.</p>
<p>That magic command is:</p>
<pre><code>alias bbic=&quot;brew update &amp;&amp;\
    brew bundle install --cleanup --file=~/.config/Brewfile&quot;</code></pre>
<ul><li><code>brew update</code> connects to the brew API server to fetch the newest version of all packages.</li><li><code>brew bundle</code>, the main command, installs and upgrades the requirements listed in the Brewfile.</li><li>Passing <code>--cleanup</code> removes any installed formula that aren&apos;t listed in the Brewfile.</li></ul>
<p>An example excerpt from my Brewfile:</p>
<pre><code># Moreutils provides, for example, vipe
brew &quot;moreutils&quot;

# macOS ships with a slightly out-of-date `less`
brew &quot;less&quot;

# jq, a command line JSON editor
brew &quot;jq&quot;

# Emacs (packaged for macOS)
tap &quot;d12frosted/emacs-plus&quot;
brew &quot;d12frosted/emacs-plus/emacs-plus&quot;, args: [&quot;with-memeplex-wide-icon&quot;]

# Sublime Text editor
cask &quot;sublime-text&quot;</code></pre>
<p>As you can see from this example, the syntax is very simple. Other declarative package management systems (Nix, for example) require learning a new syntax and a new system. But a Brewfile is just an unordered list of Homebrew packages.</p>
<h2 id="advantage-1-package-tracking">Advantage 1: Package tracking</h2>
<p>Other than the simplicity, the other thing to notice in that example excerpt is the comments. A Brewfile allows me to sort and comment on the packages inline, instead of having to keep in my head why I installed or uninstalled something. (To uninstall, I&#x2019;ll frequently just comment out the line with the package.)</p>
<p>This keeps my system organized, and ensures that I can keep track of every installed package and what its purpose is.</p>
<h2 id="advantage-2-easy-software-trials">Advantage 2: Easy Software Trials</h2>
<p>I like to be able to quickly and easily try out software, and uninstall it when I&#x2019;m done. I don&#x2019;t think installing software should be a commitment. If I&apos;m trying out a software, I can just run <code>brew install example-test-software</code>, which installs the software like normal. But the next time I run <code>bbic</code>, it will cleanup by uninstalling <code>example-test-software</code>, since it&apos;s not listed in my Brewfile. Since I like to &quot;trial-run&quot; software without hassle, this &quot;unsaved-by-default&quot; behavior is a plus for me.</p>
<h2 id="advantage-3-everything-always-up-to-date">Advantage 3: Everything always up-to-date</h2>
<p>If I want to permanently install a piece of software, I just edit <code>~/.config/Brewfile</code>, add the package (and a comment explaining why I added it), and then run <code>bbic</code>. This installs the software, but it also updates Homebrew and upgrades any out-of-date software at the same time. This ensures that every package on my system is always up to date. (This command invokes feelings of the famous <code>pacman -Syu</code> that I&apos;d grown fond of when using Arch.)</p>
<p>I can imagine many other workflows similar to this one, like having a Brewfile per-project and taking advantage of the ability to run a Brewfile-specific sandbox, or having &quot;install&quot; and &quot;uninstall&quot; aliases that edit the Brewfile for you. I&apos;m just describing what works for me. Hopefully this post gets you thinking about other ways of managing packages (that don&apos;t require switching operating system).</p>
<p>I originally started using this method because Brew didn&apos;t provide a way to automatically remove packages that were originally installed as dependencies, which made temporarily installing software difficult. Brew now, however, offers <code>brew autoremove</code>.</p>]]></content:encoded></item><item><title><![CDATA[Docker is 4 things]]></title><description><![CDATA[Docker is not just a way of running programs on Linux without a virtual machine. Docker is 4 things.]]></description><link>https://matthiasportzel.com/docker/</link><guid isPermaLink="false">64efdd5af3909ddb0d836d51</guid><category><![CDATA[idea]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Thu, 31 Aug 2023 00:35:03 GMT</pubDate><content:encoded><![CDATA[<ul><li>First, the Dockerfile file format for declaratively describing a machine (operating system, installed packages, processes, etc).</li><li>Second, the Docker Engine which takes a Dockerfile and runs it on a Linux host natively, without a virtual machine.</li><li>Third, the Docker Desktop app which takes a Dockerfile and runs it on a Mac or Windows host, using a Linux virtual machine.</li><li>Fourth, the Docker Hub container repository which allows a community to share Dockerfiles for common configurations.</li></ul><p>Often, when people evaluate Docker or make statments about &quot;Docker,&quot; they&apos;re referring only to the Docker Engine. But most of the time, this is not a useful view to take. Most of time, the practicality of Docker comes from a combination of all four of these things.</p>]]></content:encoded></item></channel></rss>