= calico = * [[https://wiki.radxa.com/RockpiS| Radxa Rock Pi S]], a teeny little ARM computer with PoE and 100Mb ethernet * Running Armbian this time, I've got `Armbian_23.8.1_Rockpi-s_bookworm_current_6.1.50.img.xz` {{{ Linux calico 6.1.50-current-rockchip64 #3 SMP PREEMPT Wed Aug 30 14:11:13 UTC 2023 aarch64 GNU/Linux }}} Much newer than the 4.4 kernel that Radxa distributes themselves * Located at home <> == Build notes == I previously wrote [[../RockPiS| general notes for Rock Pi S]] hardware based on using the Radxa distro, this time I'm trying something different. === Image and setup SSH keys === * Image the SD card with Etcher and let it boot, it'll get on the network with DHCP * The MAC address will be something random, as these boards don't have a real burnt-in MAC address, so you'll need to find it. * Login with root // 1234 * Let it run the firstrun thing to set the root password to something secure, and record it safely. Select bash or zsh, your choice. * Skip user account creation, I won't be using that * Copy your SSH key to the box, using the freshly-set root password {{{ ssh-copy-id root@IP }}} * Login again, now it'll use your SSH key {{{ ssh root@IP }}} * Regenerate SSH host keys to ensure they're clean {{{ rm /etc/ssh/ssh_host_* dpkg-reconfigure openssh-server }}} * We only want to use ed25519 as well {{{ echo "HostKey /etc/ssh/ssh_host_ed25519_key" >> /etc/ssh/sshd_config.d/10-ed25519-hostkey-only.conf }}} * Logout completely * Delete the entries from your local known_hosts file * SSH again as root@IP, accepting the new keys. It'll use your SSH key instead of asking for password now. Go ahead and reboot to make sure everything is clean. === Run armbian-config to configure the host === * System * CPU: choose the min/max speeds, use ondemand governor * Avahi: Let's announce, I guess * Hardware * Check `bs@1.3ghz` (I think this is fine for v1.3 RockPiS board * Firmware: Apply all updates, don't reboot * Network * IP * end0 * Static: 192.168.1.26 // 24 // 192.168.1.1 // 8.8.8.8 * Personal * Timezone: Australia/Sydney * Locales * Enable `en_AU.UTF-8` * Leave `en_US.UTF-8` enabled too * Select `en_AU.UTF-8` as default for system * Hostname: calico * Welcome * 10 Armbian header * 30 Armbian sysinfo * 40 Armbian updates * 41 Armbian config * 98 Armbian autoreboot warn * !! /etc/update-motd.d/ seems to be missing * Exit and run armbian-config again, seems fine now === Basic environment stuff === * Armbian doesn't seem to load root's bashrc so we trigger it ourselves {{{ echo -e "if [ -f ~/.bashrc ] ; then\n . ~/.bashrc\nfi" > /root/.profile }}} * Enable shell timestamping for root, as our usual bashrd.d won't be imported here {{{ echo -e "\n# Timestamped shell FTW\nexport HISTTIMEFORMAT='%Y-%m-%d %H:%M:%S '" >> /root/.bashrc }}} * Set hostname: {{{ hostnamectl set-hostname calico.thighhighs.top }}} * Set timezone {{{ timedatectl set-timezone Australia/Sydney }}} * Set editor {{{ echo "export EDITOR=vim" > /etc/profile.d/editor-vim.sh }}} * Disable `HashKnownHosts` {{{ echo -e "Host *\n HashKnownHosts no" > /etc/ssh/ssh_config.d/99-global.conf }}} * Configure screen {{{ curl -o ~/.screenrc https://gist.githubusercontent.com/barneydesmond/d16c5201ed9d2280251dfca7c620bb86/raw/.screenrc }}} * Configure top by entering this cheatcode {{{ z x c s 1.5 e 1 W q }}} * Disable wifi, we don't need it and it slows down boot {{{ systemctl disable wpa_supplicant.service --now systemctl disable rpcbind.socket --now systemctl stop rpcbind.service echo -e "# Don't load the WLAN+BT module, we don't need it\nblacklist 8723ds" > /etc/modprobe.d/blacklist-radios.conf update-initramfs -u }}} * Install useful packages {{{ apt update apt install -y ack bind9-dnsutils elinks net-tools netcat-openbsd nmap python-is-python3 screen strace tcpdump vim wget whiptail whois }}} * Do a full upgrade then reboot {{{ apt full-upgrade reboot }}} === Configure networking === We've already got the static IPv4 address, but let's make sure we've got this complete. What we want: * Static IPv4 addressing * Autoconfig dynamic IPv6 addressing * Global stable IPv6 addresses (I guess) * Add a locally-defined static IPv6 address, that other hosts can refer to via DNS etc * This is a nifty site for testing: http://ip.bieringer.net/ - Look at `EUI64_SCOPE` and see if it's random/privacy/global. Global is probably what we want for servers. * DNS resolvers will be manually defined The connection is managed by Network Manager, so let's try sticking with that for now. `nmtui` to edit the connection * Rename it to `Ethernet` or something easier * IPv4 * Set DNS servers to 8.8.8.8 and 8.8.4.4 * Add search domain `thighhighs.top` * IPv6 * Add v6 address 2404:e80:42e3:0:201:26:314:159 * Note that this respects the EUI-64 derivation, changing `:1:26` to `:201:26` * Add search domain `thighhighs.top` Reboot and cross your fingers === Save a known-good image for convenience === On another system with an SD card reader, take an image of the system after shrinking the filesystem {{{ e2fsck -f /dev/mmcblk0p2 resize2fs -M /dev/mmcblk0p2 # Use cfdisk or parted to shrink the partition to a bit larger than the FS, has just been reported. # In this case it's just over 1GiB, so I'll shrink the partition to 1.1GiB. # Now take the image, capture a bit more than the size of the partitions. # boot+root partitions are ~1.22GiB (1254MiB) here, so I'll capture 1300MiB just to be sure. dd bs=1M count=1300 if=/dev/mmcblk0 | pv -br | gzip --fast > 2021-12-13_calico_img_clean_os.img.gz }}} If you ever need to restore this image, make sure to run `resize-assistant` afterwards. As well as growing the FS, it needs to locate the backup GPT table at the end of the disk. At the very least you need to run `sgdisk -e /dev/mmcblk0` and then `partprobe` to clean that up. If you want to expand the filesystem manually: 1. Boot the image you just restored to the SD card 2. `sgdisk -e /dev/mmcblk0` 3. `partprobe` 4. Use parted or cfdisk to expand the 2nd partition to the desired size (or the whole disk) 5. `resize2fs /dev/mmcblk0p2` == Pihole == Straightforward basic install, no conflict with other installed services. * `curl -sSL https://install.pi-hole.net | bash` * Google upstream * Use suggested blocklist * Web interface enabled, full query logging and display {{{ [i] Web Interface password: iMm9OBVz [i] This can be changed using 'pihole -a -p' [i] View the web interface at http://pi.hole/admin or http://192.168.1.26/admin [i] You may now configure your devices to use the Pi-hole as their DNS server [i] Pi-hole DNS (IPv4): 192.168.1.26 [i] Pi-hole DNS (IPv6): 2404:e80:42e3:0:39d1:1547:50dd:bce7 [i] If you have not done so already, the above IP should be set to static. [i] The install log is located at: /etc/pihole/install.log }}} Admin UI at https://calico.thighhighs.top/admin/ Update our network config to use localhost resolvers only. This gives us the sum of what pihole/dnsmasq knows from local static configs, plus whatever is forwarded to Cloudflare. * Ether1 * IPv4 DNS: `127.0.0.1` * IPv6 DNS: `::1` * Ignore automatically obtained DNS parameters In Pihole, enable IPv6 upstreams, and '''Respond only on interface end0''', in http://calico.thighhighs.top/admin/settings.php?tab=dns This is important as the default setting won't answer queries from other LAN subnets (eg. VPN, IOT segments). Enable conditional forwarding. === TLS support === Can add TLS \o/ https://discourse.pi-hole.net/t/enabling-https-for-your-pi-hole-web-interface/5771/17 * Copy the cert to `/etc/ssl/STAR_thighhighs_top.combined.pem`, which is a concatenation of the key, the cert, the intermediate CA chain, and apparently the root CA's cert in my case. I dunno why I did that. * Install the `mod_openssl` for lighttpd: {{{ apt install lighttpd-mod-openssl }}} * Create `/etc/lighttpd/conf-enabled/pihole-tls.conf` with the following contents {{{#!conf server.modules += ( "mod_openssl" ) $HTTP["host"] =~ "^[a-zA-Z0-9-_]+\.thighhighs\.top$" { # Ensure the Pi-hole Block Page knows that this is not a blocked domain setenv.add-environment = ("fqdn" => "true") # TLS cert for Pihole admin interface $SERVER["socket"] == ":443" { ssl.engine = "enable" ssl.pemfile = "/etc/ssl/STAR_thighhighs_top.combined.pem" ssl.openssl.ssl-conf-cmd = ("MinProtocol" => "TLSv1.3", "Options" => "-ServerPreference") } $SERVER["socket"] == "[::]:443" { ssl.engine = "enable" ssl.pemfile = "/etc/ssl/STAR_thighhighs_top.combined.pem" ssl.openssl.ssl-conf-cmd = ("MinProtocol" => "TLSv1.3", "Options" => "-ServerPreference") } # Redirect HTTP to HTTPS $HTTP["scheme"] == "http" { $HTTP["host"] =~ ".*" { url.redirect = (".*" => "https://%0$0") } } } }}} * Then restart lighttpd and it should just work. == Firewall == As per https://docs.pi-hole.net/main/prerequisites/ I've installed ufw and locked things down. Limit and fail2ban would be good to do as well: https://www.raspberrypi.org/documentation/configuration/security.md {{{ apt install -y ufw ufw allow from 192.168.1.0/24 to any app OpenSSH ufw allow from 2404:e80:42e3:0::/64 to any app OpenSSH ufw enable # Pihole stuff - https://docs.pi-hole.net/main/prerequisites/#ufw ufw allow http ufw allow https ufw allow domain ufw allow 67/udp ufw allow 67/tcp ufw allow 546:547/udp }}}