PiHole 5 (and 6) enable/disable groups - block internet

Hi,

I wanted to share with you my little setup to enable and disable PiHole groups via a Command_Switch.

The purpose of this project is to restrict internet access for my kids a bit more fine-grained than just on/off. After all, most of their school homework is online. Let’s not get this discussion into a parenting conversation. And yes, there are easy ways to avoid a PiHole block. The kids are still young but I am sure we will end up in a whak-a-mole / arms-race situation sooner rather than later.

Anyway, here is my PiHole setup.
Every device in PiHole is in the Default group so everybody gets a base level of blocking.
Then there are additional groups with increasing levels of blocking.
Default
Kids
Kids-NoVideos
Kids-NoGames
IoT


All the kids devices are assigned to all the levels of kids groups as well as the default group.

The domains I want to block are assigned to the relevant group:


By enabling the relevant groups I can restrict access to these sites.

My setup is:
Home Assistant Core in a docker container on UnRaid
PiHole 5 also in a docker container on the same UnRaid server.

I added this script to PiHole to update the gravity.db database

then in HA I create this command switch:

You might need to find your own way to connect to where your PiHole runs.

These scripts come with no guarantee and as you can see there is no error handling built-in. It is up to you to make sure the names match and the groups exist. :slight_smile:

Hope this is useful for someone

PiHole6 Beta API version
see this simplified approach with PiHole6

7 Likes

Hi, if I understand your script correctly, it controls at each group level? i.e. Kid-NoVideos for whole network.
I have something similar but have separate switches for each kid device for each group.
One question, do you need ‘pihole -g’ after the sql to update gravity?
I have that but not sure that’s necessary.

[Update] I retested the need of ‘pihole -g’ in my sql command and proved necessary for my case.

I don’t think it is required.
Some basic testing today went OK without the gravity update. The real test is next week when the kids are back from camp.

I created a script to disable/enable some groups for kids and it shows right in the web interface, but it seems like some times the changes are not working. I need to go to the web interface and toggle the value manually to get it working. So, I wonder if this is the same issue you were having? If so, I probably will need to include the pihole -g to my script.

Hi, welcome to the community!!

Yes, I found ‘pihole -g’ is needed for my switches.
I did not using script but command_line switches with the sqlite codes directly.

Also, OP’s approach is different than mine, I have switches for each IP and block group, i.e. control J’s laptop gaming website access. That requires updating the “client_by_group” table instead and I used static IP with Pihole’s DHCP.

After creating my switches with some testing, I don’t check them regularly but just assume they work, especially when kids come asking for access :smiley:

Thank you. I am reviewing source code to try to determine what is exactly missing, I think it might be i need to clear DNS cache or update database timestamp, but still not sure about those.

Found that after updating group status in gravity database the web interface does call pihole restartdns reload-lists. So far, it seems to work.

If interested in checking source code where this is applied take a look at the end of the groups page:

Hi
I was looking to do this and this is the only thread that discuss how to do it. I am not an advanced user so could you please able to clarify

where do I need to put the script setGroupStatus.sh? In pi-hole install or HA?
what does sqlite3 /etc/pihole/gravity.db- is this the location where pi hole is installed?

My set up
proxmox 6.4 on which I run
a) home assistant in one KVM. It is on supervised mode- that is Debian 11, Docker v20 and used the script curl -Lo installer.sh https://raw.githubusercontent.com/home-assistant/supervised-installer/master/installer.sh
bash installer.sh
HA has Ip 192.168.0.200
b) Pihole installed in a separate KVM- Debian 10- Docker 19 and used docker compose to install it -See note 1 below
c) I have enabled home assistant pi-hole integration to pull the sensors etc and integration work on port 80 and KVM ip 192.168.0.253
d) I have pi-hole and adguard as my dns servers (internet dns not local dns) and unifi USG and unifi system and DHCP in in USG

Many thanks in advance. Also appreciate if you know of any other threads or videos that you could direct me to the info

note1:
pihole:
container_name: pihole
restart: always
image: pihole/pihole:latest
ports:
- “53:53/tcp”
- “53:53/udp”
- “67:67/udp”
- “80:80/tcp”
- “443:443/tcp”
environment:
TZ: “Australia/Adelaide”
WEBPASSWORD: “xxxxxxxx”
volumes:
- /home/sansam/pihole/pihole:/etc/pihole
- /home/sansam/pihole/dnsmasq:/etc/dnsmasq.d
dns:
- 127.0.0.1
- 1.1.1.1

Hi,
let me try to explain a bit better what is going on here.

Essentially you need to be able to enable/disable groups in PiHole. As far as I know there is no API available for that. Would be great if there was.
So we need to do it in the database. (That is what PiHole is suppoting)
PiHole uses SQLite as its DB.

The setGroupStatus.sh script makes that work by allowing us to easily change the status and also ask for the status of a group. This script needs to be installed on the PiHole host.

Then Home Assistant needs to be able to execute that script.
I am doing that by SSH into the host and then from there executing into the docker. That is certainly not very elegant and there should be a way to ssh directly to PiHole. (I could not make it work last time I tried, but I will try again soon.)
So you need to find a way to change this script:
command_on: ssh -oStrictHostKeyChecking=no [email protected] 'docker exec pihole5 bash /etc/pihole/setGroupStatus.sh Kids-NoGames enable'
to execute the script on PiHole.

If you have access to the SQLite DB from outside the container you might be able to manipulate it from there. ie: you seem to have it mapped to /home/sansam/pihole/pihole.
Maybe you can install SQLite on your ProxMox host and use that. In that case the setGroupStatus.sh script could be on the ProxMox host. But I am guessing here…

Thank you so much for the response. I am getting error in HA “Command failed: ssh -oStrictHostKeyChecking=no [email protected] ‘docker exec pihole bash /etc/pihole/setGroupStatus.sh School status’”

I added passwordless ssh from my home assistant LVM (192.168.0.200) to Debian Machine where pihole is installed (192.168.0.253). My group is School (not Kids-NoGames)

via HA machine (192.168.0.200) the following commands work perfectly. I issue the command via putty session on HA machine logged in as root
ssh -oStrictHostKeyChecking=no [email protected] ‘docker exec pihole bash /etc/pihole/setGroupStatus.sh School status’
ssh -oStrictHostKeyChecking=no [email protected] ‘docker exec pihole bash /etc/pihole/setGroupStatus.sh School enable’
ssh -oStrictHostKeyChecking=no [email protected] ‘docker exec pihole bash /etc/pihole/setGroupStatus.sh School disable’

My problem is that I cannot get the same command to work correct from HA. All the above commands give me the same error in hassio- Command failed: where from HA machine It work

I do not know what to do. I searched for command_line switches and the HA documentation is telling me to add command_on argument within " … " and I did but still get the same error

My HA switche is added to switches.yaml. I am running HA 2021.10.7, Debian 11, Docker 20+

  • platform: command_line
    switches:
    pihole_school:
    command_on: ssh -oStrictHostKeyChecking=no [email protected] ‘docker exec pihole bash /etc/pihole/setGroupStatus.sh School enable’
    command_off: ssh -oStrictHostKeyChecking=no [email protected] ‘docker exec pihole bash /etc/pihole/setGroupStatus.sh School disable’
    command_state: ssh -oStrictHostKeyChecking=no [email protected] ‘docker exec pihole bash /etc/pihole/setGroupStatus.sh School status’
    value_template: ‘{{ value == “1” }}’
    friendly_name: School_time

Appreciate any more advise

Hi,
yes, it is not a very elegant solution with SSH and keys and in my case it was no-password login.

Over the weekend I tried to implement an API that can be used to enable/disable the groups.

it is the first attempt and I have not yet added it to my setup, but it might be a bit better than the script.
Not sure if you want to give this a go ar keep looking at the script.
I won’t be able to tinker with it more until the weekend and there is no guarantee it is working. There is also no security implemented, anyone with access to the API can enable/disable all groups.

Thanks. i figure it out. The problem is that rsa passworless for the ssh command work for my virtual machine (my HA is in Debian 11 and docker - supervised install) but not for the home assistant which is in a docker container within the Debian 11.

So when i go inside my homeassistant docker it still ask for password for ssh command. What I tehrefore did was to go inside homeassistant docker with “sudo docker exe -it homeassistant bash” where homeassistant is the name of my hassio docker container name and then created rsa in there with “ssh–keygen -t rsa” and then copiy keys to the pihole machine with “ssh-copy-id [email protected]” where 192.168.0.253 is the machine where pihoole is running- again in a docker container

with above my ssh commands work within homeassistant docker container

as such now the switch work within home assistant interface. so when I turn on the switch it enable the group in pihole and when i turn off the switch it turn off the pihole group school

Thanks again. Just adding some notes here in case someone else get the same issue.

The problem has always being that ssh commands need password to execute. if not you get error in HA as such you need to make it able to access pihole machine passwordless. rsa method is secure so no problem there. If your HA is in a docker within a OS like debian then install RSA tocken in Debian does not automatically give that privilege to docker containers in that OS as sich will not work for homeassistant install in docker so you need to make ssh passwordless for each docker container and in this case homeassistant docker container by going to docker via “sudo docker exe -it homeassistant bash” where homeassistant is name of the docker container that has home assistant

1 Like

will this survive an upgrade of the docker container?
or do you have to do this every time you upgrade the container?

I will do HA update to 2021.11 and report back and I am sure it would not break it as I do not update the container to update HA - just like hassio on pi I just go to supervisor and update. That is how my install work. However if you install HA in docker say via docker compose etc it as long as you have config outside the container I cannot see why that would break it

well you are right. when I update HA it break the thing so need to do it each time I update HA. Not a big deal but not good. Need to figure out to change the location of tocken so it would in a folder like config where it would not get deleted each time docker update happen.

I will look at the API you are developing before I do the next HA update.

Not sure if there is a way to pass the password via shell_command rather than command_line. Only thing to fix is find a way to pass the password in the ssh command or have rsa tockens in a place where it will not get deleted

you could run a script after every update to re-establish the keys.
I think you would need to do the same in the PiHole container as well.

there is a dockerfile in my dbAPI and a docker on docker hub (Docker Hub).
But I only built it for my arch.

You need to map the directory that has the gravity.db into the container.
The API is on port 8000
and some basic documentation here host:8000/docs

OK, a bit of a disappointment.
I have the API ready, but if we can’t execute the
pihole restartdns reload-lists command then there is no point.
To run that command the whole SSH problem is back.

I might have to have another look at ssh from one container to the other and the keys have to survive a docker update.
Another idea I had was to add my dbAPI on into the pihole container, but I am not sure about that yet.

A little update.
I gave up on the API as I still need to call a command anyway.

But I found a solution.
I created the SSH keys in the config folder of HA so it does survive an update.
(following the top of this guide: Turn on/off UnRaid Server from Hassio & Voice Assistant)

Now I ssh from my HA Container to the docker host and then execute the script inside the PiHole docker as before.
So my switch config changed to this:

platform: command_line
switches:
  pihole_kids_nogames:
    command_on:    ssh -i /config/ssh_keys/.ssh/id_rsa [email protected] 'docker exec pihole5 bash /etc/pihole/setGroupStatus.sh Kids-NoGames enable'
    command_off:   ssh -i /config/ssh_keys/.ssh/id_rsa [email protected] 'docker exec pihole5 bash /etc/pihole/setGroupStatus.sh Kids-NoGames disable'
    command_state: ssh -i /config/ssh_keys/.ssh/id_rsa [email protected] 'docker exec pihole5 bash /etc/pihole/setGroupStatus.sh Kids-NoGames status'
    value_template: '{{ value == "1" }}'
    friendly_name: Block Games

I also changed the setGroupStatus.sh script a bit to not restart pihole DNS on every status check.

#!/bin/bash

# takes the group name and enable disable and status as input and
# updates the pihole gravity database accordingly
# then restarts the pihole dns and lists

# Data Monkey January 2021


case "$2" in
   "enable")
       sqlite3 /etc/pihole/gravity.db "update 'group' set 'enabled'=1 where name='$1'";
       # refresh PiHole
       /usr/local/bin/pihole restartdns reload-lists >/dev/null
       ;;
   "disable")
       sqlite3 /etc/pihole/gravity.db "update 'group' set 'enabled'=0 where name='$1'";
       # refresh PiHole
       /usr/local/bin/pihole restartdns reload-lists >/dev/null
       ;;
   "status")
       stat=`sqlite3 /etc/pihole/gravity.db " select enabled from 'group' where name = '$1';"`
       echo $stat
       exit 0
       ;;
   *)
   echo $"Usage: $0 {GroupName enable|disable|status}"
   exit 1
esac

Thank you for this. I looked around the database file and was able to modify your script to work with blacklist. You use domainlist table and change from name to domain.

Credit to Data Monkey for the script.

#!/bin/bash

# takes the domain and enable disable and status as input and
# updates the pihole gravity database accordingly
# then restarts the pihole dns and lists

# Data Monkey January 2021


case "$2" in
   "enable")
       sqlite3 /etc/pihole/gravity.db "update 'domainlist' set 'enabled'=1 where domain='$1'";
       # refresh PiHole
       /usr/local/bin/pihole restartdns reload-lists >/dev/null
       ;;
   "disable")
       sqlite3 /etc/pihole/gravity.db "update 'domainlist' set 'enabled'=0 where domain='$1'";
       # refresh PiHole
       /usr/local/bin/pihole restartdns reload-lists >/dev/null
       ;;
   "status")
       stat=`sqlite3 /etc/pihole/gravity.db " select enabled from 'domainlist' where domain = '$1';"`
       echo $stat
       exit 0
       ;;
   *)
   echo $"Usage: $0 {domain enable|disable|status}"
   exit 1
esac
1 Like

I have a question around the switch configuration. My config only seems to turn the pihole on. I am not trying to implement specific gravity or use groups. I simply want to toggle the pihole on and off completely using the switch. Is there something I’m missing or another way to configure just a basic toggle on/off? The toggle slides to the ‘on’ indication, but then slides back to the ‘off’. Nothing happens if pihole is on. However, if I turn pihole off manually, either through command line or the gui, and then toggle it in home assistant it will turn back on. It’s like the command_off can’t be executed, and I’m not sure the command_state is even doing anything.

Also, what exactly is the value_template supposed to be doing?

platform: command_line
switches:
  4gb:
    command_on: ssh [email protected] 'docker exec pihole bash pihole enable'
    command_off: ssh [email protected] 'docker exec pihole bash pihole disable'
    command_state: ssh [email protected] 'docker exec pihole bash pihole status'
    value_template: '{{ value == "1" }}'
    friendly_name: Toggle pihole 4gb

EDIT:
Checked documentation, and found that command_state wasn’t helping and value_template needed to be changed in order to send the right command, based on the switch.
New code:

platform: command_line
switches:
  4gb:
    friendly_name: Toggle pihole 4gb
    command_on: ssh [email protected] 'docker exec pihole bash pihole enable'
    command_off: ssh [email protected] 'docker exec pihole bash pihole disable'
    value_template: >
      {{value_json.config.on}}

Last thing I would like to see is the icon_template variable to work. It would be nice for the icon to be of the pi-hole mdi and change color based on if pihole is enabled or disabled.