A network old computers can actually use

An Alpine Linux appliance that hands a Windows 98, Mac OS 9 or DOS machine the services it was built for — DHCP, DNS, NAT, guest SMB1, AFP, FTP, a printer that writes PDFs — on a network of its own.

Repository on GitHub Documentation

If you landed here from a search engine, one of these is probably your problem:

What it builds

One small Linux machine with two network interfaces. The uplink faces the network you already have and takes its Internet access from your ordinary router. The isolated side faces the old machines, and nothing from outside can reach in.

                Internet
                    │
          your existing router
                    │
        ┌───────────┴────────────┐
        │  uplink (eth0)         │
        │                        │
        │   alpine-vde-router    │   DHCP · DNS · NAT
        │                        │   FTP · SMB · AFP
        │  isolated (eth1)       │   IPP/LPD → PDF
        └───────────┬────────────┘   NetDrive
                    │  10.1.0.0/24
    ┌───────────┬───┴────┬───────────┬──────────┐
  Win98       WinXP   Mac OS 9      DOS      anything

On the isolated side the appliance is the router (10.1.0.1 by default), the DHCP server, the DNS server, the file server and the print server at once. An old machine needs no configuration beyond “obtain an address automatically”.

serviceportused by
DHCP67/udpeverything
DNS53everything
NAT—everything that wants the Internet
FTP (anonymous)21 + 10000–10100DOS, Windows, anything scriptable
SMB / CIFS (SMB1)139, 445Windows for Workgroups 3.11, 95, 98, ME, NT, 2000, XP
AFP548Mac OS 8, 9, and OS X
IPP printing → PDF631Windows 98 and later, Linux
LPD printing → PDF515classic Mac OS, and anything with only LPR
NetDrive2002/udpDOS, as a network hard disk

One directory, three protocols

FTP, SMB1 and AFP all serve the same directory, so a Windows 98 box, a Mac OS 9 box and a DOS box are looking at the same files through whichever protocol each of them was born with. Drop a read-only folder underneath the share root and it appears in all three at once; on a VM those are usually virtiofs mounts from the host.

Every file service is guest access with no password, mapped onto a single Unix account. That is a deliberate choice, not a shortcut.

Why no passwords. Windows 98 can only do SMB1 with NTLMv1. Mac OS 9 does AFP with cleartext or DHX. Neither is something to authenticate against with a password you use anywhere else, and most of these clients cannot store a modern one anyway. The security boundary in this design is the network, not the login — the firewall accepts SSH on the uplink and nothing else, and the isolated side is a cul-de-sac. Do not port-forward anything to it from your real router.

A printer that produces files

CUPS with the PDF backend gives the isolated network a queue reachable over IPP (port 631, for Windows 98 and later) and LPD (port 515, for classic Mac OS and anything that only speaks LPR). Print jobs land in the spool directory as PDF files — and because that directory is also shared over SMB and AFP, the same old machine can print a document and then pick up its own PDF.

A trap worth knowing about: without SystemGroup sys root lpadmin in /etc/cups/cups-files.conf, running lpadmin from a root shell is refused with 403 Forbidden — a baffling error to get as root.

A hard disk for DOS over the network

mTCP NetDrive serves a disk image over UDP: the DOS client loads a small TSR and the image appears as an ordinary drive letter with a full DOS filesystem, not a network redirector. It needs about 8 KB resident, which is why it works on machines where nothing else does — a 286 with no room for a file-sharing stack, or a laptop whose drive bay is dead. It is also fast, because the client is doing plain sector reads and writes instead of translating file operations.

The NetDrive server is Michael Brutman's work and is not included in this repository; it is downloaded from his site and dropped onto the appliance.

Emulators plug in without root

Run the appliance as a virtual machine and an optional VDE switch — a virtual ethernet segment that lives in user space — lets QEMU, 86Box and PCem join the isolated network with ordinary user privileges. No bridge, no TAP device, no changes to the host's network configuration, nothing owned by root.

On real hardware the VDE chapter simply does not apply: everything from the router chapter onward is identical, with the share paths pointing at real directories. An old ThinkPad with two network ports will do.

The same network without a virtual machine

This appliance runs the router inside a VM, which is the straightforward way and what the documentation describes. There is another way. VDE ships vde_router, a userspace IPv4 router whose interfaces are connections to VDE switches rather than kernel devices — so a whole routed network can run with no VM, no TAP device and no root at all. Paired with the slirp plugin for the uplink it is a single process:

connect /tmp/vde0
connect slirp:///addr=10.1.9.1/dhcp=10.1.9.20
ifconfig eth0 add 10.1.0.254 255.255.255.0
ifconfig eth1 add 10.1.9.2 255.255.255.0
route add default 10.1.9.1
dhcpd start eth0 10.1.0.20 10.1.0.40

The catch is that vde_router as shipped does not forward packets at all, and attaching it to a segment disturbs that segment: unused addresses appear reachable and duplicate address detection always reports a conflict — which a Windows 98 or Mac OS machine probing for its address at boot will notice.

A fixed build, with nine defect fixes, a rewritten manual page and a HOWTO, is at github.com/zirize/vde-2. The patches are submitted upstream as virtualsquare/vde-2#74 and #75; use upstream instead once those land.

It does not replace this appliance. vde_router routes and hands out addresses; it has no DNS, no file sharing and no print queue, so the services set up here still need somewhere to live. Take it as the answer to “can I have the network without running a VM for it”, not as a drop-in replacement.

Installing it

A VM with 512 MB of RAM, about 2 GB of disk, two network interfaces and an Alpine Linux ISO. Roughly fifteen minutes, most of it waiting for packages to download.

git clone https://github.com/zirize/alpine-vde-router
cd alpine-vde-router
cp config.example.sh config.sh
nano config.sh                       # addresses, shares, what to install

./scripts/host/vde-switch.sh install # optional: VDE switch for emulators
./scripts/host/create-vm.sh          # define the VM
./scripts/host/install-alpine.py     # unattended Alpine install
./scripts/host/push-scripts.sh       # copy the setup scripts over

ssh root@<the address you set> 'cd /root/setup && ./install-all.sh'

Any service can be switched off in config.sh. A machine that only needs to be a router is a two-minute install.

If you would rather understand each step than run a script — which is the point of the repository — every chapter gives the individual commands to paste by hand. The scripts and the documentation are the same commands. Nothing happens off-screen. Each chapter is arranged the same way: what this does, do it, check it (with the output you should see), and the failures people actually hit.

The documentation

01 · Overviewhow the pieces fit, and what to decide before you start
02 · The VDE switchhost side; only for emulators, skip on real hardware
03 · Creating the VMlibvirt domain, two NICs, shared folders
04 · Installing Alpineunattended, or by hand
05 · RouterNAT, DHCP, DNS, firewall
06 · File sharingFTP, SMB1 for Windows 9x, AFP for classic Mac OS
07 · PrintingIPP and LPD, printed output as PDF
08 · NetDrivea network hard disk for DOS
09 · Connecting clientsWindows 98/XP, Mac OS 9, DOS, QEMU, 86Box
10 · On a physical serverwhat changes on real hardware
11 · Troubleshootingsymptoms, causes, fixes

The troubleshooting chapter is organised as a symptom index: no DHCP, missing NAT, DNS leaking to the outside, Windows 98 not seeing the shares, Mac OS 9 error −50, netatalk reporting a crash, port 631 refused, printing that produces no PDF, an emulator that cannot join the switch.

Tested on

Built and verified end to end on Alpine 3.24.2 with libvirt/QEMU on Ubuntu. Every command in the documentation was run on a machine installed from scratch by following the repository.

MIT licensed for the scripts and documentation.