Skip to main content
  1. Our Guides/
  2. CoreDNS @ Wolfspyre Labs/
  3. 🏗️ Setting Up CoreDNS/
  4. Pi4 Soup to nuts/

③ Base Config

🐾

Ready? cool. #

First things first…. Power #

So. You’ve got everything ready to go… lets power yer Pi up and get to configuring stuff.

Access #

You’re likely to want to login to the host locally first. It just removes one more potential hiccup point.

Users keys and passwords #

My usual practice is to create a couple users on a host.

  • 🐺 One user for myself.
     This user is usually wolf or wnoble ¯\_(ツ)_/¯.
        This user has no special privilges, and is usually only permitted to login from a few addresses
  • 🤖 One user for automation.
    • This user usually has password authentication disabled.
  • The user(s) actually running the services

I keep the same UID/gid across all my machines so’s that nfsmounted homedirs, if I ever choose to use them, aren’t an utter mess.

Create users #

Personal user(s) #
user creation
useradd --uid 9999 --create-home --home-dir /home/wolf \   
--shell /usr/bin/bash --comment "Wolf Noble"  wolf &&
passwd wolf

Change Passwords #

Change the password of each user that is capable of logging in.. The password should be unique, long, and stored someplace safe. like a password manager like 1password.

Users warranting new passwords #
  • ubuntu
  • pi
  • root
  • any other password-enabled user you’ve created.

Create ssh keys #

For each user

sshkey creation
if [[ -f ${HOME}/.ssh/id_rsa.pub ]]; then
  echo "ssh key exists for `whoami`"
else
  echo "`whoami` has no ssh key. Generating."
  ssh-keygen 
Next add your newly minted sshkey to authorized_keys

sshkey authorization
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys && chmod 0600 ~/.ssh/authorized_keys
Deploy ssh keys to siblings #
sshkey replication
for user in USERLISTHERE; do
  for host in coredns-01 coredns-02 coredns-03; do
    su - ${user}
    ssh-copy-id ${user}@${host}
  done
done

Grant sudo privileges #

Privilege #

/etc/sudoers.d/010_pi-nopasswd:

pi ALL=(ALL) NOPASSWD: ALL

/etc/sudoers.d/011_wolf-nopasswd:

wolf ALL=(ALL) ALL

Test the above #

validate you can:

  • login to each host as the user expected.
  • users that should be able to perform sudo actions can.
  • each host should be able to be accessed by the others as relevant users.

…. Lets continue, shall we?

Configure the network interface to be statically defined #

As a general rule, Your core infrastructure should be as self-reliant as possible.
This means removing as many functional dependencies as possible.
When viewed through that lens, it makes a lot of sense to statically configure your DNS server’s network stack.

That being said, it’s also worthwhile to make things as antifragile as possible.

On the off chance that host reverts its’ networking config to use DHCP,
it’d be nice if your DHCP server issued it the address everything expects it to be at, right?

……RIGHT?

Identify your host’s MAC address and current IP address. #

running the command ip a show eth0 should give you everything you need here:

root@coredns:~/# ip a show eth0
root@coredns-03:/home/pi# ip a show eth0
This should output something similar to:

root@coredns:~/# ip a show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether dc:a6:32:ff:aa:dd brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.53/24 metric 100 brd 192.168.1.255 scope global dynamic eth0
       valid_lft 24271sec preferred_lft 24271sec
    inet6 fe80::dea6:32ff:fe55:9063/64 scope link
       valid_lft forever preferred_lft forever 
This is telling you that your eth0 interface has the mac address dc:a6:32:ff:aa:dd. Use this to configure your DHCP server.

Tip
Configuring your DHCP server to assign a specific address to this host is optional, and outside the scope of this guide.
It’s worth doing, imho..

Statically configure your network interface #

Ubuntu 22 uses a combination of cloud-init and netplan to configure networking.

The way to statically configure the network is by

Editing the netplan configuration file: #

As you can see below, the original example config for netplan isn’t terribly informative.
Fortunately the netplan manpage has some good examples in it: man netplan


/etc/netplan/50-cloud-init.yaml (original)
# This file is generated from information provided by the datasource.  Changes
# to it will not persist across an instance reboot.  To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    ethernets:
        eth0:
            dhcp4: true
            optional: true
    version: 2
/etc/netplan/50-cloud-init.yaml (static config)
# This file is generated from information provided by the datasource.  Changes
# to it will not persist across an instance reboot.  To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
  version: 2
  ethernets:
    eth0:
      match:
        macaddress: 'dc:a6:32:ff:aa:dd'
      wakeonlan: true
      set-name: 'eth0'
      dhcp4: false
      addresses:
      - '192.168.53.53/16'
      gateway4: '192.168.1.1'
      nameservers:
        search: [dmz.wolfspyre.io, wolfspyre.io]
        addresses: ['127.0.0.1']

Test the configuration #

netplan try --debug

If this worked as anticipated, you’ll be prompted to Press ENTER before a timer resets. If not, wait a minute or so and ssh back in and try again.

Warning
This might be obvious, but if you’re changing the address your host will have, a successful test will kill your ssh connection.
In this case, getting a ping going from your workstation to the new target address will make it easy for you to assess when you can ssh into the host at its new address.

Disable Cloudinit #

The Nice thing about the example Netplan config, is it tells you exactly how to disable cloudinit.

To disable cloud-init’s network configuration capabilities, write a file
/etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
network: {config: disabled}

so… that’s pretty straight forward:

echo 'network: {config: disabled}' > /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg


Package installations #

Some basic packages that we are certain to want:

Install some packages
apt-get install dstat grub-common grub2-common ifstat jq logrotate \
net-tools netstat-nat nicstat ntpdate raspi-config os-prober screen \
silversearcher-ag sysstat tmux tree unzip 
#

Set Local time #

Its fairly simple to set the local timezone:

rm -rf /etc/localtime; ln -s /usr/share/zoneinfo/America/Chicago /etc/localtime


WolfspyreLabs Scoped stuff #

🐾
A lot of this stuff could and arguabbly should be done with automation..
AND I don’t want to get into a chicken/egg situation with my core infrastructure.
I will likely write some ansible playbooks to configure a lot of this in the future, which will retain steady-state config over time.
BUT I wanted to have this focus on CoreDNS not on the automation-tool-du-jour1

Directories and Files #

/etc/hosts #

So for critical infra hosts, I populate /etc/hosts with the IP addresses of the hosts that system will need to talk to in order to function.
This helps reduce fragility in times of odd fluctuation.

Uncomment the entries for the relevant network segment for the host being built.

/etc/hosts
127.0.0.1 localhost
10.18.42.53 coredns-01.mgt.wolfspyre.io coredns-01.wolfspyre.io coredns-01 coredns01 coredns # dns-1
10.18.40.53 coredns-02.dmz.wolfspyre.io coredns-02.wolfspyre.io coredns-02 coredns02 coredns # dns-2
10.0.2.53   coredns-03.wolfspyre.com    coredns-03.wolfspyre.io coredns-03 coredns03 coredns # dns-3
# 10.18.42.1  skwirrweltrap.mgt.wolfspyre.io skwirreltrap.wolfspyre.io skwirreltrap            # firewall vip
# 10.18.42.2  atticus.mgt.wolfspyre.io atticus.wolfspyre.io atticus                            # firewall A
# 10.18.42.3  evey.mgt.wolfspyre.io evey.wolfspyre.io evey                                     # firewall B
# 10.18.40.1  skwirrweltrap.dmz.wolfspyre.io skwirreltrap.wolfspyre.io skwirreltrap            # firewall vip
# 10.18.40.2  atticus.dmz.wolfspyre.io atticus.wolfspyre.io atticus                            # firewall A
# 10.18.40.3  evey.dmz.wolfspyre.io evey.wolfspyre.io evey                                     # firewall B
# 10.0.2.1    skwirrweltrap.wolfspyre.com skwirreltrap.wolfspyre.io skwirreltrap               # firewall vip
# 10.0.2.2    atticus.wolfspyre.com atticus.wolfspyre.io atticus                               # firewall A
# 10.0.2.3    evey.wolfspyre.com  evey.wolfspyre.io evey                                       # firewall B
# 10.18.42.23 pine.mgt.wolfspyre.io pine.wolfspyre.io pine                                     # NAS
# 10.18.40.23 pine.dmz.wolfspyre.io pine.wolfspyre.io pine                                     # NAS
# 10.0.2.23   pine.wolfspyre.com pine.wolfspyre.io pine                                        # NAS

/etc/networks #

/etc/networks
default           0.0.0.0
loopback          127              loopback-net
gitlab-jogger     172.20.57.0
gitlab-walker     172.20.58.0
gitlab-crawler    172.20.59.0
link-local        169.254.0.0
Infra             10.18.1.0
NoblewiseNet      192.0.0.0
PXELan            10.18.3.0
Tinkerbell        10.18.4.0
Proxmox           10.18.10.0
VMZNet            10.18.12.0
AD-Net            10.18.15.0
Ranchernet        10.18.18.0
Protect-DMZ       10.18.36.0
Noblewise-DMZ     10.18.40.0
Logging-Metrics   10.18.41.0
Management-Net    10.18.42.0
Proxmox-Internal  10.18.43.0
Aruba-VCLAN       10.18.44.0
KVM-PVT           10.18.50.0
StorageNET        10.18.198.0
Ceph-Net          10.18.199.0
VPN-Net           10.18.200.0

/etc/rc.local #

the rc.local script runs after the system is running. Specifically WHEN it runs depends on a few things, but it’s sufficient to say it runs late in the boot process.

We will use it later in this guide to optionally refresh things

Info
It’s easy to forget that the script must be executable in order to be run. Ergo:
chmod +x /etc/rc.local
/etc/rc.local
#!/usr/bin/env bash
##/etc/rc.local
/etc/init.d/procps restart
# This is only here to give you a way to validate the script is firing. 
/usr/bin/date > /tmp/rclocal_script_has_run
exit 0

/etc/services #

I try to populate /etc/services with relevant information for the ports services will listen on. This is of questionable value.
IANAs port assignment registry
should be considered the canonical source

update /etc/services
echo -e "node-exporter\t9100/tcp\tmetrics\t\t#prometheus metrics" | sort -k2 -n -o /etc/services -m - /etc/services
echo -e "coredns-metrics\t9153/tcp\tcoredns\t\t#prometheus metrics" | sort -k2 -n -o /etc/services -m - /etc/services
🐾

Update #

Now lets update the host, and wipe the slate clean… thus making sure everything comes back as expected.

sudo su - && apt-get update && apt-get -y upgrade && reboot

Go get a cup of something, this should take a few minutes, and your system will reboot. We’ll pick back up when the host has booted

🐾