├── .github └── FUNDING.yml ├── LICENSE └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [drduh] 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 drduh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Important** After many years of service, the PC Engines APU platform is now [EOL](https://www.pcengines.ch/eol.htm). 2 | 3 | This 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. 4 | 5 | I am **not** responsible for anything you do by following any part of this guide! 6 | 7 | # Overview 8 | 9 | The completed router configuration will enable: 10 | 11 | * An egress Ethernet interface for Internet routing - can be connected to WAN or a cable modem 12 | * A local wireless interface on `192.168.1.0/24` 13 | * A local Ethernet interface on `172.16.1.0/24` 14 | * A local Ethernet interface on `10.8.1.0/24` 15 | * An additional (4th) Ethernet interface is available on APU4 16 | 17 | ## Hardware 18 | 19 | This guide should work on any PC Engines APU model. Here is a suggested parts list: 20 | 21 | | Part | Description | Cost 22 | |------|-------------|------ 23 | | [apu4c4](https://pcengines.ch/apu4c4.htm) | apu4c4 system board | $117.50 24 | | [case1d2bluu](https://pcengines.ch/case1d2bluu.htm) | Enclosure 3 LAN, blue | $9.40 25 | | [ac12vus2](https://pcengines.ch/ac12vus2.htm) | AC adapter 12V 2A US plug | $4.10 26 | | [msata16g](https://pcengines.ch/msata16g.htm) | SSD M-Sata 16GB MLC, Phison S11 | $15.50 27 | | [wle200nx](https://pcengines.ch/wle200nx.htm) | Compex WLE200NX miniPCI express card | $19.00 28 | | 2 x [pigsma](https://pcengines.ch/pigsma.htm) | Cable I-PEX -> reverse SMA | $2.70 29 | | 2 x [antsmadb](https://pcengines.ch/antsmadb.htm) | Antenna reverse SMA dual band | $4.10 30 | 31 | **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). 32 | 33 | To 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). 34 | 35 | See [Issue #1](https://github.com/drduh/PC-Engines-APU-Router-Guide/issues/1) for a list of alternative parts. 36 | 37 | ## Assembly 38 | 39 | Clear 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. 40 | 41 | Attach the mSATA disk and miniPCI wireless adapter in their respective slots. 42 | 43 | See the relevant APU series manual for detailed board information: 44 | 45 | * [APU2](https://www.pcengines.ch/pdf/apu2.pdf) 46 | * [APU3](https://www.pcengines.ch/pdf/apu3.pdf) 47 | * [APU4](https://www.pcengines.ch/pdf/apu4.pdf) 48 | 49 | **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): 50 | 51 | 1. 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. 52 | 1. Install the radio card in the miniPCI express socket. 53 | 1. Install the pigtail cable in the cut-out of the enclosure. This will ground the pigtail to the enclosure. 54 | 1. Touch the I-PEX connector of the pigtail to the mounting hole to discharge, then plug onto the radio card. 55 | 56 | To avoid arcing, plug in the DC jack first, then plug the power adapter into mains. 57 | 58 | Press `F10` during boot and select `Payload [memtest]` to complete at least one pass. 59 | 60 | # Connect over serial 61 | 62 | The APU serial connection uses 115200 baud rate, 8N1 (8 data bits, no parity, 1 stop bit). 63 | 64 | On OpenBSD, use [cu](https://man.openbsd.org/cu): 65 | 66 | ```console 67 | doas cu -r -s 115200 -l cuaU0 68 | ``` 69 | 70 | On Linux, use [screen](https://www.gnu.org/software/screen/manual/screen.html): 71 | 72 | ```console 73 | screen /dev/ttyUSB0 115200 8N1 74 | ``` 75 | 76 | Or use [minicom](https://linux.die.net/man/1/minicom): 77 | 78 | ```console 79 | sudo minicom -D /dev/ttyUSB0 80 | ``` 81 | 82 | Power on the APU and make note of the firmware version displayed briefly during boot. 83 | 84 | # Updating firmware 85 | 86 | Check for the latest PC Engines firmware version at [pcengines.github.io](https://pcengines.github.io/) 87 | 88 | **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/) 89 | 90 | To update firmware, first download and extract [TinyCore Linux](https://pcengines.ch/file/apu2-tinycore6.4.img.gz). 91 | 92 | Download and import the [firmware signing key](https://github.com/3mdeb/3mdeb-secpack/tree/master/customer-keys/pcengines/release-keys), then check the file signature: 93 | 94 | ```console 95 | $ curl -LO https://raw.githubusercontent.com/3mdeb/3mdeb-secpack/master/customer-keys/pcengines/release-keys/pcengines-open-source-firmware-release-4.19-key.asc 96 | 97 | $ gpg --import pcengines-open-source-firmware-release-4.19-key.asc 98 | gpg: key 0x30A53DE2F5A6D89A: 1 signature not checked due to a missing key 99 | gpg: key 0x30A53DE2F5A6D89A: public key "PC Engines open-source firmware release 4.19 signing key" imported 100 | gpg: Total number processed: 1 101 | gpg: imported: 1 102 | 103 | $ gpg apu4_v4.19.0.1.SHA256.sig 104 | gpg: assuming signed data in 'apu4_v4.19.0.1.SHA256' 105 | gpg: Signature made Thu 02 Feb 2023 03:22:57 AM PST 106 | gpg: using RSA key 05CF36F166C3D676A08AB70F30A53DE2F5A6D89A 107 | gpg: Good signature from "PC Engines open-source firmware release 4.19 signing key" [unknown] 108 | gpg: WARNING: This key is not certified with a trusted signature! 109 | gpg: There is no indication that the signature belongs to the owner. 110 | Primary key fingerprint: 05CF 36F1 66C3 D676 A08A B70F 30A5 3DE2 F5A6 D89A 111 | 112 | $ shasum -a 256 apu4_v4.19.0.1.rom 2>/dev/null | grep -q $(cat apu4_v4.19.0.1.SHA256 | awk '{print $1}') && echo ok 113 | ok 114 | ``` 115 | 116 | Mount a USB disk and write the TinyCore image, copy the `.rom` file: 117 | 118 | ```console 119 | curl -O https://pcengines.ch/file/apu2-tinycore6.4.img.gz 120 | 121 | gzip -d apu2-tinycore6.4.img.gz 122 | 123 | sha256sum apu2-tinycore6.4.img 124 | f5a20eeb01dfea438836e48cb15a18c5780194fed6bf21564fc7c894a1ac06d7 apu2-tinycore6.4.img 125 | 126 | sudo dd if=apu2-tinycore6.4.img of=/dev/sdd bs=1M 127 | 128 | sudo mkdir /mnt/usb 129 | 130 | sudo mount /dev/sdd1 /mnt/usb 131 | 132 | sudo cp -v apu4_*.rom /mnt/usb 133 | 134 | sudo umount /mnt/usb 135 | ``` 136 | 137 | Connect the USB disk to the APU, press `F10` at boot and select the USB disk: 138 | 139 | ```console 140 | SeaBIOS (version rel-1.14.0.1-0-g8610266a) 141 | 142 | Press F10 key now for boot menu 143 | 144 | Select boot device: 145 | 146 | 1. USB MSC Drive Samsung Flash Drive DUO 1100 147 | 2. AHCI/0: SB2 ATA-11 Hard-Disk (111 GiBytes) 148 | 3. Payload [setup] 149 | 4. Payload [memtest] 150 | ``` 151 | 152 | Check the current version: 153 | 154 | ```console 155 | root@pcengines:~# dmesg | grep apu 156 | [ 0.000000] DMI: PC Engines apu4/apu4, BIOS v4.10.0.1 09/10/2019 157 | ``` 158 | 159 | Save the existing version and write the new one: 160 | 161 | ```console 162 | root@pcengines:~# cd /media/SYSLINUX 163 | 164 | root@pcengines:/media/SYSLINUX# flashrom -p internal -r apu4.rom.$(dmidecode -s baseboard-serial-number|tail -n1).$(date +%F) 165 | [...] 166 | Found Winbond flash chip "W25Q64.V" (8192 kB, SPI) mapped at physical address 0xff800000. 167 | Reading flash... done. 168 | 169 | root@pcengines:/media/SYSLINUX# flashrom -p internal -w apu4_v4.19.0.1.rom 170 | [...] 171 | Found Winbond flash chip "W25Q64.V" (8192 kB, SPI) mapped at physical address 0xff800000. 172 | Reading old flash chip contents... done. 173 | Erasing and writing flash chip... Erase/write done. 174 | Verifying flash... VERIFIED. 175 | ``` 176 | 177 | Unplug the USB disk and `reboot` 178 | 179 | **Optional** On reboot, select `F10` and `Payload [setup]` then `w` to enable BIOS write protection then `s` to save and reboot. 180 | 181 | Verify the version by checking serial output during boot: 182 | 183 | ``` 184 | PC Engines apu4 185 | coreboot build 20230131 186 | BIOS version v4.19.0.1 187 | ``` 188 | 189 | From OpenBSD: 190 | 191 | ```console 192 | $ dmesg | grep bios 193 | bios0 at mainbus0: SMBIOS rev. 2.8 @ 0xcfe8b020 (13 entries) 194 | bios0: vendor coreboot version "v4.19.0.1" date 01/31/2023 195 | bios0: PC Engines apu4 196 | acpi0 at bios0: ACPI 6.0 197 | ``` 198 | 199 | From Debian: 200 | 201 | ```console 202 | $ sudo dmesg | grep apu 203 | [ 0.000000] DMI: PC Engines apu4/apu4, BIOS v4.19.0.1 01/31/2023 204 | ``` 205 | 206 | **Note** APU firmware can also be updated from Debian, without rebooting to TinyCore Linux: 207 | 208 | ```console 209 | sudo apt install flashrom 210 | 211 | wget https://3mdeb.com/open-source-firmware/pcengines/apu4/apu4_v4.19.0.1.rom 212 | 213 | sudo flashrom -p internal -w apu2_v4.19.0.1.rom 214 | ``` 215 | 216 | To complete the update, shut down Debian and power off the APU fully, then reboot. 217 | 218 | # Prepare OS installer 219 | 220 | Use another computer to prepare an installer for either OpenBSD or Debian. 221 | 222 | ## OpenBSD 223 | 224 | Download 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. 225 | 226 | Verify the signatures file and hash of the installation image: 227 | 228 | ```console 229 | cat /etc/signify/openbsd-75-base.pub 230 | untrusted comment: openbsd 7.5 base public key 231 | RWRGj1pRpprAfgeF/rgld4ubduChLvTkigA1Zj7WLDsVA4qfYSWOEI8q 232 | 233 | signify -C -p /etc/signify/openbsd-75-base.pub -x SHA256.sig install75.img 234 | Signature Verified 235 | install75.img: OK 236 | ``` 237 | 238 | Insert a USB disk. Run `dmesg` to identify its label. Then copy the installation file to the USB disk: 239 | 240 | On OpenBSD: 241 | 242 | ```console 243 | doas dd if=install75.img of=/dev/rsd2c bs=1m 244 | ``` 245 | 246 | On Linux: 247 | 248 | ```console 249 | sudo dd if=install75.img of=/dev/sdd bs=1M 250 | ``` 251 | 252 | ## Debian 253 | 254 | Download 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. 255 | 256 | Verify the signatures file and hash of the installation image: 257 | 258 | ```console 259 | $ gpg SHA512SUMS.sign 260 | gpg: assuming signed data in 'SHA512SUMS' 261 | gpg: Signature made Sat 07 Oct 2023 01:24:41 PM PDT 262 | gpg: using RSA key DF9B9C49EAA9298432589D76DA87E80D6294BE9B 263 | gpg: Can't check signature: No public key 264 | 265 | $ gpg --keyserver hkps://keyserver.ubuntu.com:443 --recv DF9B9C49EAA9298432589D76DA87E80D6294BE9B 266 | gpg: key 0xDA87E80D6294BE9B: public key "Debian CD signing key " imported 267 | gpg: Total number processed: 1 268 | gpg: imported: 1 269 | 270 | $ gpg SHA512SUMS.sign 271 | gpg: Signature made Sat 29 Jun 2024 01:50:21 PM PDT 272 | gpg: using RSA key DF9B9C49EAA9298432589D76DA87E80D6294BE9B 273 | gpg: Good signature from "Debian CD signing key " [unknown] 274 | gpg: WARNING: This key is not certified with a trusted signature! 275 | gpg: There is no indication that the signature belongs to the owner. 276 | Primary key fingerprint: DF9B 9C49 EAA9 2984 3258 9D76 DA87 E80D 6294 BE9B 277 | ``` 278 | 279 | OpenBSD: 280 | 281 | ```console 282 | grep $(sha512 -q debian-12.6.0-amd64-netinst.iso) SHA512SUMS 283 | 712cf43c5c9d60dbd5190144373c18b910c89051193c47534a68b0cd137c99bd8274902f59b25aba3b6ba3e5bca51d7c433c06522f40adb93aacc5e21acf57eb debian-12.6.0-amd64-netinst.iso 284 | ``` 285 | 286 | Linux: 287 | 288 | ```console 289 | grep $(sha512sum debian-12.6.0-amd64-netinst.iso) SHA512SUMS 290 | SHA512SUMS:712cf43c5c9d60dbd5190144373c18b910c89051193c47534a68b0cd137c99bd8274902f59b25aba3b6ba3e5bca51d7c433c06522f40adb93aacc5e21acf57eb debian-12.6.0-amd64-netinst.iso 291 | ``` 292 | 293 | Insert a USB disk. Run `dmesg` to identify its label. Then copy the installation file to the USB disk. 294 | 295 | OpenBSD: 296 | 297 | ```console 298 | doas dd if=debian-12.6.0-amd64-netinst.iso of=/dev/rsd2c bs=1m 299 | ``` 300 | 301 | Linux: 302 | 303 | ```console 304 | sudo dd if=debian-12.6.0-amd64-netinst.iso of=/dev/sdd bs=1M 305 | ``` 306 | 307 | Unplug the USB disk and plug it into the APU. 308 | 309 | # Installing the OS 310 | 311 | Press `F10` at boot and select the USB disk. 312 | 313 | ## OpenBSD 314 | 315 | Set the serial console parameters: 316 | 317 | ```console 318 | Booting from Hard Disk... 319 | Using drive 0, partition 3. 320 | Loading...... 321 | probing: pc0 com0 com1 mem[639K 3325M 752M a20=on] 322 | disk: hd0+ hd1+ 323 | >> OpenBSD/amd64 BOOT 3.47 324 | boot> stty com0 115200 325 | boot> set tty com0 326 | switching console to com>> OpenBSD/amd64 BOOT 3.47 327 | boot> [Press Enter] 328 | ``` 329 | 330 | Select the Install option: 331 | 332 | ```console 333 | Welcome to the OpenBSD/amd64 7.5 installation program. 334 | (I)nstall, (U)pgrade, (A)utoinstall or (S)hell? I 335 | ``` 336 | 337 | When presented with a list of network interfaces, `em0` is the Ethernet port closest to the serial port: 338 | 339 | ```console 340 | Available network interfaces are: em0 em1 em2 em3 vlan0. 341 | ``` 342 | 343 | Use DHCP or configure a static route: 344 | 345 | ```console 346 | Network interface to configure? (name, lladdr, '?', or 'done') [done] em0 347 | IPv4 address for em0? (or 'autoconf' or 'none') [autoconf] 192.168.1.2 348 | Netmask for em0? [255.255.255.0] 349 | IPv6 address for em0? (or 'autoconf' or 'none') [none] 350 | Available network interfaces are: em0 em1 em2 em3 vlan0. 351 | Network interface to configure? (name, lladdr, '?', or 'done') [done] 352 | Default IPv4 route? (IPv4 address or 'none') 192.168.1.1 353 | add net default: gateway 192.168.1.1 354 | DNS domain name? (e.g. 'example.com') [my.domain] local 355 | DNS nameservers? (IP address list or 'none') [none] 192.168.1.1 356 | ``` 357 | 358 | Configure the root password and set up a user account: 359 | 360 | ```console 361 | Password for root account? (will not echo) 362 | Password for root account? (again) 363 | Start sshd(8) by default? [yes] 364 | Change the default console to com0? [yes] 365 | Available speeds are: 9600 19200 38400 57600 115200. 366 | Which speed should com0 use? (or 'done') [115200] 367 | Setup a user? (enter a lower-case loginname, or 'no') [no] sysadm 368 | Full name for user sysadm? [sysadm] 369 | Password for user sysadm? (will not echo) 370 | Password for user sysadm? (again) 371 | ``` 372 | 373 | Select the internal mSATA disk and default options for partitioning: 374 | 375 | ```console 376 | Available disks are: sd0 sd1. 377 | Which disk is the root disk? ('?' for details) [sd0] ? 378 | sd0: ATA, SB2, SBFM naa.0000000000000000 (119.2G) 379 | sd1: PNY, USB 2.0 FD, 1100 serial.00000000000000000000 (29.9G) 380 | Available disks are: sd0 sd1. 381 | Which disk is the root disk? ('?' for details) [sd0] 382 | ``` 383 | 384 | **Note** The "unused" partition (`/dev/sd0c`) is actually the [entire disk](https://www.openbsd.org/faq/faq14.html#intro). 385 | 386 | Select a [mirror](https://www.openbsd.org/ftp.html) and start the installation: 387 | 388 | ```console 389 | HTTP Server? (hostname, list#, 'done' or '?') cdn.openbsd.org 390 | Server directory? [pub/OpenBSD/7.5/amd64] 391 | 392 | Select sets by entering a set name, a file name pattern or 'all'. De-select 393 | sets by prepending a '-', e.g.: '-game*'. Selected sets are labelled '[X]'. 394 | [X] bsd [X] base75.tgz [X] game75.tgz [X] xfont75.tgz 395 | [X] bsd.mp [X] comp75.tgz [X] xbase75.tgz [X] xserv75.tgz 396 | [X] bsd.rd [X] man75.tgz [X] xshare75.tgz 397 | Set name(s)? (or 'abort' or 'done') [done] 398 | ``` 399 | 400 | After installation is complete, unplug the USB disk and reboot. See the OpenBSD [FAQ](https://www.openbsd.org/faq/faq4.html#Install) for more information. 401 | 402 | ## Debian 403 | 404 | At the install menu, select `Tab` to edit boot options and replace `quiet` with: 405 | 406 | ``` 407 | console=ttyS0,115200n8 408 | ``` 409 | 410 | Select `Enter` and select an available resolution: 411 | 412 | ``` 413 | Undefined video mode number: 314 414 | Press to see video modes available, to continue, or wait 30 sec 415 | Mode: Resolution: Type: 416 | 0 F00 80x25 CGA/MDA/HGC 417 | Enter a video mode or "scan" to scan for additional modes: 0 418 | ``` 419 | 420 | Configure a network adapter - `enp1s0` is the interface closest to the serial port. 421 | 422 | Select `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`). 423 | 424 | Select `Separate /home, /var, and /tmp partitions` as the [partitioning scheme](https://www.debian.org/releases/stable/armel/apcs03.html.en). 425 | 426 | During `Software selection` - de-select everything except *SSH server*. 427 | 428 | Select the internal mSATA drive and not the USB disk as the GRUB loader target. 429 | 430 | # First boot 431 | 432 | ## OpenBSD 433 | 434 | The following boot parameters have been appended to `/etc/boot.conf` by the installer and everything should just work: 435 | 436 | ``` 437 | stty com0 115200 438 | set tty com0 439 | ``` 440 | 441 | ## Debian 442 | 443 | After the GRUB menu, output may get stuck at: 444 | 445 | ``` 446 | Loading Linux 6.1.0-23-amd64 ... 447 | Loading initial ramdisk ... 448 | ``` 449 | 450 | If so, reboot and press `e` at the GRUB menu to enter edit mode, scroll down and replace the word `quiet` with: 451 | 452 | ``` 453 | console=ttyS0,115200n8 454 | ``` 455 | 456 | **Note** If arrow keys do not work in GRUB, try using Emacs key bindings to navigate the text field: 457 | 458 | * `Control-B` to move left 459 | * `Control-F` to move right 460 | * `Control-P` to move up 461 | * `Control-N` to move down 462 | 463 | Press `Control-X` to continue booting and you should see console output. 464 | 465 | **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. 466 | 467 | # First login 468 | 469 | ## OpenBSD 470 | 471 | Log in as `root` and install [pending updates](https://man.openbsd.org/syspatch) or [switch to -current](https://www.openbsd.org/faq/current.html): 472 | 473 | ```console 474 | syspatch 475 | ``` 476 | 477 | Install any pending [firmware updates](https://man.openbsd.org/fw_update): 478 | 479 | ```console 480 | fw_update 481 | ``` 482 | 483 | Edit `/etc/doas.conf` to allow the regular user to run [privileged commands](https://man.openbsd.org/doas.conf) without a password: 484 | 485 | ``` 486 | permit nopass keepenv :wheel 487 | permit nopass keepenv root 488 | ``` 489 | 490 | Install any needed software: 491 | 492 | ```console 493 | pkg_add bash zsh vim curl free pftop vnstat 494 | ``` 495 | 496 | Reboot to complete any pending updates. 497 | 498 | ## Debian 499 | 500 | Log in as `root` to get started. 501 | 502 | If necessary, update GRUB by editing `/etc/default/grub` and removing or replacing `quiet` with `console=ttyS0,115200n8` then update the configuration: 503 | 504 | ```console 505 | update-grub 506 | ``` 507 | 508 | Install any pending updates and necessary software: 509 | 510 | ```console 511 | apt update && apt -y upgrade 512 | 513 | apt -y install lshw lsof vim zsh git sudo dnsmasq net-tools iptables tcpdump hostapd firmware-atheros 514 | ``` 515 | 516 | **Optional** Change the default login shell to zsh for the primary user: 517 | 518 | ``` 519 | chsh -s /usr/bin/zsh sysadm 520 | ``` 521 | 522 | # Configure network interfaces 523 | 524 | ## OpenBSD 525 | 526 | On the APU, set a local network interface address and make it permanent: 527 | 528 | ```console 529 | doas ifconfig em1 10.8.1.1 255.255.255.0 530 | 531 | echo "inet 10.8.1.1 255.255.255.0" | doas tee /etc/hostname.em1 532 | ``` 533 | 534 | Configure an OpenBSD client with DHCP by following the [Networking FAQ](https://www.openbsd.org/faq/faq6.html) or using a static address: 535 | 536 | ```console 537 | doas ifconfig em1 10.8.1.4 255.255.255.0 538 | 539 | ping -c 1 10.8.1.1 540 | PING 10.8.1.1 (10.8.1.1): 56 data bytes 541 | 64 bytes from 10.8.1.1: icmp_seq=0 ttl=255 time=0.845 ms 542 | ``` 543 | 544 | **Optional** Randomize MAC addresses on boot: 545 | 546 | ```console 547 | echo "lladdr random" | doas tee -a /etc/hostname.em0 /etc/hostname.em1 /etc/hostname.em2 548 | ``` 549 | 550 | ## Debian 551 | 552 | On the APU and on another computer, determine the interface names available: 553 | 554 | ```console 555 | lshw -C network | grep "logical name" 556 | ``` 557 | 558 | On the APU, edit `/etc/network/interfaces` to append: 559 | 560 | ``` 561 | auto enp2s0 562 | iface enp2s0 inet static 563 | address 10.8.1.1 564 | netmask 255.255.255.0 565 | gateway 10.8.1.1 566 | ``` 567 | 568 | Where `enp2s0` is the network interface one port away from the serial port. 569 | 570 | Restart networking and bring up the interface: 571 | 572 | ```console 573 | service networking restart 574 | 575 | ifup enp2s0 576 | ``` 577 | 578 | On another Linux computer, edit `/etc/network/interfaces` to append: 579 | 580 | ``` 581 | auto eno1 582 | iface eno1 inet static 583 | address 10.8.1.2 584 | netmask 255.255.255.0 585 | gateway 10.8.1.1 586 | ``` 587 | 588 | Then also restart networking and bring up the interface: 589 | 590 | ```console 591 | sudo service networking restart 592 | 593 | sudo ifup eno1 594 | ``` 595 | 596 | Or on another OpenBSD computer, edit `/etc/hostname.em0` to append: 597 | 598 | ``` 599 | inet 10.8.1.4 255.255.255.0 600 | ``` 601 | 602 | It should now be possible to ping the router: 603 | 604 | ```console 605 | ping -c 1 10.8.1.1 606 | PING 10.8.1.1 (10.8.1.1): 56 data bytes 607 | 64 bytes from 10.8.1.1: icmp_seq=0 ttl=64 time=0.519 ms 608 | ``` 609 | 610 | To configure the wireless interface, edit `/etc/network/interfaces` on the APU to include: 611 | 612 | ``` 613 | auto wlp5s0 614 | iface wlp5s0 inet static 615 | address 192.168.1.1 616 | netmask 255.255.255.0 617 | hostapd /etc/hostapd.conf 618 | ``` 619 | 620 | Reboot after verifying network connectivity. 621 | 622 | # Configure SSH 623 | 624 | From a client, an SSH connection to the APU should be possible, but not yet authorized: 625 | 626 | ```console 627 | $ ssh sysadm@10.8.1.1 628 | The authenticity of host '10.8.1.1 (10.8.1.1)' can't be established. 629 | ECDSA key fingerprint is SHA256:AAAAA. 630 | Are you sure you want to continue connecting (yes/no)? yes 631 | Warning: Permanently added '10.8.1.1' (ECDSA) to the list of known hosts. 632 | Permission denied (publickey,password). 633 | ``` 634 | 635 | If using a [YubiKey](https://github.com/drduh/YubiKey-Guide), copy its public key to clipboard: 636 | 637 | ```console 638 | ssh-add -L | awk '{print $1" "$2}' | xclip 639 | ``` 640 | 641 | Or generate a new SSH key on the client and copy it to clipboard: 642 | 643 | ```console 644 | ssh-keygen -f -C 'sysadm' ~/.ssh/pcengines 645 | 646 | xclip ~/.ssh/pcengines.pub 647 | ``` 648 | 649 | On 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`: 650 | 651 | ```console 652 | mkdir ~/.ssh ; cat > ~/.ssh/authorized_keys 653 | [Paste clipboard contents using the middle mouse button or Shift-Insert] 654 | [Then press Control-D to save] 655 | ``` 656 | 657 | SSH from a client will now work: 658 | 659 | ```console 660 | $ ssh sysadm@10.8.1.1 -i ~/.ssh/pcengines 661 | Host key fingerprint is SHA256:AAAAA 662 | 663 | Linux pcengines 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64 664 | sysadm@pcengines~ % 665 | ``` 666 | 667 | Configure the connection on a client by editing `~/.ssh/config`: 668 | 669 | ``` 670 | Host pcengines 671 | HostName 10.8.1.1 672 | IdentityFile ~/.ssh/pcengines 673 | User sysadm 674 | Port 22 675 | ControlMaster auto 676 | ControlPath ~/.ssh/master-%r@%h:%p 677 | ControlPersist 1m 678 | ``` 679 | 680 | Connect using the new alias: 681 | 682 | ```console 683 | ssh pcengines 684 | ``` 685 | 686 | Download configuration files: 687 | 688 | ```console 689 | git clone https://github.com/drduh/config 690 | ``` 691 | 692 | The 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. 693 | 694 | # DHCP and DNS 695 | 696 | [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). 697 | 698 | Use [drduh/config/dnsmasq.conf](https://github.com/drduh/config/blob/master/dnsmasq.conf) for a configuration example, including blocked domains: 699 | 700 | ```console 701 | cp config/dnsmasq.conf /etc/dnsmasq.conf 702 | 703 | cat config/domains/* | tee -a /etc/dnsmasq.conf 704 | 705 | vim /etc/dnsmasq.conf 706 | ``` 707 | 708 | Configure additional blocklist: 709 | 710 | ```console 711 | git clone https://github.com/StevenBlack/hosts 712 | 713 | sudo cp hosts/hosts /etc/dns-blocklist 714 | ``` 715 | 716 | ## OpenBSD 717 | 718 | To install dnsmasq as a service enabled on boot: 719 | 720 | ```console 721 | doas pkg_add dnsmasq 722 | 723 | doas rcctl start dnsmasq 724 | 725 | doas rcctl enable dnsmasq 726 | ``` 727 | 728 | # Wireless 729 | 730 | ## OpenBSD 731 | 732 | **Note** Wireless performance is currently significantly worse on OpenBSD than Debian. 733 | 734 | Edit `/etc/hostname.athn0` to include: 735 | 736 | ```shell 737 | inet 192.168.1.1 255.255.255.0 738 | media autoselect mode 11n mediaopt hostap chan 11 739 | nwid NAME wpakey "PASSWORD" 740 | ``` 741 | 742 | Restart networking: 743 | 744 | ```console 745 | doas sh /etc/netstart 746 | ``` 747 | 748 | ## Debian 749 | 750 | Install the default hostapd configuration: 751 | 752 | ```console 753 | cat /usr/share/doc/hostapd/examples/hostapd.conf | sudo tee -a /etc/hostapd.conf 754 | ``` 755 | 756 | Or use [drduh/config/hostapd.conf](https://github.com/drduh/config/blob/master/hostapd.conf): 757 | 758 | ```console 759 | sudo cp config/hostapd.conf /etc/hostapd.conf 760 | ``` 761 | 762 | Edit the configuration to set the network name and password. 763 | 764 | *Tip* Avoid passwords with the characters `'` and `"`. 765 | 766 | ```console 767 | sudo vim /etc/hostapd.conf 768 | ``` 769 | 770 | Ensure hostapd starts: 771 | 772 | ```console 773 | sudo hostapd /etc/hostapd.conf 774 | ``` 775 | 776 | **Note** You may need to manually assign the interface an address: 777 | 778 | ```console 779 | sudo ifconfig wlp5s0 192.168.1.1 780 | ``` 781 | 782 | # IP forwarding 783 | 784 | In order to be a router, [IP forwarding](https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt) must be enabled. 785 | 786 | ## OpenBSD 787 | 788 | Enable now and on boot: 789 | 790 | ```console 791 | doas sysctl net.inet.ip.forwarding=1 792 | 793 | echo "net.inet.ip.forwarding=1" | doas tee -a /etc/sysctl.conf 794 | ``` 795 | 796 | ## Debian 797 | 798 | Enable now and on boot: 799 | 800 | ```console 801 | sudo sysctl -w net.ipv4.ip_forward=1 802 | 803 | echo "net.ipv4.ip_forward=1" | sudo tee --append /etc/sysctl.conf 804 | ``` 805 | 806 | # Configure firewall 807 | 808 | ## OpenBSD 809 | 810 | See [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: 811 | 812 | ```console 813 | doas mkdir /etc/pf 814 | 815 | doas cp config/pf/pf.conf /etc/ 816 | 817 | doas cp config/pf/blocklist config/pf/martians config/pf/private /etc/pf/ 818 | ``` 819 | 820 | Turn PF off and back on again: 821 | 822 | ```console 823 | doas pfctl -d 824 | 825 | doas pfctl -e -f /etc/pf.conf 826 | ``` 827 | 828 | **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. 829 | 830 | To inspect blocked traffic: 831 | 832 | ```console 833 | doas tcpdump -ni pflog0 834 | ``` 835 | 836 | ## Debian 837 | 838 | Use [Iptables](https://en.wikipedia.org/wiki/Iptables) to manage a stateful firewall. 839 | 840 | Use [drduh/config/scripts/iptables.sh](https://github.com/drduh/config/blob/master/scripts/iptables.sh) and edit it to your needs: 841 | 842 | ```console 843 | sudo cp config/scripts/iptables.sh /etc 844 | 845 | sudo vim /etc/iptables.sh 846 | 847 | sudo chmod +x /etc/iptables.sh 848 | 849 | sudo /etc/iptables.sh 850 | ``` 851 | 852 | Save the firewall rules to apply them on boot: 853 | 854 | ```console 855 | sudo iptables-save | tee /etc/iptables/rules.v4 856 | ``` 857 | 858 | # Privoxy 859 | 860 | [Privoxy](https://www.privoxy.org/) is a powerful Web proxy capable of filtering and rewriting URLs to block ads, upgrade HTTP connections, and more. 861 | 862 | ## Debian 863 | 864 | Install Privoxy: 865 | 866 | ```console 867 | sudo apt -y install privoxy 868 | ``` 869 | 870 | Use [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. 871 | 872 | ```console 873 | sudo cp config/privoxy/config config/privoxy/user.action /etc/privoxy/ 874 | ``` 875 | 876 | Restart the service and check the log: 877 | 878 | ```console 879 | sudo service privoxy restart 880 | 881 | sudo tail -f /var/log/privoxy/logfile 882 | ``` 883 | 884 | # Lighttpd 885 | 886 | [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. 887 | 888 | ## Debian 889 | 890 | Install Lighttpd with ModMagnet: 891 | 892 | ```console 893 | sudo apt -y install lighttpd lighttpd-mod-magnet 894 | ``` 895 | 896 | Use [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. 897 | 898 | ```console 899 | sudo cp config/lighttpd/lighttpd.conf config/lighttpd/magnet.luau /etc/lighttpd/ 900 | ``` 901 | 902 | Restart the service and check the log: 903 | 904 | ```console 905 | sudo service lighttpd restart 906 | 907 | sudo cat /var/log/lighttpd/error.log 908 | ``` 909 | 910 | # DNSCrypt 911 | 912 | First install `minisign` or build from [source](https://github.com/jedisct1/minisign/releases/latest) 913 | 914 | Download 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: 915 | 916 | ```console 917 | curl -LfO https://github.com/DNSCrypt/dnscrypt-proxy/releases/download/2.1.5/dnscrypt-proxy-linux_x86_64-2.1.5.tar.gz 918 | 919 | curl -LfO https://github.com/DNSCrypt/dnscrypt-proxy/releases/download/2.1.5/dnscrypt-proxy-linux_x86_64-2.1.5.tar.gz.minisig 920 | 921 | minisign -Vm dnscrypt-proxy-*.tar.gz -P RWTk1xXqcTODeYttYMCMLo0YJHaFEHn7a3akqHlb/7QvIQXHVPxKbjB5 922 | Signature and comment signature verified 923 | Trusted comment: timestamp:1691773871 file:dnscrypt-proxy-linux_x86_64-2.1.5.tar.gz hashed 924 | 925 | tar xf dnscrypt-proxy*.gz 926 | 927 | cp config/dnscrypt-proxy.toml linux-x86_64/ 928 | 929 | cd linux-x86_64/ 930 | 931 | vim dnscrypt-proxy.toml 932 | ``` 933 | 934 | **Optional** Download and configure a hosts blacklist: 935 | 936 | ```console 937 | git clone https://github.com/DNSCrypt/dnscrypt-proxy 938 | 939 | cd dnscrypt-proxy/utils/generate-domains-blocklists 940 | 941 | python3 generate-domains-blocklist.py > blocklist-$(date +%F).txt 942 | 943 | cp blocklist-$(date +%F).txt ~/linux-x86_64/blocklist.txt 944 | ``` 945 | 946 | Start the program and check `dnscrypt.log` for success or errors: 947 | 948 | ```console 949 | sudo ./dnscrypt-proxy 950 | ``` 951 | 952 | Once everything is working as expected, install and start dnscrypt-proxy as a service: 953 | 954 | ```console 955 | sudo ./dnscrypt-proxy -service install 956 | 957 | sudo ./dnscrypt-proxy -service start 958 | 959 | tail -f dnscrypt.log 960 | ``` 961 | 962 | # Security and maintenance 963 | 964 | To confirm the firewall is configured correctly, run port scans from an internal and external hosts, for example: 965 | 966 | ```console 967 | nmap -v -A -T4 192.168.1.1 -Pn 968 | ``` 969 | 970 | To view blocked packets, tail the system message buffer on Linux: 971 | 972 | ```console 973 | $ sudo dmesg -wH 974 | [Jul 1 12:00] DROPIN>IN=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 975 | [...] 976 | ``` 977 | 978 | On OpenBSD, blocked packets will be sent to the PF log interface: 979 | 980 | ```console 981 | $ doas tcpdump -ni pflog0 982 | tcpdump: listening on pflog0, link-type PFLOG 983 | 12:00:00.000000 192.168.1.10.40770 > 192.168.1.1.1720: S 3331100898:3331180098(0) win 29200 (DF) 984 | [...] 985 | ``` 986 | 987 | Install a USB camera and configure [Motion](https://motion-project.github.io/) to detect and monitor physical access. 988 | 989 | (Linux only) Increase system entropy with a hardware device like [OneRNG](http://onerng.info/). 990 | 991 | ## OpenBSD 992 | 993 | Check open network ports with `doas fstat | grep net` and `doas netstat -a -n -p udp -p tcp` 994 | 995 | Check running processes and sessions with `ps -A` and `last` 996 | 997 | Pay attention to [OpenBSD errata](https://www.openbsd.org/errata.html) and apply security fixes periodically with `doas syspatch` 998 | 999 | OpenBSD 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. 1000 | 1001 | Check temperatures with `sysctl hw.sensors` or configure [sensorsd](https://man.openbsd.org/OpenBSD-current/man8/sensorsd.8). 1002 | 1003 | ## Debian 1004 | 1005 | Check open ports and listening programs with `sudo lsof -Pni` and `sudo netstat -npl` 1006 | 1007 | Check running processes and logged-in users with `ps -eax` and `last -F` 1008 | 1009 | Pay attention to [Debian security advisories](https://lists.debian.org/debian-security-announce/recent) and run `sudo apt update && sudo apt upgrade` periodically or configure [unattended upgrades](https://wiki.debian.org/UnattendedUpgrades). 1010 | 1011 | Install and enable [SELinux](https://wiki.debian.org/SELinux): 1012 | 1013 | ```console 1014 | sudo apt -y install selinux-basics selinux-policy-default 1015 | 1016 | sudo selinux-activate 1017 | 1018 | sudo reboot 1019 | ``` 1020 | 1021 | Or, install and enable [AppArmor](https://wiki.debian.org/AppArmor), then reboot: 1022 | 1023 | ```console 1024 | sudo apt -y install apparmor apparmor-profiles apparmor-utils 1025 | 1026 | sudo mkdir -p /etc/default/grub.d 1027 | 1028 | echo 'GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT apparmor=1 security=apparmor"' | sudo tee /etc/default/grub.d/apparmor.cfg 1029 | 1030 | sudo update-grub && sudo reboot 1031 | ``` 1032 | 1033 | Install and enable [Firejail](https://firejail.wordpress.com/): 1034 | 1035 | ```console 1036 | sudo apt -y install firejail firejail-profiles 1037 | 1038 | sudo firecfg 1039 | ``` 1040 | 1041 | See also [Debian SSD Optimizations](https://wiki.debian.org/SSDOptimization). 1042 | 1043 | # Similar work 1044 | 1045 | * [elad/openbsd-apu2](https://github.com/elad/openbsd-apu2) 1046 | * [martinbaillie/homebrew-openbsd-pcengines-router](https://github.com/martinbaillie/homebrew-openbsd-pcengines-router) 1047 | * [northox/openbsd-apu2](https://github.com/northox/openbsd-apu2) 1048 | * [vedetta-com/vedetta](https://github.com/vedetta-com/vedetta) 1049 | 1050 | --------------------------------------------------------------------------------