{"id":15148710,"url":"https://github.com/drduh/pc-engines-apu-router-guide","last_synced_at":"2025-03-26T22:10:39.049Z","repository":{"id":97971885,"uuid":"90302791","full_name":"drduh/PC-Engines-APU-Router-Guide","owner":"drduh","description":"Guide to building a Linux or BSD router on the PC Engines APU platform","archived":false,"fork":false,"pushed_at":"2024-08-18T23:12:43.000Z","size":140,"stargazers_count":169,"open_issues_count":0,"forks_count":25,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-03-24T09:45:10.384Z","etag":null,"topics":["debian","firewall","home-network","home-security","homelab","iptables","linux","openbsd","pcengines","privacy","router","security","vpn","walkthrough"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/drduh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["drduh"]}},"created_at":"2017-05-04T19:38:28.000Z","updated_at":"2025-03-23T20:57:04.000Z","dependencies_parsed_at":null,"dependency_job_id":"baf0ed2c-06ad-44c9-b2f2-e54ddd4de930","html_url":"https://github.com/drduh/PC-Engines-APU-Router-Guide","commit_stats":{"total_commits":62,"total_committers":3,"mean_commits":"20.666666666666668","dds":"0.32258064516129037","last_synced_commit":"bd0f36e21e5938898dda33bce03d109071dd19dd"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drduh%2FPC-Engines-APU-Router-Guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drduh%2FPC-Engines-APU-Router-Guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drduh%2FPC-Engines-APU-Router-Guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drduh%2FPC-Engines-APU-Router-Guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/drduh","download_url":"https://codeload.github.com/drduh/PC-Engines-APU-Router-Guide/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245743426,"owners_count":20665092,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["debian","firewall","home-network","home-security","homelab","iptables","linux","openbsd","pcengines","privacy","router","security","vpn","walkthrough"],"created_at":"2024-09-26T13:21:55.930Z","updated_at":"2025-03-26T22:10:39.022Z","avatar_url":"https://github.com/drduh.png","language":null,"funding_links":["https://github.com/sponsors/drduh"],"categories":[],"sub_categories":[],"readme":"**Important** After many years of service, the PC Engines APU platform is now [EOL](https://www.pcengines.ch/eol.htm).\n\nThis guide demonstrates how to build a wired/wireless router using the PC Engines [APU platform](https://www.pcengines.ch/apu.htm) and a free operating system like [OpenBSD](https://www.openbsd.org/) or [Debian](https://www.debian.org/distrib/) to be used for [network address translation](https://computer.howstuffworks.com/nat.htm), as a stateful firewall, to filter Web traffic, and more.\n\nI am **not** responsible for anything you do by following any part of this guide!\n\n# Overview\n\nThe completed router configuration will enable:\n\n* An egress Ethernet interface for Internet routing - can be connected to WAN or a cable modem\n* A local wireless interface on `192.168.1.0/24`\n* A local Ethernet interface on `172.16.1.0/24`\n* A local Ethernet interface on `10.8.1.0/24`\n* An additional (4th) Ethernet interface is available on APU4\n\n## Hardware\n\nThis guide should work on any PC Engines APU model. Here is a suggested parts list:\n\n| Part | Description | Cost\n|------|-------------|------\n| [apu4c4](https://pcengines.ch/apu4c4.htm) | apu4c4 system board | $117.50\n| [case1d2bluu](https://pcengines.ch/case1d2bluu.htm) | Enclosure 3 LAN, blue | $9.40\n| [ac12vus2](https://pcengines.ch/ac12vus2.htm) | AC adapter 12V 2A US plug | $4.10\n| [msata16g](https://pcengines.ch/msata16g.htm) | SSD M-Sata 16GB MLC, Phison S11 | $15.50\n| [wle200nx](https://pcengines.ch/wle200nx.htm) | Compex WLE200NX miniPCI express card | $19.00\n| 2 x [pigsma](https://pcengines.ch/pigsma.htm) | Cable I-PEX -\u003e reverse SMA | $2.70\n| 2 x [antsmadb](https://pcengines.ch/antsmadb.htm) | Antenna reverse SMA dual band | $4.10\n\n**Note** WLE600VX and WLE900VX cards will likely not work due to [regulatory compliance reasons](https://medium.com/@renaudcerrato/how-to-build-your-own-wireless-router-from-scratch-part-3-d54eecce157f).\n\nTo connect over serial, you will need a [USB to Serial (9-Pin) Converter Cable](https://www.amazon.com/gp/product/B00IDSM6BW) and [Modem Serial RS232 Cable](https://www.amazon.com/gp/product/B000067SCH), also available from [PC Engines](https://www.pcengines.ch/usbcom1a.htm).\n\nSee [Issue #1](https://github.com/drduh/PC-Engines-APU-Router-Guide/issues/1) for a list of alternative parts.\n\n## Assembly\n\nClear an area to work and unpack all the materials. Follow the [apu cooling assembly instructions](https://www.pcengines.ch/apucool.htm) to install the heat conduction plate.\n\nAttach the mSATA disk and miniPCI wireless adapter in their respective slots.\n\nSee the relevant APU series manual for detailed board information:\n\n* [APU2](https://www.pcengines.ch/pdf/apu2.pdf)\n* [APU3](https://www.pcengines.ch/pdf/apu3.pdf)\n* [APU4](https://www.pcengines.ch/pdf/apu4.pdf)\n\n**Note** Wireless radio cards are ESD sensitive, especially the RF switch and the power amplifier. To avoid damage by electrostatic discharge, the following installation procedure is [recommended](https://www.pcengines.ch/wle200nx.htm):\n\n1. Touch your hands and the bag containing the radio card to a ground point on the router board (for example one of the mounting holes). This will equalize the potential of radio card and router board.\n1. Install the radio card in the miniPCI express socket.\n1. Install the pigtail cable in the cut-out of the enclosure. This will ground the pigtail to the enclosure.\n1. Touch the I-PEX connector of the pigtail to the mounting hole to discharge, then plug onto the radio card.\n\nTo avoid arcing, plug in the DC jack first, then plug the power adapter into mains.\n\nPress `F10` during boot and select `Payload [memtest]` to complete at least one pass.\n\n# Connect over serial\n\nThe APU serial connection uses 115200 baud rate, 8N1 (8 data bits, no parity, 1 stop bit).\n\nOn OpenBSD, use [cu](https://man.openbsd.org/cu):\n\n```console\ndoas cu -r -s 115200 -l cuaU0\n```\n\nOn Linux, use [screen](https://www.gnu.org/software/screen/manual/screen.html):\n\n```console\nscreen /dev/ttyUSB0 115200 8N1\n```\n\nOr use [minicom](https://linux.die.net/man/1/minicom):\n\n```console\nsudo minicom -D /dev/ttyUSB0\n```\n\nPower on the APU and make note of the firmware version displayed briefly during boot.\n\n# Updating firmware\n\nCheck for the latest PC Engines firmware version at [pcengines.github.io](https://pcengines.github.io/)\n\n**Note** As of 2023, PC Engines firmware is no longer being updated - see [announcement](https://docs.dasharo.com/variants/pc_engines/post-eol-fw-announcement/)\n\nTo update firmware, first download and extract [TinyCore Linux](https://pcengines.ch/file/apu2-tinycore6.4.img.gz).\n\nDownload and import the [firmware signing key](https://github.com/3mdeb/3mdeb-secpack/tree/master/customer-keys/pcengines/release-keys), then check the file signature:\n\n```console\n$ curl -LO https://raw.githubusercontent.com/3mdeb/3mdeb-secpack/master/customer-keys/pcengines/release-keys/pcengines-open-source-firmware-release-4.19-key.asc\n\n$ gpg --import pcengines-open-source-firmware-release-4.19-key.asc\ngpg: key 0x30A53DE2F5A6D89A: 1 signature not checked due to a missing key\ngpg: key 0x30A53DE2F5A6D89A: public key \"PC Engines open-source firmware release 4.19 signing key\" imported\ngpg: Total number processed: 1\ngpg:               imported: 1\n\n$ gpg apu4_v4.19.0.1.SHA256.sig\ngpg: assuming signed data in 'apu4_v4.19.0.1.SHA256'\ngpg: Signature made Thu 02 Feb 2023 03:22:57 AM PST\ngpg:                using RSA key 05CF36F166C3D676A08AB70F30A53DE2F5A6D89A\ngpg: Good signature from \"PC Engines open-source firmware release 4.19 signing key\" [unknown]\ngpg: WARNING: This key is not certified with a trusted signature!\ngpg:          There is no indication that the signature belongs to the owner.\nPrimary key fingerprint: 05CF 36F1 66C3 D676 A08A  B70F 30A5 3DE2 F5A6 D89A\n\n$ shasum -a 256 apu4_v4.19.0.1.rom 2\u003e/dev/null | grep -q $(cat apu4_v4.19.0.1.SHA256 | awk '{print $1}') \u0026\u0026 echo ok\nok\n```\n\nMount a USB disk and write the TinyCore image, copy the `.rom` file:\n\n```console\ncurl -O https://pcengines.ch/file/apu2-tinycore6.4.img.gz\n\ngzip -d apu2-tinycore6.4.img.gz\n\nsha256sum apu2-tinycore6.4.img\nf5a20eeb01dfea438836e48cb15a18c5780194fed6bf21564fc7c894a1ac06d7  apu2-tinycore6.4.img\n\nsudo dd if=apu2-tinycore6.4.img of=/dev/sdd bs=1M\n\nsudo mkdir /mnt/usb\n\nsudo mount /dev/sdd1 /mnt/usb\n\nsudo cp -v apu4_*.rom /mnt/usb\n\nsudo umount /mnt/usb\n```\n\nConnect the USB disk to the APU, press `F10` at boot and select the USB disk:\n\n```console\nSeaBIOS (version rel-1.14.0.1-0-g8610266a)\n\nPress F10 key now for boot menu\n\nSelect boot device:\n\n1. USB MSC Drive Samsung Flash Drive DUO 1100\n2. AHCI/0: SB2 ATA-11 Hard-Disk (111 GiBytes)\n3. Payload [setup]\n4. Payload [memtest]\n```\n\nCheck the current version:\n\n```console\nroot@pcengines:~# dmesg | grep apu\n[    0.000000] DMI: PC Engines apu4/apu4, BIOS v4.10.0.1 09/10/2019\n```\n\nSave the existing version and write the new one:\n\n```console\nroot@pcengines:~# cd /media/SYSLINUX\n\nroot@pcengines:/media/SYSLINUX# flashrom -p internal -r apu4.rom.$(dmidecode -s baseboard-serial-number|tail -n1).$(date +%F)\n[...]\nFound Winbond flash chip \"W25Q64.V\" (8192 kB, SPI) mapped at physical address 0xff800000.\nReading flash... done.\n\nroot@pcengines:/media/SYSLINUX# flashrom -p internal -w apu4_v4.19.0.1.rom\n[...]\nFound Winbond flash chip \"W25Q64.V\" (8192 kB, SPI) mapped at physical address 0xff800000.\nReading old flash chip contents... done.\nErasing and writing flash chip... Erase/write done.\nVerifying flash... VERIFIED.\n```\n\nUnplug the USB disk and `reboot`\n\n**Optional** On reboot, select `F10` and `Payload [setup]` then `w` to enable BIOS write protection then `s` to save and reboot.\n\nVerify the version by checking serial output during boot:\n\n```\nPC Engines apu4\ncoreboot build 20230131\nBIOS version v4.19.0.1\n```\n\nFrom OpenBSD:\n\n```console\n$ dmesg | grep bios\nbios0 at mainbus0: SMBIOS rev. 2.8 @ 0xcfe8b020 (13 entries)\nbios0: vendor coreboot version \"v4.19.0.1\" date 01/31/2023\nbios0: PC Engines apu4\nacpi0 at bios0: ACPI 6.0\n```\n\nFrom Debian:\n\n```console\n$ sudo dmesg | grep apu\n[    0.000000] DMI: PC Engines apu4/apu4, BIOS v4.19.0.1 01/31/2023\n```\n\n**Note** APU firmware can also be updated from Debian, without rebooting to TinyCore Linux:\n\n```console\nsudo apt install flashrom\n\nwget https://3mdeb.com/open-source-firmware/pcengines/apu4/apu4_v4.19.0.1.rom\n\nsudo flashrom -p internal -w apu2_v4.19.0.1.rom\n```\n\nTo complete the update, shut down Debian and power off the APU fully, then reboot.\n\n# Prepare OS installer\n\nUse another computer to prepare an installer for either OpenBSD or Debian.\n\n## OpenBSD\n\nDownload the installation image - [`amd64/install75.img`](https://cdn.openbsd.org/pub/OpenBSD/7.5/amd64/install75.img) - as well as [`SHA256`](https://cdn.openbsd.org/pub/OpenBSD/7.5/amd64/SHA256) and [`SHA256.sig`](https://cdn.openbsd.org/pub/OpenBSD/7.5/amd64/SHA256.sig) files.\n\nVerify the signatures file and hash of the installation image:\n\n```console\ncat /etc/signify/openbsd-75-base.pub\nuntrusted comment: openbsd 7.5 base public key\nRWRGj1pRpprAfgeF/rgld4ubduChLvTkigA1Zj7WLDsVA4qfYSWOEI8q\n\nsignify -C -p /etc/signify/openbsd-75-base.pub -x SHA256.sig install75.img\nSignature Verified\ninstall75.img: OK\n```\n\nInsert a USB disk. Run `dmesg` to identify its label. Then copy the installation file to the USB disk:\n\nOn OpenBSD:\n\n```console\ndoas dd if=install75.img of=/dev/rsd2c bs=1m\n```\n\nOn Linux:\n\n```console\nsudo dd if=install75.img of=/dev/sdd bs=1M\n```\n\n## Debian\n\nDownload the latest [network installation image](https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/) - as well as [`SHA512SUMS`](https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA512SUMS) and [`SHA512SUMS.sign`](https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA512SUMS.sign) files.\n\nVerify the signatures file and hash of the installation image:\n\n```console\n$ gpg SHA512SUMS.sign\ngpg: assuming signed data in 'SHA512SUMS'\ngpg: Signature made Sat 07 Oct 2023 01:24:41 PM PDT\ngpg:                using RSA key DF9B9C49EAA9298432589D76DA87E80D6294BE9B\ngpg: Can't check signature: No public key\n\n$ gpg --keyserver hkps://keyserver.ubuntu.com:443 --recv DF9B9C49EAA9298432589D76DA87E80D6294BE9B\ngpg: key 0xDA87E80D6294BE9B: public key \"Debian CD signing key \u003cdebian-cd@lists.debian.org\u003e\" imported\ngpg: Total number processed: 1\ngpg:               imported: 1\n\n$ gpg SHA512SUMS.sign\ngpg: Signature made Sat 29 Jun 2024 01:50:21 PM PDT\ngpg:                using RSA key DF9B9C49EAA9298432589D76DA87E80D6294BE9B\ngpg: Good signature from \"Debian CD signing key \u003cdebian-cd@lists.debian.org\u003e\" [unknown]\ngpg: WARNING: This key is not certified with a trusted signature!\ngpg:          There is no indication that the signature belongs to the owner.\nPrimary key fingerprint: DF9B 9C49 EAA9 2984 3258  9D76 DA87 E80D 6294 BE9B\n```\n\nOpenBSD:\n\n```console\ngrep $(sha512 -q debian-12.6.0-amd64-netinst.iso) SHA512SUMS\n712cf43c5c9d60dbd5190144373c18b910c89051193c47534a68b0cd137c99bd8274902f59b25aba3b6ba3e5bca51d7c433c06522f40adb93aacc5e21acf57eb  debian-12.6.0-amd64-netinst.iso\n```\n\nLinux:\n\n```console\ngrep $(sha512sum debian-12.6.0-amd64-netinst.iso) SHA512SUMS\nSHA512SUMS:712cf43c5c9d60dbd5190144373c18b910c89051193c47534a68b0cd137c99bd8274902f59b25aba3b6ba3e5bca51d7c433c06522f40adb93aacc5e21acf57eb  debian-12.6.0-amd64-netinst.iso\n```\n\nInsert a USB disk. Run `dmesg` to identify its label. Then copy the installation file to the USB disk.\n\nOpenBSD:\n\n```console\ndoas dd if=debian-12.6.0-amd64-netinst.iso of=/dev/rsd2c bs=1m\n```\n\nLinux:\n\n```console\nsudo dd if=debian-12.6.0-amd64-netinst.iso of=/dev/sdd bs=1M\n```\n\nUnplug the USB disk and plug it into the APU.\n\n# Installing the OS\n\nPress `F10` at boot and select the USB disk.\n\n## OpenBSD\n\nSet the serial console parameters:\n\n```console\nBooting from Hard Disk...\nUsing drive 0, partition 3.\nLoading......\nprobing: pc0 com0 com1 mem[639K 3325M 752M a20=on]\ndisk: hd0+ hd1+\n\u003e\u003e OpenBSD/amd64 BOOT 3.47\nboot\u003e stty com0 115200\nboot\u003e set tty com0\nswitching console to com\u003e\u003e OpenBSD/amd64 BOOT 3.47\nboot\u003e [Press Enter]\n```\n\nSelect the Install option:\n\n```console\nWelcome to the OpenBSD/amd64 7.5 installation program.\n(I)nstall, (U)pgrade, (A)utoinstall or (S)hell? I\n```\n\nWhen presented with a list of network interfaces, `em0` is the Ethernet port closest to the serial port:\n\n```console\nAvailable network interfaces are: em0 em1 em2 em3 vlan0.\n```\n\nUse DHCP or configure a static route:\n\n```console\nNetwork interface to configure? (name, lladdr, '?', or 'done') [done] em0\nIPv4 address for em0? (or 'autoconf' or 'none') [autoconf] 192.168.1.2\nNetmask for em0? [255.255.255.0]\nIPv6 address for em0? (or 'autoconf' or 'none') [none]\nAvailable network interfaces are: em0 em1 em2 em3 vlan0.\nNetwork interface to configure? (name, lladdr, '?', or 'done') [done]\nDefault IPv4 route? (IPv4 address or 'none') 192.168.1.1\nadd net default: gateway 192.168.1.1\nDNS domain name? (e.g. 'example.com') [my.domain] local\nDNS nameservers? (IP address list or 'none') [none] 192.168.1.1\n```\n\nConfigure the root password and set up a user account:\n\n```console\nPassword for root account? (will not echo)\nPassword for root account? (again)\nStart sshd(8) by default? [yes]\nChange the default console to com0? [yes]\nAvailable speeds are: 9600 19200 38400 57600 115200.\nWhich speed should com0 use? (or 'done') [115200]\nSetup a user? (enter a lower-case loginname, or 'no') [no] sysadm\nFull name for user sysadm? [sysadm]\nPassword for user sysadm? (will not echo)\nPassword for user sysadm? (again)\n```\n\nSelect the internal mSATA disk and default options for partitioning:\n\n```console\nAvailable disks are: sd0 sd1.\nWhich disk is the root disk? ('?' for details) [sd0] ?\n    sd0: ATA, SB2, SBFM naa.0000000000000000 (119.2G)\n    sd1: PNY, USB 2.0 FD, 1100 serial.00000000000000000000 (29.9G)\nAvailable disks are: sd0 sd1.\nWhich disk is the root disk? ('?' for details) [sd0]\n```\n\n**Note** The \"unused\" partition (`/dev/sd0c`) is actually the [entire disk](https://www.openbsd.org/faq/faq14.html#intro).\n\nSelect a [mirror](https://www.openbsd.org/ftp.html) and start the installation:\n\n```console\nHTTP Server? (hostname, list#, 'done' or '?') cdn.openbsd.org\nServer directory? [pub/OpenBSD/7.5/amd64]\n\nSelect sets by entering a set name, a file name pattern or 'all'. De-select\nsets by prepending a '-', e.g.: '-game*'. Selected sets are labelled '[X]'.\n    [X] bsd           [X] base75.tgz    [X] game75.tgz    [X] xfont75.tgz\n    [X] bsd.mp        [X] comp75.tgz    [X] xbase75.tgz   [X] xserv75.tgz\n    [X] bsd.rd        [X] man75.tgz     [X] xshare75.tgz\nSet name(s)? (or 'abort' or 'done') [done]\n```\n\nAfter installation is complete, unplug the USB disk and reboot. See the OpenBSD [FAQ](https://www.openbsd.org/faq/faq4.html#Install) for more information.\n\n## Debian\n\nAt the install menu, select `Tab` to edit boot options and replace `quiet` with:\n\n```\nconsole=ttyS0,115200n8\n```\n\nSelect `Enter` and select an available resolution:\n\n```\nUndefined video mode number: 314\nPress \u003cENTER\u003e to see video modes available, \u003cSPACE\u003e to continue, or wait 30 sec\nMode: Resolution:  Type:\n0 F00   80x25      CGA/MDA/HGC\nEnter a video mode or \"scan\" to scan for additional modes: 0\n```\n\nConfigure a network adapter - `enp1s0` is the interface closest to the serial port.\n\nSelect `Guided - use entire disk and set up LVM` as the partition method. Be sure to select internal mSATA drive and not the USB disk as the installation target (usually `sda`).\n\nSelect `Separate /home, /var, and /tmp partitions` as the [partitioning scheme](https://www.debian.org/releases/stable/armel/apcs03.html.en).\n\nDuring `Software selection` - de-select everything except *SSH server*.\n\nSelect the internal mSATA drive and not the USB disk as the GRUB loader target.\n\n# First boot\n\n## OpenBSD\n\nThe following boot parameters have been appended to `/etc/boot.conf` by the installer and everything should just work:\n\n```\nstty com0 115200\nset tty com0\n```\n\n## Debian\n\nAfter the GRUB menu, output may get stuck at:\n\n```\nLoading Linux 6.1.0-23-amd64 ...\nLoading initial ramdisk ...\n```\n\nIf so, reboot and press `e` at the GRUB menu to enter edit mode, scroll down and replace the word `quiet` with:\n\n```\nconsole=ttyS0,115200n8\n```\n\n**Note** If arrow keys do not work in GRUB, try using Emacs key bindings to navigate the text field:\n\n* `Control-B` to move left\n* `Control-F` to move right\n* `Control-P` to move up\n* `Control-N` to move down\n\nPress `Control-X` to continue booting and you should see console output.\n\n**Note** If you get an error like, `Alert! /dev/sdX1 does not exist dropping to shell` and are dropped to an initramfs prompt, reboot and edit the `quiet` line to point to `/dev/sda1` or correct partition.\n\n# First login\n\n## OpenBSD\n\nLog in as `root` and install [pending updates](https://man.openbsd.org/syspatch) or [switch to -current](https://www.openbsd.org/faq/current.html):\n\n```console\nsyspatch\n```\n\nInstall any pending [firmware updates](https://man.openbsd.org/fw_update):\n\n```console\nfw_update\n```\n\nEdit `/etc/doas.conf` to allow the regular user to run [privileged commands](https://man.openbsd.org/doas.conf) without a password:\n\n```\npermit nopass keepenv :wheel\npermit nopass keepenv root\n```\n\nInstall any needed software:\n\n```console\npkg_add bash zsh vim curl free pftop vnstat\n```\n\nReboot to complete any pending updates.\n\n## Debian\n\nLog in as `root` to get started.\n\nIf necessary, update GRUB by editing `/etc/default/grub` and removing or replacing `quiet` with `console=ttyS0,115200n8` then update the configuration:\n\n```console\nupdate-grub\n```\n\nInstall any pending updates and necessary software:\n\n```console\napt update \u0026\u0026 apt -y upgrade\n\napt -y install lshw lsof vim zsh git sudo dnsmasq net-tools iptables tcpdump hostapd firmware-atheros\n```\n\n**Optional** Change the default login shell to zsh for the primary user:\n\n```\nchsh -s /usr/bin/zsh sysadm\n```\n\n# Configure network interfaces\n\n## OpenBSD\n\nOn the APU, set a local network interface address and make it permanent:\n\n```console\ndoas ifconfig em1 10.8.1.1 255.255.255.0\n\necho \"inet 10.8.1.1 255.255.255.0\" | doas tee /etc/hostname.em1\n```\n\nConfigure an OpenBSD client with DHCP by following the [Networking FAQ](https://www.openbsd.org/faq/faq6.html) or using a static address:\n\n```console\ndoas ifconfig em1 10.8.1.4 255.255.255.0\n\nping -c 1 10.8.1.1\nPING 10.8.1.1 (10.8.1.1): 56 data bytes\n64 bytes from 10.8.1.1: icmp_seq=0 ttl=255 time=0.845 ms\n```\n\n**Optional** Randomize MAC addresses on boot:\n\n```console\necho \"lladdr random\" | doas tee -a /etc/hostname.em0 /etc/hostname.em1 /etc/hostname.em2\n```\n\n## Debian\n\nOn the APU and on another computer, determine the interface names available:\n\n```console\nlshw -C network | grep \"logical name\"\n```\n\nOn the APU, edit `/etc/network/interfaces` to append:\n\n```\nauto enp2s0\niface enp2s0 inet static\naddress 10.8.1.1\nnetmask 255.255.255.0\ngateway 10.8.1.1\n```\n\nWhere `enp2s0` is the network interface one port away from the serial port.\n\nRestart networking and bring up the interface:\n\n```console\nservice networking restart\n\nifup enp2s0\n```\n\nOn another Linux computer, edit `/etc/network/interfaces` to append:\n\n```\nauto eno1\niface eno1 inet static\naddress 10.8.1.2\nnetmask 255.255.255.0\ngateway 10.8.1.1\n```\n\nThen also restart networking and bring up the interface:\n\n```console\nsudo service networking restart\n\nsudo ifup eno1\n```\n\nOr on another OpenBSD computer, edit `/etc/hostname.em0` to append:\n\n```\ninet 10.8.1.4 255.255.255.0\n```\n\nIt should now be possible to ping the router:\n\n```console\nping -c 1 10.8.1.1\nPING 10.8.1.1 (10.8.1.1): 56 data bytes\n64 bytes from 10.8.1.1: icmp_seq=0 ttl=64 time=0.519 ms\n```\n\nTo configure the wireless interface, edit `/etc/network/interfaces` on the APU to include:\n\n```\nauto wlp5s0\niface wlp5s0 inet static\naddress 192.168.1.1\nnetmask 255.255.255.0\nhostapd /etc/hostapd.conf\n```\n\nReboot after verifying network connectivity.\n\n# Configure SSH\n\nFrom a client, an SSH connection to the APU should be possible, but not yet authorized:\n\n```console\n$ ssh sysadm@10.8.1.1\nThe authenticity of host '10.8.1.1 (10.8.1.1)' can't be established.\nECDSA key fingerprint is SHA256:AAAAA.\nAre you sure you want to continue connecting (yes/no)? yes\nWarning: Permanently added '10.8.1.1' (ECDSA) to the list of known hosts.\nPermission denied (publickey,password).\n```\n\nIf using a [YubiKey](https://github.com/drduh/YubiKey-Guide), copy its public key to clipboard:\n\n```console\nssh-add -L | awk '{print $1\" \"$2}' | xclip\n```\n\nOr generate a new SSH key on the client and copy it to clipboard:\n\n```console\nssh-keygen -f -C 'sysadm' ~/.ssh/pcengines\n\nxclip ~/.ssh/pcengines.pub\n```\n\nOn the APU, over the serial connection, as the primary user (e.g., `sysadm` - *not* `root`), configure SSH to accept that key by pasting it into `~/.ssh/authorized_keys`:\n\n```console\nmkdir ~/.ssh ; cat \u003e ~/.ssh/authorized_keys\n[Paste clipboard contents using the middle mouse button or Shift-Insert]\n[Then press Control-D to save]\n```\n\nSSH from a client will now work:\n\n```console\n$ ssh sysadm@10.8.1.1 -i ~/.ssh/pcengines\nHost key fingerprint is SHA256:AAAAA\n\nLinux pcengines 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64\nsysadm@pcengines~ %\n```\n\nConfigure the connection on a client by editing `~/.ssh/config`:\n\n```\nHost pcengines\n  HostName 10.8.1.1\n  IdentityFile ~/.ssh/pcengines\n  User sysadm\n  Port 22\n  ControlMaster auto\n  ControlPath ~/.ssh/master-%r@%h:%p\n  ControlPersist 1m\n```\n\nConnect using the new alias:\n\n```console\nssh pcengines\n```\n\nDownload configuration files:\n\n```console\ngit clone https://github.com/drduh/config\n```\n\nThe serial connection can now be terminated. Be sure to log out with `Ctrl-D` or `exit` before disconnecting, otherwise anyone can plug in the serial cable to assume your session without a passphrase.\n\n# DHCP and DNS\n\n[Dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html) will provide [DHCP](https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol) and handle DNS for the local network(s).\n\nUse [drduh/config/dnsmasq.conf](https://github.com/drduh/config/blob/master/dnsmasq.conf) for a configuration example, including blocked domains:\n\n```console\ncp config/dnsmasq.conf /etc/dnsmasq.conf\n\ncat config/domains/* | tee -a /etc/dnsmasq.conf\n\nvim /etc/dnsmasq.conf\n```\n\nConfigure additional blocklist:\n\n```console\ngit clone https://github.com/StevenBlack/hosts\n\nsudo cp hosts/hosts /etc/dns-blocklist\n```\n\n## OpenBSD\n\nTo install dnsmasq as a service enabled on boot:\n\n```console\ndoas pkg_add dnsmasq\n\ndoas rcctl start dnsmasq\n\ndoas rcctl enable dnsmasq\n```\n\n# Wireless\n\n## OpenBSD\n\n**Note** Wireless performance is currently significantly worse on OpenBSD than Debian.\n\nEdit `/etc/hostname.athn0` to include:\n\n```shell\ninet 192.168.1.1 255.255.255.0\nmedia autoselect mode 11n mediaopt hostap chan 11\nnwid NAME wpakey \"PASSWORD\"\n```\n\nRestart networking:\n\n```console\ndoas sh /etc/netstart\n```\n\n## Debian\n\nInstall the default hostapd configuration:\n\n```console\ncat /usr/share/doc/hostapd/examples/hostapd.conf | sudo tee -a /etc/hostapd.conf\n```\n\nOr use [drduh/config/hostapd.conf](https://github.com/drduh/config/blob/master/hostapd.conf):\n\n```console\nsudo cp config/hostapd.conf /etc/hostapd.conf\n```\n\nEdit the configuration to set the network name and password.\n\n*Tip* Avoid passwords with the characters `'` and `\"`.\n\n```console\nsudo vim /etc/hostapd.conf\n```\n\nEnsure hostapd starts:\n\n```console\nsudo hostapd /etc/hostapd.conf\n```\n\n**Note** You may need to manually assign the interface an address:\n\n```console\nsudo ifconfig wlp5s0 192.168.1.1\n```\n\n# IP forwarding\n\nIn order to be a router, [IP forwarding](https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt) must be enabled.\n\n## OpenBSD\n\nEnable now and on boot:\n\n```console\ndoas sysctl net.inet.ip.forwarding=1\n\necho \"net.inet.ip.forwarding=1\" | doas tee -a /etc/sysctl.conf\n```\n\n## Debian\n\nEnable now and on boot:\n\n```console\nsudo sysctl -w net.ipv4.ip_forward=1\n\necho \"net.ipv4.ip_forward=1\" | sudo tee --append /etc/sysctl.conf\n```\n\n# Configure firewall\n\n## OpenBSD\n\nSee [PF - Building a Router](https://www.openbsd.org/faq/pf/example1.html), or use [drduh/config/pf](https://github.com/drduh/config/blob/master/pf/) files:\n\n```console\ndoas mkdir /etc/pf\n\ndoas cp config/pf/pf.conf /etc/\n\ndoas cp config/pf/blocklist config/pf/martians config/pf/private /etc/pf/\n```\n\nTurn PF off and back on again:\n\n```console\ndoas pfctl -d\n\ndoas pfctl -e -f /etc/pf.conf\n```\n\n**Optional** Use [drduh/config/scripts/pf-blocklist.sh](https://github.com/drduh/config/blob/master/scripts/pf-blocklist.sh) to find and block unwanted networks.\n\nTo inspect blocked traffic:\n\n```console\ndoas tcpdump -ni pflog0\n```\n\n## Debian\n\nUse [Iptables](https://en.wikipedia.org/wiki/Iptables) to manage a stateful firewall.\n\nUse [drduh/config/scripts/iptables.sh](https://github.com/drduh/config/blob/master/scripts/iptables.sh) and edit it to your needs:\n\n```console\nsudo cp config/scripts/iptables.sh /etc\n\nsudo vim /etc/iptables.sh\n\nsudo chmod +x /etc/iptables.sh\n\nsudo /etc/iptables.sh\n```\n\nSave the firewall rules to apply them on boot:\n\n```console\nsudo iptables-save | tee /etc/iptables/rules.v4\n```\n\n# Privoxy\n\n[Privoxy](https://www.privoxy.org/) is a powerful Web proxy capable of filtering and rewriting URLs to block ads, upgrade HTTP connections, and more.\n\n## Debian\n\nInstall Privoxy:\n\n```console\nsudo apt -y install privoxy\n```\n\nUse [drduh/config/privoxy/config](https://github.com/drduh/config/blob/master/privoxy/config) and [drduh/config/privoxy/user.action](https://github.com/drduh/config/blob/master/privoxy/user.action) - or edit the configuration yourself.\n\n```console\nsudo cp config/privoxy/config config/privoxy/user.action /etc/privoxy/\n```\n\nRestart the service and check the log:\n\n```console\nsudo service privoxy restart\n\nsudo tail -f /var/log/privoxy/logfile\n```\n\n# Lighttpd\n\n[Lighttpd](https://www.lighttpd.net/) with [mod_magnet](https://redmine.lighttpd.net/projects/1/wiki/Docs_ModMagnet) makes for a highly capable Web server which can be used to replace ad images with custom content, upload and share content on the local network, act as a captive portal, and more.\n\n## Debian\n\nInstall Lighttpd with ModMagnet:\n\n```console\nsudo apt -y install lighttpd lighttpd-mod-magnet\n```\n\nUse [drduh/config/lighttpd/lighttpd.conf](https://github.com/drduh/config/blob/master/lighttpd/lighttpd.conf) and [drduh/config/lighttpd/magnet.luau](https://github.com/drduh/config/blob/master/lighttpd/magnet.luau) - or edit the configuration yourself.\n\n```console\nsudo cp config/lighttpd/lighttpd.conf config/lighttpd/magnet.luau /etc/lighttpd/\n```\n\nRestart the service and check the log:\n\n```console\nsudo service lighttpd restart\n\nsudo cat /var/log/lighttpd/error.log\n```\n\n# DNSCrypt\n\nFirst install `minisign` or build from [source](https://github.com/jedisct1/minisign/releases/latest)\n\nDownload the latest Linux release - [`dnscrypt-proxy-linux_x86_64-*.tar.gz`](https://github.com/DNSCrypt/dnscrypt-proxy/releases/latest), verify it and edit the configuration:\n\n```console\ncurl -LfO https://github.com/DNSCrypt/dnscrypt-proxy/releases/download/2.1.5/dnscrypt-proxy-linux_x86_64-2.1.5.tar.gz\n\ncurl -LfO https://github.com/DNSCrypt/dnscrypt-proxy/releases/download/2.1.5/dnscrypt-proxy-linux_x86_64-2.1.5.tar.gz.minisig\n\nminisign -Vm dnscrypt-proxy-*.tar.gz -P RWTk1xXqcTODeYttYMCMLo0YJHaFEHn7a3akqHlb/7QvIQXHVPxKbjB5\nSignature and comment signature verified\nTrusted comment: timestamp:1691773871   file:dnscrypt-proxy-linux_x86_64-2.1.5.tar.gz   hashed\n\ntar xf dnscrypt-proxy*.gz\n\ncp config/dnscrypt-proxy.toml linux-x86_64/\n\ncd linux-x86_64/\n\nvim dnscrypt-proxy.toml\n```\n\n**Optional** Download and configure a hosts blacklist:\n\n```console\ngit clone https://github.com/DNSCrypt/dnscrypt-proxy\n\ncd dnscrypt-proxy/utils/generate-domains-blocklists\n\npython3 generate-domains-blocklist.py \u003e blocklist-$(date +%F).txt\n\ncp blocklist-$(date +%F).txt ~/linux-x86_64/blocklist.txt\n```\n\nStart the program and check `dnscrypt.log` for success or errors:\n\n```console\nsudo ./dnscrypt-proxy\n```\n\nOnce everything is working as expected, install and start dnscrypt-proxy as a service:\n\n```console\nsudo ./dnscrypt-proxy -service install\n\nsudo ./dnscrypt-proxy -service start\n\ntail -f dnscrypt.log\n```\n\n# Security and maintenance\n\nTo confirm the firewall is configured correctly, run port scans from an internal and external hosts, for example:\n\n```console\nnmap -v -A -T4 192.168.1.1 -Pn\n```\n\nTo view blocked packets, tail the system message buffer on Linux:\n\n```console\n$ sudo dmesg -wH\n[Jul 1 12:00] DROPIN\u003eIN=enp1s0 OUT= MAC=00:00:00:00:00:00:00:00:00:00:00:00:00:00 SRC=192.168.1.10 DST=192.168.1.1 LEN=64 TOS=0x00 PREC=0x00 TTL=64 ID=29501 DF PROTO=TCP SPT=43228 DPT=554 WINDOW=16384 RES=0x00 SYN URGP=0\n[...]\n```\n\nOn OpenBSD, blocked packets will be sent to the PF log interface:\n\n```console\n$ doas tcpdump -ni pflog0\ntcpdump: listening on pflog0, link-type PFLOG\n12:00:00.000000 192.168.1.10.40770 \u003e 192.168.1.1.1720: S 3331100898:3331180098(0) win 29200 \u003cmss 1460,sackOK,timestamp 232580000 0,nop,wscale 7\u003e (DF)\n[...]\n```\n\nInstall a USB camera and configure [Motion](https://motion-project.github.io/) to detect and monitor physical access.\n\n(Linux only) Increase system entropy with a hardware device like [OneRNG](http://onerng.info/).\n\n## OpenBSD\n\nCheck open network ports with `doas fstat | grep net` and `doas netstat -a -n -p udp -p tcp`\n\nCheck running processes and sessions with `ps -A` and `last`\n\nPay attention to [OpenBSD errata](https://www.openbsd.org/errata.html) and apply security fixes periodically with `doas syspatch`\n\nOpenBSD releases occur approximately every six months - [follow current snapshots](https://www.openbsd.org/faq/current.html) for faster updates by periodically running `doas sysupgrade -s` to reboot and install updates.\n\nCheck temperatures with `sysctl hw.sensors` or configure [sensorsd](https://man.openbsd.org/OpenBSD-current/man8/sensorsd.8).\n\n## Debian\n\nCheck open ports and listening programs with `sudo lsof -Pni` and `sudo netstat -npl`\n\nCheck running processes and logged-in users with `ps -eax` and `last -F`\n\nPay attention to [Debian security advisories](https://lists.debian.org/debian-security-announce/recent) and run `sudo apt update \u0026\u0026 sudo apt upgrade` periodically or configure [unattended upgrades](https://wiki.debian.org/UnattendedUpgrades).\n\nInstall and enable [SELinux](https://wiki.debian.org/SELinux):\n\n```console\nsudo apt -y install selinux-basics selinux-policy-default\n\nsudo selinux-activate\n\nsudo reboot\n```\n\nOr, install and enable [AppArmor](https://wiki.debian.org/AppArmor), then reboot:\n\n```console\nsudo apt -y install apparmor apparmor-profiles apparmor-utils\n\nsudo mkdir -p /etc/default/grub.d\n\necho 'GRUB_CMDLINE_LINUX_DEFAULT=\"$GRUB_CMDLINE_LINUX_DEFAULT apparmor=1 security=apparmor\"' | sudo tee /etc/default/grub.d/apparmor.cfg\n\nsudo update-grub \u0026\u0026 sudo reboot\n```\n\nInstall and enable [Firejail](https://firejail.wordpress.com/):\n\n```console\nsudo apt -y install firejail firejail-profiles\n\nsudo firecfg\n```\n\nSee also [Debian SSD Optimizations](https://wiki.debian.org/SSDOptimization).\n\n# Similar work\n\n* [elad/openbsd-apu2](https://github.com/elad/openbsd-apu2)\n* [martinbaillie/homebrew-openbsd-pcengines-router](https://github.com/martinbaillie/homebrew-openbsd-pcengines-router)\n* [northox/openbsd-apu2](https://github.com/northox/openbsd-apu2)\n* [vedetta-com/vedetta](https://github.com/vedetta-com/vedetta)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrduh%2Fpc-engines-apu-router-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdrduh%2Fpc-engines-apu-router-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrduh%2Fpc-engines-apu-router-guide/lists"}