<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>alpine — LowEndSpirit</title>
        <link>https://lowendspirit.com/index.php?p=/</link>
        <pubDate>Thu, 04 Jun 2026 07:18:48 +0000</pubDate>
        <language>en</language>
            <description>alpine — LowEndSpirit</description>
    <atom:link href="https://lowendspirit.com/index.php?p=/discussions/tagged/alpine/feed.rss" rel="self" type="application/rss+xml"/>
    <item>
        <title>Alpine Linux 3.23 - 23mb ram | 71mb disk - guide</title>
        <link>https://lowendspirit.com/index.php?p=/discussion/10647/alpine-linux-3-23-23mb-ram-71mb-disk-guide</link>
        <pubDate>Thu, 12 Mar 2026 18:35:01 +0000</pubDate>
        <category>Technical</category>
        <dc:creator>AnthonySmith</dc:creator>
        <guid isPermaLink="false">10647@/index.php?p=/discussions</guid>
        <description><![CDATA[<p><strong>Minimising Alpine 3.23 on a KVM VPS ran on TierHive</strong></p>

<p>This guide documents how to strip a freshly deployed Alpine 3.23 (should be fine on 3.22 also) VPS down to the minimum RAM and disk footprint without breaking it.</p>

<p>For those reading it running it outside of TierHive, please note this targets KVM-based VPS instances with a virtio-blk disk (<code>/dev/vda</code>), a single network interface, and a static IP assigned at deployment. If your disk is virtio-scsi (<code>/dev/sda</code>) there is one step that differs, noted inline.</p>

<hr />

<h2>Before</h2>

<p>Fresh deploy, cloud-init has run, nothing changed yet, cant run apk, not enough free ram.</p>

<pre><code>              total        used        free      shared  buff/cache   available
Mem:             91          38          25           2          28          47
Swap:             0           0           0
</code></pre>

<pre><code>Filesystem      Size      Used Available Use% Mounted on
/dev/vda       953.0M    164.4M    741.7M  18% /
</code></pre>

<hr />

<h2>Stage 1: Kernel Module Blacklist and Initramfs</h2>

<p>The Alpine virt kernel loads modules that have no purpose on a headless KVM VPS: USB controllers, graphics drivers, cloud-specific network drivers for AWS and GCP, I2C buses, input devices, and more. Blacklisting them stops them loading on boot.</p>

<p>Some modules, however, are listed in the kernel <code>modules=</code> boot parameter and load before the blacklist is read. They also need removing from the initramfs features list. Do all three together so only one <code>mkinitfs</code> run is needed.</p>

<p>Create the blacklist:</p>

<pre><code>cat &gt; /etc/modprobe.d/blacklist-unnecessary.conf &lt;&lt; 'EOF'
# Graphics (headless server)
blacklist drm
blacklist drm_kms_helper
blacklist simpledrm
blacklist virtio_gpu
blacklist fb

# KVM (not nesting VMs)
blacklist kvm
blacklist kvm_amd
blacklist kvm_intel

# Legacy devices
blacklist floppy
blacklist cdrom
blacklist sr_mod
blacklist isofs

# HID/input (headless)
blacklist hid
blacklist usbhid
blacklist hid_generic
blacklist psmouse
blacklist mousedev

# Wrong cloud drivers (not GCP/AWS)
blacklist gve
blacklist ena

# Force block DRM (blacklist alone does not work, ACPI triggers it)
install drm /bin/true
install drm_kms_helper /bin/true
install simpledrm /bin/true
install fb /bin/true

# USB (not needed on VPS)
blacklist usbcore
blacklist xhci_hcd
blacklist xhci_pci
blacklist usb_common

# I2C (not needed)
blacklist i2c_core
blacklist i2c_smbus
blacklist i2c_piix4

# Input (headless)
blacklist evdev
blacklist button

# Misc not needed
blacklist loop
blacklist ata_generic
blacklist i6300esb
blacklist qemu_fw_cfg

# Memory ballooning
blacklist virtio_balloon

# Hard block loop device (blacklist entry alone is not always sufficient)
install loop /bin/true
EOF
</code></pre>

<p>Strip the initramfs down to what a KVM virtio-blk instance actually needs. The default includes USB, CDROM, NVMe, RAID, SCSI, and cloud-specific drivers that will never be used:</p>

<pre><code>sed -i 's/^features=.*/features="base ext4 virtio"/' /etc/mkinitfs/mkinitfs.conf
</code></pre>

<blockquote><div>
  <p>If your disk is virtio-scsi (<code>/dev/sda</code>) keep <code>scsi</code> in the features list: <code>features="base ext4 scsi virtio"</code></p>
</div></blockquote>

<p>Fix the bootloader. The <code>modules=</code> parameter loads drivers early, before the blacklist runs. Remove <code>usb-storage</code>, <code>ena</code>, and <code>gve</code> from it. Also add the tuning parameters now so they are in place for the reboot at the end of this guide.</p>

<p>For <code>/boot/extlinux.conf</code>:</p>

<pre><code>sed -i 's/,usb-storage,ext4,ena,gve/,ext4 ipv6.disable=1 audit=0 nowatchdog/' /boot/extlinux.conf
</code></pre>

<p>For <code>/etc/update-extlinux.conf</code> (persists the change across kernel updates):</p>

<pre><code>sed -i 's/,usb-storage,ext4,ena,gve/,ext4/' /etc/update-extlinux.conf
sed -i 's/default_kernel_opts="/default_kernel_opts="ipv6.disable=1 audit=0 nowatchdog /' /etc/update-extlinux.conf
</code></pre>

<p>The parameters added:</p>

<ul>
<li><code>ipv6.disable=1</code> disables IPv6 at kernel level, removing the associated threads and memory allocations. Skip this if you use IPv6.</li>
<li><code>audit=0</code> disables the Linux audit subsystem. It serves no purpose on a VPS, runs a kernel thread, and pre-allocates slab memory.</li>
<li><code>nowatchdog</code> disables the softlockup and hardlockup detectors.</li>
</ul>

<p>Rebuild the initramfs:</p>

<pre><code>mkinitfs
</code></pre>

<hr />

<h2>Stage 2: Replace OpenSSH with Dropbear</h2>

<p>Dropbear is a minimal SSH server designed for low-resource systems. It is significantly smaller than OpenSSH and links against far fewer libraries. On a NAT VPS with a single exposed port, the switch must be done atomically: stop sshd and start dropbear in one command or you will lose access.</p>

<pre><code>apk add dropbear
rc-service sshd stop &amp;&amp; rc-service dropbear start
rc-update del sshd default
rc-update add dropbear default
apk del openssh openssh-client-common openssh-client-default openssh-keygen openssh-server openssh-server-common openssh-server-common-openrc openssh-server-pam openssh-sftp-server
</code></pre>

<p>Your session might drop. Reconnect on the same port as before.</p>

<hr />

<h2>Stage 3: Remove Cloud-Init and Python</h2>

<p>Cloud-init runs once at first boot to configure the instance from the provider metadata. After that it does nothing. It pulls in Python 3 and a large set of dependencies. Since it has already run and the instance is configured, all of it can be removed, if you want to keep python, remove the '|py3-|python3|pyc' part in the command.</p>

<pre><code>apk del $(grep "^P:" /lib/apk/db/installed | sed 's/^P://' | grep -E "^(cloud-init|cloud-utils|py3-|python3|pyc)")
</code></pre>

<hr />

<h2>Stage 4: Package Cleanup</h2>

<p>Remove packages that serve no purpose on a running VPS. This covers NTP replacement, redundant shell and user management tools, hardware management utilities for hardware that does not exist, and network drivers for other cloud platforms.</p>

<p><strong>Replace chrony with busybox ntpd.</strong> Chrony is a full-featured NTP implementation. Busybox includes a lightweight ntpd applet that requires no additional package:</p>

<pre><code>rc-service chronyd stop
rc-update del chronyd default
rc-update add ntpd default
apk del chrony chrony-openrc
</code></pre>

<blockquote><div>
  <p><strong>NTP is optional on KVM.</strong> The guest clock is disciplined by the hypervisor via <code>kvm-clock</code>. On TierHive and similar platforms where the end user has no control over VM suspension or migration, the hypervisor keeps the clock accurate and ntpd adds no value. To skip NTP entirely, do not add the ntpd service.</p>
</div></blockquote>

<p>Remove packages with no runtime use:</p>

<pre><code>apk del bash sudo doas nvme-cli syslinux mtools numactl curl e2fsprogs-extra partx qemu-guest-agent qemu-guest-agent-openrc
</code></pre>

<blockquote><div>
  <p><code>qemu-guest-agent</code> enables live snapshots and guest introspection from the hypervisor. If your hosting platform uses QEMU guest operations, keep it.</p>
</div></blockquote>

<p>Remove orphaned libraries left behind by the packages above. Some will be retained by apk because the kernel package depends on them, which is expected:</p>

<pre><code>apk del readline gdbm mpdecimal sqlite-libs yaml p11-kit libtasn1 gnutls nettle gmp libidn2 libunistring libexpat libedit libffi shadow tzdata libseccomp libncursesw libpanelw ncurses-terminfo-base
</code></pre>

<p>Remove dhcpcd. Once a VPS has a static IP assigned at deployment, the DHCP client is not needed:</p>

<pre><code>apk del dhcpcd dhcpcd-openrc
</code></pre>

<p>Clear the package cache:</p>

<pre><code>rm -rf /var/cache/apk/*
</code></pre>

<hr />

<h2>Stage 5: Service Cleanup</h2>

<p>Disable services that have nothing to do on a KVM VPS:</p>

<pre><code>rc-update del acpid boot
rc-update del hwclock boot
rc-update del swap boot
</code></pre>

<ul>
<li><code>acpid</code> handles ACPI events such as power button presses. The hypervisor manages power state on a VPS, not the guest.</li>
<li><code>hwclock</code> syncs the hardware clock at boot and shutdown. On KVM the RTC is virtualised and managed by the hypervisor.</li>
<li><code>swap</code> checks for and activates swap devices. There is no swap.</li>
</ul>

<hr />

<h2>Stage 6: System Tuning</h2>

<p><strong>Fix IPv6 sysctl errors</strong></p>

<p>With <code>ipv6.disable=1</code> set, the kernel no longer has IPv6 sysctl keys. The default Alpine sysctl file tries to set them anyway and produces errors at boot. Comment them out:</p>

<pre><code>sed -i '/net\.ipv6/s/^/# /' /usr/lib/sysctl.d/00-alpine.conf
</code></pre>

<p><strong>Prevent debugfs and tracefs from mounting</strong></p>

<p>These kernel debug filesystems expose internal state and are not needed on a production VPS. Note that the memory for the tracing framework is allocated at kernel initialisation regardless; this only stops the filesystems from being accessible:</p>

<pre><code>sed -i 's/mount -n -t debugfs/: #mount -n -t debugfs/' /etc/init.d/sysfs
sed -i 's/mount -n -t tracefs/: #mount -n -t tracefs/' /etc/init.d/sysfs
</code></pre>

<p><strong>Sysctl tuning</strong></p>

<p>The default network socket buffers are sized for servers under heavy load, not minimal VPS instances. Reduce them along with a few other settings:</p>

<pre><code>cat &gt; /etc/sysctl.d/10-minvps.conf &lt;&lt; 'EOF'
# Reduce network socket buffers
net.core.rmem_default = 32768
net.core.wmem_default = 32768
net.core.rmem_max = 131072
net.core.wmem_max = 131072
net.core.netdev_max_backlog = 64
net.core.somaxconn = 128

# Reclaim inode and dentry caches more aggressively under memory pressure
vm.vfs_cache_pressure = 500

# Reduce PID table overhead
kernel.pid_max = 4096

# Dirty page writeback thresholds
vm.dirty_background_ratio = 5
vm.dirty_ratio = 10

# Disable watchdog
kernel.watchdog = 0
EOF
</code></pre>

<p><strong>Switch syslogd to in-memory circular buffer</strong></p>

<p>By default syslogd writes to <code>/var/log/messages</code> on disk. Switching to a circular buffer stores logs in memory instead. They remain accessible via <code>logread</code>. This removes the ongoing disk writes and the associated page cache overhead:</p>

<pre><code>sed -i 's/SYSLOGD_OPTS="-t"/SYSLOGD_OPTS="-t -C64"/' /etc/conf.d/syslog
</code></pre>

<p><strong>Reduce block device read-ahead</strong></p>

<p>The kernel defaults to 8MB of read-ahead on the block device. On virtual storage this is wasted memory. 128KB is more than sufficient:</p>

<pre><code>echo 128 &gt; /sys/block/vda/queue/read_ahead_kb

cat &gt; /etc/local.d/readahead.start &lt;&lt; 'EOF'
#!/bin/sh
echo 128 &gt; /sys/block/vda/queue/read_ahead_kb
EOF

chmod +x /etc/local.d/readahead.start
rc-update add local default
</code></pre>

<hr />

<h2>Reboot</h2>

<pre><code>reboot
</code></pre>

<hr />

<h2>After</h2>

<pre><code>              total        used        free      shared  buff/cache   available
Mem:             91          23          51           0          17          63
Swap:             0           0           0
</code></pre>

<pre><code>Filesystem      Size      Used Available Use% Mounted on
/dev/vda       953.0M     71.9M    834.1M   8% /
</code></pre>

<p>RAM down from 38MB to 23MB. Disk down from 164.4MB to 71.9MB.</p>

<hr />

<h2>What Is Still Running</h2>

<p>The only userspace processes after boot are <code>syslogd</code> (circular buffer mode), <code>dropbear</code>, and two getty processes: one on <code>ttyS0</code> for serial console access and one on <code>tty1</code> for the browser-based console panel.</p>

<p>The loaded kernel modules are exactly what the system requires: the virtio stack (virtio-blk, virtio-net, virtio-rng), the ext4 filesystem stack (ext4, jbd2, mbcache, crc16), hardware AES acceleration (aesni-intel, ghash-clmulni-intel, gf128mul), rng-core, net-failover, failover, and af-packet for raw socket support.</p>

<p>Notes for tinkerers:</p>

<p>Two kernel threads will appear in <code>ps aux</code> that look surprising: <code>[scsi_eh_0]</code> and <code>[scsi_eh_1]</code>. These are SCSI error handler threads compiled into the virt kernel. They are dormant and cannot be removed without a custom kernel.</p>

<p>Similarly, <code>[watchdogd]</code> persists despite <code>nowatchdog</code> in the cmdline. There is no <code>/dev/watchdog</code> device present and no watchdog module loaded. The thread does nothing.</p>

<hr />

<p>I have done this on the VPS that runs <a href="https://backtogeek.com" rel="nofollow">https://backtogeek.com</a> if you want to have a look as a performance indication, the whole thing runs on the 128mb, 1gb disk, low priority tier (the $0.10 /month $0.000135 /hour one) its a nothing site, just playing with rust to see how compact i can get a bespoke thingy running with tls support, it uses about 25mb in total to run that site, i will finish it one day and release it (open source) as a hackernews clone/micro blog platform</p>

<p>Anyway... hopefully that injects some low-end spirit into you!</p>

<p>More to come, its not meant to be a tierhive promotion, but it's what I have to work on, and it does not get much more low end than tierhive, this should work on pretty much any kvm host, if any hosts want to provide a VPS for me to test future crap on, I am happy to use your links instead!</p>

<p>version on the tierhive blog: <a href="https://tierhive.com/blog/tierhive-howto/how-to-run-alpine-with-just-23mb-ram" rel="nofollow">https://tierhive.com/blog/tierhive-howto/how-to-run-alpine-with-just-23mb-ram</a></p>

<p>Coming soon, similar guide for Debian 13</p>
]]>
        </description>
    </item>
    <item>
        <title>Issue installing Alpine Linux on a VPS</title>
        <link>https://lowendspirit.com/index.php?p=/discussion/4156/issue-installing-alpine-linux-on-a-vps</link>
        <pubDate>Tue, 10 May 2022 15:10:24 +0000</pubDate>
        <category>Help</category>
        <dc:creator>o_be_one</dc:creator>
        <guid isPermaLink="false">4156@/index.php?p=/discussions</guid>
        <description><![CDATA[<p>Hello all,</p>

<p>i have several VPS with VirMach since years, all running Alpine Linux i've installed from netboot.xyz (network install). They are all running smooth since a while but there is one i've never been able to install. It's been a while, as i was "well just let it on the side for now eventually VirMach may have an issue they will fix" but after months i'm not able to install my server. I'm pretty sure anyway there is a workaround without involving my provider so i wanted to ask the community here first.</p>

<p>This VPS is able to run with they're premade setup (i've tried Ubuntu, works).<br />
Again i already have several VPS with the same provider, all on Alpine Linux, same setup used. The difference between them is the node where they are hosted, as i often jump on new discounts they have (this one is a BF-2021 special, i have 4 VPS from this offer, 3 are working with Alpine).</p>

<p>Please see following screenshot to view my issue:<br />
<img src="https://lowendspirit.com/uploads/editor/18/bdj4o3auzrxj.png" alt="" title="" /></p>

<p>Thank you so much for sharing your time helping to debug <img src="https://lowendspirit.com/plugins/emojiextender/emoji/twitter/smile.png" title=":)" alt=":)" height="18" />.</p>
]]>
        </description>
    </item>
   </channel>
</rss>
