Lean and Local: DNS, VPN, IRC and Ad Blocking

Running a full-featured network stack on old hardware isn’t just possible, it’s efficient. This post covers how I configured Alpine Linux as a diskless system hosting DNS resolution, ad blocking, VPN access, and a local IRC server.
Why Diskless?
The system boots entirely from RAM using Alpine’s diskless
mode. This eliminates wear on flash storage, improves startup speed, and ensures a clean slate on each reboot. Changes are persisted manually using lbu
, making the setup both robust and disposable, perfect for low-power hardware with limited write endurance.
Base Setup
The machine is an old D-Class thin client with 4 GB RAM and an AMD G-T48E CPU. Alpine Linux 3.21 is installed with only essential packages (229 total). Services are configured via OpenRC
and restored from compressed overlays on boot.
DNS and Ad Blocking: Blocky
Blocky handles all local DNS queries, with DoT upstreams, custom mappings, and deny lists per client.
Highlights:
- Local resolution for custom domains like
joren.blog
- Cloudflare, Google as upstream resolvers
- Per-IP blocking rules
- Prometheus metrics for monitoring
Example config:
blocking:
denylists:
ads:
- https://big.oisd.nl/domainswild
vtm:
- /home/joren/dns/vtmgo.txt
clientGroupsBlock:
default:
- ads
172.16.0.120:
- vtm
VPN: WireGuard via PiVPN
WireGuard provides encrypted access to the local network, and PiVPN makes managing it trivial. While WireGuard itself is minimal, PiVPN adds essential automation without requiring a full control panel or web UI.
Key benefits in this setup:
-
Client management is simple and scriptable. Adding, disabling, or revoking peers takes seconds:
pivpn -a # add client pivpn -r # remove client pivpn -off <name> # temporarily disable
-
Mobile-friendly. Each config can be exported as a QR code with
pivpn -qr
, which is perfect for importing into the WireGuard mobile app. -
Monitoring support. View live connections with
pivpn -c
, or audit all issued keys withpivpn -l
. -
Backups included. One command backs up all configs:
pivpn -bk
.
Example output:
::: Connected Clients List :::
Name Remote IP Virtual IP Bytes Received Bytes Sent Last Seen
Phone 84.199.x.x:60042 10.60.150.2 439MiB 3.3GiB May 29 2025 - 22:39:56
In this context, PiVPN reduces the friction of managing WireGuard while remaining fully compatible with Alpine’s diskless, CLI-centric philosophy. No services are wasted, and all changes remain under user control.
IRC: ngIRCd
For real-time messaging, I run a public-facing ngIRCd instance accessible over both plaintext (port 6667) and encrypted TLS (ports 6697, 6698). Despite its modest footprint, ngIRCd is stable, portable, and well-suited for both LAN and internet-facing deployments.
The server is configured to:
- Autojoin clients to a default
#General
channel - Support cloaking for user privacy
- Restrict joins per user/IP to prevent abuse
- Provide operator access with predefined credentials
- Disable DNS and Ident lookups for speed and reduced leakage
Here’s a snapshot of the active configuration:
[Global]
Name = irc.alpine4071
Info = RAM-only IRC Server
Listen = 0.0.0.0
Ports = 6667
MotdPhrase = "Welcome to our RAM-only IRC server!"
AdminInfo1 = IRC Server
AdminInfo2 = Anywhere On Earth
AdminEMail = admin@irc.alpine4071
[SSL]
CertFile = /home/joren/certs/fullchain1.pem
KeyFile = /home/joren/certs/privkey1.pem
Ports = 6697, 6698
Authentication and moderation are handled via the [Operator]
block, and all users are dropped into a predefined channel:
[Channel]
Name = #General
Topic = General Channel
Autojoin = yes
Why ngIRCd?
- It works well on memory-constrained systems.
- It doesn’t require database backends or scripting engines.
- It supports modern essentials like TLS, cloaking, and structured limits.
- It’s simple to secure and configure, even when exposed to the open internet.
This makes ngIRCd a perfect fit for remote support, small private networks, or just having your own IRC node to tinker with, without touching a gigabyte of storage.
You can connect today via:
irc://alpine-4071.duckdns.org:6667 (plaintext)
ircs://alpine-4071.duckdns.org:6697 (TLS)
Making It Stick: LBU
To persist changes in a stateless system, I use Alpine’s lbu
:
lbu include /etc/blocky/config.yml
lbu include /etc/ngircd/ngircd.conf
lbu commit -d
This updates the overlay that Alpine loads at each boot. All runtime data stays in RAM.
Runlevel Integration
All services are enabled through OpenRC:
rc-update add blocky default
rc-update add wg-quick default
rc-update add ngircd default
rc-update add iptables default
Boot time is under 10 seconds, with full network stack active by the time DHCP finishes.
Final Thoughts
Alpine’s diskless approach is perfect for resilient, low-maintenance edge systems. Combined with fast tools like Blocky and WireGuard, even minimal hardware becomes a capable, efficient network node, quietly resolving DNS, filtering traffic, handling VPN access, and hosting IRC.