Table of Contents

Pi-Hole - Setup Pi-Hole running in LXC

Not Working

Create an LXC Container

lxc init ubuntu:20.04 pihole

returns:

Creating pihole

Check the status

lxc info pihole

returns:

Name: pihole
Location: none
Remote: unix://
Architecture: x86_64
Created: 2021/01/03 20:40 UTC
Status: Stopped
Type: container
Profiles: default

Start the Container

lxc start pihole

Check the status again

lxc info pihole

returns:

Name: pihole
Location: none
Remote: unix://
Architecture: x86_64
Created: 2021/01/03 20:40 UTC
Status: Running
Type: container
Profiles: default
Pid: 844849
Ips:
  eth0:	inet	10.207.221.25	vethd19000f6
  eth0:	inet6	fd42:4242:fe05:c96b:216:3eff:fecd:bd67	vethd19000f6
  eth0:	inet6	fe80::216:3eff:fecd:bd67	vethd19000f6
  lo:	inet	127.0.0.1
  lo:	inet6	::1
Resources:
  Processes: 76
  CPU usage:
    CPU usage (in seconds): 10
  Memory usage:
    Memory (current): 419.70MB
    Memory (peak): 462.38MB
  Network usage:
    eth0:
      Bytes received: 779.53kB
      Bytes sent: 20.10kB
      Packets received: 195
      Packets sent: 201
    lo:
      Bytes received: 1.68kB
      Bytes sent: 1.68kB
      Packets received: 19
      Packets sent: 19

NOTE: This shows the container is running.

It also shows it has an IP address of 10.207.221.25, which is probably not what is wanted as this is different from the host subnet range.


Assign the bride profile to the container

IMPORTANT: Do NOT use the macvlan profile as it does not allow the host to access the Container.

Every other device can access the Container, just not the host, unless the host is placed into Promiscuous mode.

See: Make your LXD containers get IP addresses from your LAN using macvlan

See: Create a Bridge Profile

lxc profile assign pihole default,bridgeprofile

returns:

Profiles default,bridgeprofile applied to pihole

NOTE: The assign command must have both the default and bridgeprofile profiles as shown.


Check the status once again

lxc info pihole

returns:

Name: pihole
Location: none
Remote: unix://
Architecture: x86_64
Created: 2021/01/03 20:40 UTC
Status: Running
Type: container
Profiles: default, bridgedprofile
Pid: 844849
Ips:
  eth0:	inet	192.168.1.150	br0
  eth0:	inet6	fe80::216:3eff:fe38:3c04	br0
  lo:	inet	127.0.0.1
  lo:	inet6	::1
Resources:
  Processes: 79
  CPU usage:
    CPU usage (in seconds): 10
  Memory usage:
    Memory (current): 427.35MB
    Memory (peak): 462.38MB
  Network usage:
    eth0:
      Bytes received: 1.29kB
      Bytes sent: 1.47kB
      Packets received: 11
      Packets sent: 11
    lo:
      Bytes received: 1.68kB
      Bytes sent: 1.68kB
      Packets received: 19
      Packets sent: 19

NOTE: The IP address has changed to 192.168.1.150.

This is the correct subnet matching that of the host.

If the result does not show an IP for eth0, then just wait a few seconds and retry. It seems to take a while sometimes before the container picks up the change. Do not panic if this continues to not show. Just continue with the steps.


Set the default login password

lxc exec pihole -- passwd ubuntu
New password: 
Retype new password: 
passwd: password updated successfully

NOTE: There is a default user account named ubuntu, which is being used here.

You could setup a completely different user account if wanted.

NOTE: An alternative way to do this is by:

lxc exec pihole -- /bin/bash

Then to issue the following command, and enter a secure password:

passwd ubuntu

Set up a proxy to allow web traffic into the LXD container (Optional)

On the host, not the container, add a proxy:

lxc config device add pihole web proxy listen=tcp:0.0.0.0:80 connect=tcp:127.0.0.1:80

returns:

Device web added to pihole

NOTE: Ensure that the Container is stopped before running this.

If this fails, then not a worry and may not be needed. You may get an error such as

Error: Failed to start device "web": Error occurred when starting proxy device: Error: Failed to listen on 0.0.0.0:80: listen tcp 0.0.0.0:80: bind: address already in use

Get a Shell inside the Container

lxc exec pihole bash

NOTE: Alternatively try:

lxc console pihole

returns:

To detach from the console, press: <ctrl>+a q

NOTE: Press <ENTER>.

pihole login: ubuntu
Password: 

NOTE: Enter ubuntu for the login and use the password you set for that account.

This should then log you into a standard ubuntu system:

Welcome to Ubuntu 20.04.1 LTS (GNU/Linux 5.4.0-58-generic x86_64)
 
 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
 
  System information as of Sun Jan  3 20:57:34 UTC 2021
 
  System load:    2.2       Temperature:           37.0 C
  Usage of /home: unknown   Processes:             24
  Memory usage:   0%        Users logged in:       0
  Swap usage:     0%        IPv4 address for eth0: 192.168.1.148
 
1 update can be installed immediately.
0 of these updates are security updates.
To see these additional updates run: apt list --upgradable
 
 
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
 
 
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
 
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
 
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

Check the Network

Ensure that LXC is configured properly; i.e. that it is able to access the internet.

ip a

returns:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
20: eth0@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 00:16:3e:38:3c:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.1.150/24 brd 192.168.1.255 scope global dynamic eth0
       valid_lft 6056sec preferred_lft 6056sec
    inet6 fe80::216:3eff:fe38:3c04/64 scope link 
       valid_lft forever preferred_lft forever

NOTE: The eth0 interface does show it has an IP address which is part of the host subnet, i.e. 192.168.1.150.

Try to ping.

ping 192.168.1.1 -c 1

returns:

PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.410 ms
 
--- 192.168.1.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.410/0.410/0.410/0.000 ms

NOTE: Change the ping address as needed to the correct subnet.

If the ping fails, then try to restart networking on the container:

netplan apply

Configure an IP on the Container

Pi-Hole needs a static IP, so set one.

By default the Container uses DHCP, so each time it starts it would receive a different IP.

vi /etc/netplan/50-cloud-init.yaml
# 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:
#            dhcp4: true
#
# Let NetworkManager manage all devices on this system
network:
  version: 2
  #renderer: NetworkManager
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: no
      # disable existing configuration for ethernet
      addresses: [192.168.1.150/24]
      gateway4: 192.168.1.1
      nameservers:
        addresses: [192.168.1.1]
      dhcp6: no

NOTE: This sets a static IP address, which is needed for Pi-Hole.

The default dhcp has been commented out, but can be deleted from this file.

The actual netplan filename may be slightly different; Edit the actual filename within the /etc/netplan directory.


Apply the network changes

netplan apply

Exit the Shell

exit

Restart the Pi-Hole Container

lxc restart pihole

Try to ping the Pi-Hole Container from the Host

ping 192.168.1.150

returns:

PING 192.168.1.150 (192.168.1.150) 56(84) bytes of data.
64 bytes from 192.168.1.150: icmp_seq=1 ttl=64 time=0.031 ms
64 bytes from 192.168.1.150: icmp_seq=2 ttl=64 time=0.027 ms
64 bytes from 192.168.1.150: icmp_seq=3 ttl=64 time=0.026 ms
64 bytes from 192.168.1.150: icmp_seq=4 ttl=64 time=0.044 ms
64 bytes from 192.168.1.150: icmp_seq=5 ttl=64 time=0.028 ms
 
--- 192.168.1.150 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4101ms
rtt min/avg/max/mdev = 0.026/0.031/0.044/0.006 ms

NOTE: If this step fails, bash back into the container

lxc exec pihole bash

and then restart the network:

netplan apply

Then exit and retry the ping and if that works you should be able to access Pi-Hole from the web.


Get a Shell inside the Container

lxc exec pihole bash

Update the Container

sudo apt update
sudo apt upgrade

Install additional packages

sudo apt install cron curl wget openssh-server vim ca-certificates

NOTE: Some of these additional packages may already be installed. Not a concern.

The ca-certificates package is needed to prevent errors later with curl.

Without this, errors such as: curl: (60) SSL certificate problem: unable to get local issuer certificate may be seen.

Of course, this package, as well as any other package can be installed later with commands such as:

apt install ca-certificates

Install Pi-Hole

sudo curl -sSL https://install.pi-hole.net | bash

or

curl -sSL https://install.pi-hole.net -o pihole.sh

NOTE: The 2nd option here just downloads the script. It does not actually install Pi-Hole until it is run.

This is a little safer, as it allows you to check the code in the script against trojans etc. Once you are sure it is okay then run:

sudo bash pihole.sh

Select the defaults until the DNS screen and then choose Cloudflare as your DNS.


NOTE: If an error occurs, then either fix the firewall rules or try:

curl -sSL https://install.pi-hole.net | PIHOLE_SKIP_OS_CHECK=true sudo -E bash

Set the Pi-hole password

When you return to the prompt in the terminal session, enter the following command to set your Pi-hole password:

pihole -a -p

Try to access Pi-Hole from a Web Browser

192.168.1.150

IMPORTANT: Make sure that the URL you type is does NOT contain https:// in front of the IP Address.

NOTE: If this fails, then try to access it from a different device than the host.

If this works, then mostly good. Primary reason host cannot access is that the network needs to run in Promiscuous mode.

Configure Promiscuous mode then retry.

An alternative option is to use a Bridged Profile.


Exit the Pi-Hole Container

exit

Get Information on the Pi-Hole Container

lxc info pihole

returns:

Name: pihole
Location: none
Remote: unix://
Architecture: x86_64
Created: 2021/01/07 14:59 UTC
Status: Running
Type: container
Profiles: default, bridgeprofile
Pid: 708446
Ips:
  eth0:	inet	192.168.1.150	vethb3f914e9
  eth0:	inet6	fe80::216:3eff:fecb:fcf8	vethb3f914e9
  lo:	inet	127.0.0.1
  lo:	inet6	::1
Resources:
  Processes: 88
  CPU usage:
    CPU usage (in seconds): 20
  Memory usage:
    Memory (current): 266.82MB
    Memory (peak): 276.11MB
  Network usage:
    eth0:
      Bytes received: 2.45MB
      Bytes sent: 3.70MB
      Packets received: 18537
      Packets sent: 3905
    lo:
      Bytes received: 4.05MB
      Bytes sent: 4.05MB
      Packets received: 60882
      Packets sent: 60882

TIP: If this still does not work, then perhaps delete the Pi-Hole Container and restart.

lxc delete pihole
lxc profile delete macvlan
lxc profile delete bridgeprofile

No need to delete the profiles if you are happy with these. Just delete the actual Container and follow the steps above.


Have the LXC Container Start Automatically

By default, LXC containers may not start automatically.

lxc config set pihole boot.autostart true

Ensure that LXC is set to start containers at boot.

/etc/default/lxc
# LXC_AUTO - whether or not to start containers at boot
LXC_AUTO="true"

NOTE: Also check file /etc/default/lxc-net, just in case this overrides this setting.

NOTE: Autostart is mainly used to select which containers to start.

When the host system boots, LXC decides the order and the delay between each startup.


Show the Pi-Hole Container Configuration File

lxc config show pihole

returns:

architecture: x86_64
config:
  boot.autostart: "true"
  image.architecture: amd64
  image.description: ubuntu 20.04 LTS amd64 (release) (20210105)
  image.label: release
  image.os: ubuntu
  image.release: focal
  image.serial: "20210105"
  image.type: squashfs
  image.version: "20.04"
  volatile.base_image: 21da67063730fc446ca7fe090a7cf90ad9397ff4001f69907d7db690a30897c3
  volatile.eth0.host_name: veth9b7de9bd
  volatile.eth0.hwaddr: 00:16:3e:4c:1b:d7
  volatile.idmap.base: "0"
  volatile.idmap.current: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":1000000000},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":1000000000}]'
  volatile.idmap.next: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":1000000000},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":1000000000}]'
  volatile.last_state.idmap: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":1000000000},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":1000000000}]'
  volatile.last_state.power: RUNNING
  volatile.uuid: 10e59167-cf89-4919-bb1c-9e701d15e08c
devices: {}
ephemeral: false
profiles:
- default
- bridgeprofile
stateful: false
description: ""

NOTE: This file will not be created until a change is made to it.

In this case, the autostart config done previously has enabled this.