
<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.5">Jekyll</generator><link href="https://pelepelin.github.io//feed.xml" rel="self" type="application/atom+xml" /><link href="https://pelepelin.github.io//" rel="alternate" type="text/html" /><updated>2024-05-08T11:47:19+00:00</updated><id>https://pelepelin.github.io//feed.xml</id><title type="html">Konstantin Pelepelin</title><subtitle>Web Developer</subtitle><entry><title type="html">Alpine on a router</title><link href="https://pelepelin.github.io//Alpine-on-a-router/" rel="alternate" type="text/html" title="Alpine on a router" /><published>2023-10-19T00:00:00+00:00</published><updated>2023-10-19T00:00:00+00:00</updated><id>https://pelepelin.github.io//Alpine-on-a-router</id><content type="html" xml:base="https://pelepelin.github.io//Alpine-on-a-router/"><![CDATA[<p>In this article I’ll show simple steps to install Alpine in a chroot environment
on a SOHO router.</p>

<h2 id="motivation">Motivation</h2>

<p>Nowadays many SOHO routers are quite powerful devices. Probably, not as powerful
in some aspects as latest Raspberry Pi but powerful enough to run several
additional services besides basic routing functionality. In fact, many routers
provide Samba and other file servers for years. Some powerful models contain
even BitTorrent clients, DLNA servers, VPN clients and servers in the stock
firmware.</p>

<p>On the other side, router vendors firmware is rarely ready for extension. Some
vendors even lock their firmware so enthusiasts need to hack it first if they
want to add anything to their devices. Luckily, there are many vendors which do
provide telnet or ssh access to the device console.</p>

<p>Still, even if one gets to the console, those devices don’t contain any
development tools and there are no vendor repositories for third party software.
So enthusiasts need to create their own repositories. One of well known examples
is Entware which can be used on many device brands, models and flavours.</p>

<p>It worth noting that router firmwares are usually quite different from a typical
multipurpose Linux distribution. As a result, Entware adopts the practice of
installing everything under <code class="language-plaintext highlighter-rouge">/opt</code> filesystem hierarchy. Installing software
under a prefix like <code class="language-plaintext highlighter-rouge">/usr/local</code> is not something unknown in a *NIX world,
however, the weird thing is that Entware can’t rely on “host” layout and
libraries at all, so it needs even its own <code class="language-plaintext highlighter-rouge">/opt/etc</code> and its own C library, as
host can use anything of uClibc, musl or glibc.</p>

<p>Does it remind you of anything? When one wants to run applications independently
of the host system, they could run them in a virtual machine. Or in the modern
Linux world, in a container.</p>

<p>Well, I’m not crazy enough to run Docker on a router (yet). But what about
chroot? Some linux distributions have support for running in chroot. The
distribution used for lightweight containers most often, Alpine, also has
<a href="https://wiki.alpinelinux.org/wiki/Alpine_Linux_in_a_chroot">instructions how to setup a chroot</a>.</p>

<h2 id="but-why-actually">But why, actually?</h2>

<ul>
  <li>There’s enough spare power on the router to run some services 24x7 and I don’t
need an additional box for that.</li>
  <li>Current Entware repository for ARM x64 architecture
<a href="https://bin.entware.net/aarch64-k3.10/Packages.html">contains about 2800 packages</a>.
Alpine contains more than 5000 packages in its “stable” repo and 14000 in
“community”.</li>
  <li>Entware is maintained by a few enthusiasts. Alpine has thousands of users in
production including big enterprises so it gets updates faster.</li>
  <li>Entware adopts some compromises to run on a low-resource hardware in a
non-standard system layout and without conflicts with the firmware. Alpine is
purposely built for low resource usage but follows standard layout.</li>
  <li>Alpine uses a lightweight musl C library (which has its own downsides).</li>
  <li>Alpine is used by many Docker images so if I need to run some application
which is not packaged for Alpine, it’s likely it has an Alpine-based Docker
image so the recipe can be extracted from it.</li>
</ul>

<h2 id="okay-lets-give-it-a-try">Okay, let’s give it a try</h2>

<p>My router runs a so called
<a href="https://www.asuswrt-merlin.net/">Asuswrt-merlin firmware</a>.
I already have an attached USB drive formatted to ext4 and Entware installed on
it.</p>

<p>Probably, it should be possible to follow
<a href="https://wiki.alpinelinux.org/wiki/Alpine_Linux_in_a_chroot">instructions from the Alpine wiki</a>
step by step without installed Entware. However, someone already scripted that.
Unfortunately, the script uses some utilities not provided by the limited router
firmware so I need Entware.</p>

<p>I’ve made a couple of modifications so I don’t need additional configuration of
the script for my router, they are in
<a href="https://github.com/pelepelin/alpine-chroot-install/tree/aarch64">in the aarch64 branch of my fork</a>.
See the README there for more details.</p>

<blockquote>
  <p><strong>Disclaimer:</strong> I’m writing these instructions from memory. I did this a
couple of times but something can be missing. I’ll fix that when I’ll use my
own recipe next time.</p>
</blockquote>

<p>So, first I need to install some Entware packages for that script to work:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>opkg <span class="nb">install </span>coreutils-id coreutils-mktemp bash coreutils-sha256sum
</code></pre></div></div>

<p>You may probably need to install <code class="language-plaintext highlighter-rouge">curl</code> also because router <code class="language-plaintext highlighter-rouge">wget</code> may lack
HTTPS support.</p>

<p>Download the script with <code class="language-plaintext highlighter-rouge">wget</code> or <code class="language-plaintext highlighter-rouge">curl</code>.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget https://github.com/pelepelin/alpine-chroot-install/raw/aarch64/alpine-chroot-install
<span class="nb">chmod</span> +x alpine-chroot-install
</code></pre></div></div>

<p>Find the path for the installation. In the example below the storage is mounted
as <code class="language-plaintext highlighter-rouge">/mnt/disk</code> so the command will install Alpine under <code class="language-plaintext highlighter-rouge">/mnt/disk/alpine</code> which
should not exist before installation.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./alpine-chroot-install <span class="nt">-d</span> /mnt/disk/alpine
</code></pre></div></div>

<p>It should download and install a minimal alpine environment. I can chroot into
it with an installed script:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/mnt/disk/alpine/enter-chroot
</code></pre></div></div>

<p>Exit chroot by exiting the shell.</p>

<h2 id="further-steps">Further steps</h2>

<p>Now I have a way to enter the chroot environment, play with Alpine packages
there and do all the things.</p>

<p>Unfortunately, once the router is rebooted, mount points created by install
script will disappear. So I need to put their creation into the <code class="language-plaintext highlighter-rouge">enter-chroot</code>
script (and ultimately, fix it in the install script). Unmount script (called
<code class="language-plaintext highlighter-rouge">destroy</code>) is not yet robust too.</p>

<p>Chroot environment provides only limited isolation. First problem I’ve found is
that ID mappings used by the router in its <code class="language-plaintext highlighter-rouge">/etc/passwd</code> and <code class="language-plaintext highlighter-rouge">/etc/group</code> don’t
match Alpine base ID mappings. I had to find some compromise. In theory, it
should be possible to use <code class="language-plaintext highlighter-rouge">cgroups</code> for ID mapping and probably more isolation,
up to the level which is provided by Linux containers but I’m not sure if I
really need it. Anyway, Entware provides <code class="language-plaintext highlighter-rouge">unshare</code> utility to play with that.</p>

<p>On the other side, it would be good to make installation script independent of
Entware utilities.</p>

<p>If I want any Alpine service to auto-run when the router boots up, I need to
hook it into router scripts. AsusWRT-Merlin firmware provides a lot of hooks for
that. At least, I’ll use
<a href="https://github.com/RMerl/asuswrt-merlin.ng/wiki/User-scripts#post-mount"><code class="language-plaintext highlighter-rouge">post-mount</code></a>,
<a href="https://github.com/RMerl/asuswrt-merlin.ng/wiki/User-scripts#unmount"><code class="language-plaintext highlighter-rouge">unmount</code></a>
and
<a href="https://github.com/RMerl/asuswrt-merlin.ng/wiki/User-scripts#services-stop"><code class="language-plaintext highlighter-rouge">services-stop</code></a>.</p>

<p>For starting and stopping services Alpine uses
<a href="https://docs.alpinelinux.org/user-handbook/0.1a/Working/openrc.html">OpenRC</a>
init system. OpenRC provides some support for chroot environment but that
requires
<a href="https://wiki.gentoo.org/wiki/OpenRC#Chroot_support">additional configuration</a>.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[In this article I’ll show simple steps to install Alpine in a chroot environment on a SOHO router.]]></summary></entry><entry><title type="html">MS RDP Input Latency Setting</title><link href="https://pelepelin.github.io//msrdp-input-latency/" rel="alternate" type="text/html" title="MS RDP Input Latency Setting" /><published>2023-10-15T00:00:00+00:00</published><updated>2023-10-15T00:00:00+00:00</updated><id>https://pelepelin.github.io//msrdp-input-latency</id><content type="html" xml:base="https://pelepelin.github.io//msrdp-input-latency/"><![CDATA[<p>Working a long time with MS RDP classic client (so called “Remote Desktop Connection”, mstsc.exe),
previously I never knew about this configuration option, found in<br />
<a href="https://www.virtualbox.org/manual/ch12.html#ts_win-host-rdp-client">VirtualBox troubleshooting chapter</a>:</p>

<blockquote>
  <p>RDP client collects input for a certain time before sending it to the RDP server.
The interval can be decreased by setting a Windows registry key to smaller values
than the default of 100. The unit for its values is milliseconds.</p>
</blockquote>

<p>100ms is a pretty noticeable delay.</p>

<blockquote>
  <p>The key does not exist initially and must be of type DWORD.
Depending whether the setting should be changed for an individual user or for
the system, set either of the following.</p>

  <p><code class="language-plaintext highlighter-rouge">HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Min Send Interval</code>
<code class="language-plaintext highlighter-rouge">HKEY_LOCAL_MACHINE\Software\Microsoft\Terminal Server Client\Min Send Interval</code></p>
</blockquote>]]></content><author><name></name></author><summary type="html"><![CDATA[Working a long time with MS RDP classic client (so called “Remote Desktop Connection”, mstsc.exe), previously I never knew about this configuration option, found in VirtualBox troubleshooting chapter:]]></summary></entry><entry><title type="html">Sudo without a password prompt</title><link href="https://pelepelin.github.io//sudo-nopasswd/" rel="alternate" type="text/html" title="Sudo without a password prompt" /><published>2020-08-05T00:00:00+00:00</published><updated>2020-08-05T00:00:00+00:00</updated><id>https://pelepelin.github.io//sudo-nopasswd</id><content type="html" xml:base="https://pelepelin.github.io//sudo-nopasswd/"><![CDATA[<p>I often install new Linux virtual machines where I’m the only interactive user and so I see no sense in entering password every several minutes. Unfortunately, <code class="language-plaintext highlighter-rouge">sudoers</code> syntax is not at all intuitive, so every time I need to google for the same lines to be added.</p>

<ul>
  <li>Run <code class="language-plaintext highlighter-rouge">sudo visudo</code>.</li>
  <li>Update the <code class="language-plaintext highlighter-rouge">%sudo</code> line to be:
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>%sudo   ALL=(ALL:ALL) NOPASSWD: ALL
</code></pre></div>    </div>
  </li>
</ul>

<p><strong>Update</strong>: In Ubuntu 20.04, installer created a file in <code class="language-plaintext highlighter-rouge">/etc/sudoers.d/</code> which overrode the setting in <code class="language-plaintext highlighter-rouge">sudoers</code>. I removed it.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I often install new Linux virtual machines where I’m the only interactive user and so I see no sense in entering password every several minutes. Unfortunately, sudoers syntax is not at all intuitive, so every time I need to google for the same lines to be added.]]></summary></entry><entry><title type="html">Developer’s work is a waterfall</title><link href="https://pelepelin.github.io//Waterfall/" rel="alternate" type="text/html" title="Developer’s work is a waterfall" /><published>2020-02-24T00:00:00+00:00</published><updated>2020-02-24T00:00:00+00:00</updated><id>https://pelepelin.github.io//Waterfall</id><content type="html" xml:base="https://pelepelin.github.io//Waterfall/"><![CDATA[<p>In order to do something you always need to do something else.</p>

<p>That’s how my software development always goes. No matter if it’s a job task or my own wish, before I can achieve what was an initial goal, before I can finish the task, I need to learn and finish a thousand of other things.</p>

<p>Like now. I want to make this blog alive but apart of intial easy setup (thanks to the man whose setup I cloned) it involves perpetual unintended nested learning. Look, I want to make the blog bilingual but the initial template is not suited. So I need to experiment with other templates, but it requires local Jekyll environment. Which I don’t want to set up on my Windows laptop, so I need a good virtualized environment. Also, I’m a bit tired by small annoyances while developing Node.JS applications on Windows, so I’d move all development into this environment and so a seemingly easy short path of using Docker for Windows is less attractive. I’d try <a href="https://docs.microsoft.com/en-us/windows/wsl/wsl2-index">WSL2</a> but it’s not in a Windows public release build yet and I failed to join the Windows Insider Program (maybe it’s for better). So I stick to VirtualBox. Unfortunately, heavy applications in VirtualBox lose up to 30% of performance. Also, on my job workplace I still use some Windows applications during the day. So this time I’ve learned that there are interesting alternatives to using a Linux desktop inside of a VirtualBox window. Namely, <a href="https://sourceforge.net/projects/vcxsrv/">VcXsrv</a> and <a href="https://xpra.org/">Xpra</a> look promising enough for seamless integration of Linux and Windows desktops. VcXsrv is good enough but Xpra is especially interesting as it promises that Linux sessions can survive Windows host reboots the same way as if I use VirtualBox UI. Unfortunately, setup is not that seamless and there are some bugs I’m trying to resolve. So that all becomes really long.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[In order to do something you always need to do something else.]]></summary></entry><entry><title type="html">Windows Run as Administrator</title><link href="https://pelepelin.github.io//Windows-Run-as-Admin/" rel="alternate" type="text/html" title="Windows Run as Administrator" /><published>2020-02-24T00:00:00+00:00</published><updated>2020-02-24T00:00:00+00:00</updated><id>https://pelepelin.github.io//Windows-Run-as-Admin</id><content type="html" xml:base="https://pelepelin.github.io//Windows-Run-as-Admin/"><![CDATA[<p>It would be funny how many things in Windows UI are hidden if it wouldn’t require googling to find them. And if you don’t use a feature often enough you need to search every time as it’s forgotten by that time.</p>

<p>One of those memos is: how to run a command as Administrator. Here it is: <code class="language-plaintext highlighter-rouge">Windows+R</code>, type a command, <code class="language-plaintext highlighter-rouge">Ctrl+Shift+Enter</code>.</p>

<p>How could I guess this <code class="language-plaintext highlighter-rouge">Ctrl+Shift+</code>?</p>]]></content><author><name></name></author><summary type="html"><![CDATA[It would be funny how many things in Windows UI are hidden if it wouldn’t require googling to find them. And if you don’t use a feature often enough you need to search every time as it’s forgotten by that time.]]></summary></entry><entry><title type="html">Set up a Jekyll website</title><link href="https://pelepelin.github.io//Hello-World/" rel="alternate" type="text/html" title="Set up a Jekyll website" /><published>2019-09-29T00:00:00+00:00</published><updated>2019-09-29T00:00:00+00:00</updated><id>https://pelepelin.github.io//Hello-World</id><content type="html" xml:base="https://pelepelin.github.io//Hello-World/"><![CDATA[<p>Recently I’ve thought that having no website is unacceptable for a proficient web developer.</p>

<p>While I’m going to create some demos to showcase my skills later, this is the first step.</p>

<p>I think, having a Jekyll-based blog on GitHub is one of the most geeky ways to create a site for a developer. However, I was lazy enough to set up Ruby locally. It appeared there is a template site called <a href="https://www.jekyllnow.com/about/">Jekyll Now</a> which allows to setup a Jekyll site on GitHub without a local development copy.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Recently I’ve thought that having no website is unacceptable for a proficient web developer.]]></summary></entry></feed>