CPANEL updates, automated error checking.

This is a follow up to this post. The below script is written with automated CPANEL updates in mind, but could be quite easily modified to be used with any automated updates with logs.

!/bin/bash
cd /var/cpanel/updatelogs # Change to cpanel updates logs directory.
VAR1=$(ls -tr up*|tail -1) # Find the latest log and set it as a variable.
egrep 'Error:|error:|Another app is currently holding the yum lock|Segmentation fault' $VAR1 > /tmp/update-check # Check for errors and output to temp file
if egrep 'Error:|error:|Another app is currently holding the yum lock|Segmentation fault' /tmp/update-check; then # If then to check for errors and send email alert if  required.
     /bin/mail -s "$(echo -e "Check to see if updates work, failed\nX-Priority: 1")" < /tmp/update-check root
fi
unset VAR1 # Unset variable.

Cronjob should be scheduled about an hour after updates:

0 0 * * * /bin/bash  /usr/local/sbin/upcp-check.sh &>/dev/null 

Thanks Tom.

P.S Please feel free to comment.

Advanced Policy Firewall Systemd – Proper solution.

This post is an update to the blog posted here. I believe I have a working solution for the apf service to fail, if apf doesn’t start correctly:

/etc/systemd/system/apf.service:

[Unit] 
Description=apf firewall with iptables
After=syslog.target network.target

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/usr/local/sbin/apf-start.sh
ExecStop=/usr/local/sbin/apf --stop

[Install]
WantedBy=basic.target

/usr/local/sbin/apf-start.sh:

#!/bin/bash
/usr/local/sbin/apf --start &> /tmp/check-apf
if egrep 'unable to load iptables module|timed out while attempting to gain lock|could not process allow_hosts|could not process deny_hosts|apf does not appear to have rules loaded|could not verify that interface|trust rules unchanged since last refresh' /tmp/check-apf; then
     /usr/local/sbin/apf --stop
     echo "APF Aborted"
     exit 1
else
     echo "All ok"
fi
exit 0

From looking at /etc/apf/internals/functions.apf, the egrep should cover all possible errors. If anyone thinks I’ve missed any, please feel free to let me know.

I have confirmed results in systemd failure by changing un-trusted interface to a interface which doesn’t exist on my system.

I’ve updated the issue for this on rfxn’s github.

Thanks Tom.

P.S Please feel free to comment.

Centos Yum update, failure alert – Updated Scripts

This is an update to the blog posted here. The original scripts have an issue when updates are available, in the fact that there is an alert sent if the updates are not installed. Being as the whole point is to check whether updates work, rather than updating; this is unwanted behaviour. So the scripts have been rewritten:

Centos 6:

#!/bin/bash
/usr/bin/timeout 120 /usr/bin/yum update --assumeno &> /tmp/check-update # check for rpm database & dependency errors
rm -rf /tmp/yum_save_tx* # clear yum saved transactions
if egrep 'Error:|error:|Another app is currently holding the yum lock|Segmentation fault' /tmp/check-update; then # if condition checks yum output for errors and sends email if there is any
    /bin/mail -s "$(echo -e "Check to see if updates work, failed\nX-Priority: 1")" < /tmp/check-update root
fi

Centos 7:

#!/bin/bash
/bin/timeout 120 /bin/yum update --assumeno &> /tmp/check-update # check for rpm database & dependency errors
rm -rf /tmp/yum_save_tx* # clear yum saved transactions
if egrep 'Error:| error:|Another app is currently holding the yum lock|Segmentation fault' /tmp/check-update; then # if condition checks yum output for errors and sends email if there is any
    /bin/mail -s "$(echo -e "Check to see if updates work, failed\nX-Priority: 1")" < /tmp/check-update root
fi

Thanks Tom.

P.S Please feel free to comment.

Centos Yum update, failure alert

As linux systems admin you may have multiple servers, in this case it would make sense to automate updates. But even with the best monitoring failed updates can occasionally go unnoticed, with crontab and the below script; this can be avoided.

Create the script with you choice of editor:
/usr/local/sbin/ifupdateswork.sh

Centos 7:

#!/bin/bash
/bin/timeout 120 /bin/yum update --assumeno &> /tmp/check-update || /bin/mail -s "$(echo -e "Check to see if updates work, failed\nX-Priority: 1")" < /tmp/check-update root

Centos 6:

#!/bin/bash
/usr/bin/timeout 120 /usr/bin/yum update --assumeno &> /tmp/check-update || /bin/mail -s "$(echo -e "Check to see if updates work, failed\nX-Priority: 1")" < /tmp/check-update root

Lets breakdown the script before we go any further:

timeout 120 – This causes yum to automatically closes after 2 minutes, this prevents the script from causing the automatic update from failing.

yum update –assumeno – The script is only for testing updating works, not to install updates; this is what the assume no flag does.

&> /tmp/check-update – Writes (also overwrites) error and standard output to /tmp/check-update

|| /bin/mail -s “$(echo -e “Check to see if updates work, failed\nX-Priority: 1″)” < /tmp/check-update root – Email is only sent if for any reason updates would fail, subject is set to: Check to see if updates work, failed. Importance Priority 1 is set in the header of the email. Uses /tmp/check-update as the body of the email. Then sends the email to root, normally an alias would be used for root so the email is sent to the system administrator; but alias’s are not covered here.

Make the script only executable by root:
$ chmod u+x /usr/local/sbin/ifupdateswork.sh

Now schedule using crontab, I suggest running this script about an hour before the automated updates so for example mine looks like this:

0 0 * * * /bin/bash  /usr/local/sbin/ifupdateswork.sh

On this particular server automated updates run at 12:51 am every day.

Thats it, all done. If there are now any issues with updates an email alert will be sent and only then.

Thanks Tom.

P.S Please feel free to comment.


Arch Linux, openvpn Transmission Server on A KVM Virtual Machine.

This Weekend I decided to challenge myself, to setting a Tranmisson Server with Arch Linux on a KVM. For those of you not aware Arch Linux is a minimalist, with a lot of self config; a rolling release with latest packages.

These are the steps I followed:

Boot The KVM with install ISO, which can be downloaded from here: https://www.archlinux.org/download/

Follow this guide https://wiki.archlinux.org/index.php/installation_guide until Initramfs, Then:

edit /etc/mkinitcpio.conf: MODULES=(virtio virtio_blk virtio_pci virtio_net)

mkinitcpio -p linux

set root password with passwd
create new user:
useradd -m -g users -s /bin/bash *username*
passwd *username*

pacman -S grub grub-bios
grub-install –target=i386-pc –recheck /dev/vda
pacman -S os-prober
mkdir -p /boot/grub/locale
cp /usr/share/locale/en@quot/LC_MESSAGES/grub.mo /boot/grub/locale/en.mo
grub-mkconfig > /boot/grub/grub.cfg
exit

umount -R /mnt
reboot 0

You should now having a working Arch Linux install, but no network; check this guide to resolve:

Being as this a server, it should use a static IP address. Method 2 for static IP works.

add a nameserver to to /etc/resolv.conf e.g:

# Resolver configuration file.
# See resolv.conf(5) for details.
nameserver 1.1.1.1

edit /etc/sudoers to add user to sudo or drop sudo from the below commands and run as root instead.

Packages:

sudo pacman -S mlocate openvpn wget unzip python transmission-cli autofs nfs-utils intel-ucode polkit haveged iptables

update grub configuration for intel-ucode:

sudo grub-mkconfig -o /boot/grub/grub.cfg

The following is needed so ssh works on startup, without having to login in to the console first:

sudo systemctl enable haveged

iptables:

sudo iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
sudo iptables -A FORWARD -i tun0 -o ens3 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i ens3 -o tun0 -j ACCEPT
sudo iptables -A OUTPUT -o tun0 -m comment --comment "vpn" -j ACCEPT
sudo iptables -A OUTPUT -o ens3 -p icmp -m comment --comment "icmp" -j ACCEPT
sudo iptables -A OUTPUT -d 192.168.1.0/24 -o ens3 -m comment --comment "lan" -j ACCEPT
sudo iptables -A OUTPUT -o ens3 -p udp -m udp --dport 1198 -m comment --comment "openvpn" -j ACCEPT
sudo iptables -A OUTPUT -o ens3 -p tcp -m tcp --sport 22 -m comment --comment "ssh" -j ACCEPT
sudo iptables -A OUTPUT -o ens3 -p udp -m udp --dport 123 -m comment --comment "ntp" -j ACCEPT
sudo iptables -A OUTPUT -o ens3 -p udp -m udp --dport 53 -m comment --comment "dns" -j ACCEPT
sudo iptables -A OUTPUT -o ens3 -p tcp -m tcp --dport 53 -m comment --comment "dns" -j ACCEPT
sudo iptables -A OUTPUT -o ens3 -j DROP

replace 192.168.1.0/24 with your IP Range.

sudo su

iptables-save > /etc/iptables/iptables.rules

Openvpn configuration will vary depending on the provider, essentailly though provider will provide .opvn files for each server. This needs copying to a *.vpn, for example vpn.conf. Now create /etc/pass.txt add your vpn credentials, username first line; password 2nd. Update the following in vpn.conf:

auth-user-pass /etc/openvpn/pass.txt

sudo systemctl start openvpn@vpn
sudo systemctl enable openvpn@vpn

You can confirm you are no longer using your ISPs IP with:

curl ipinfo.io/ip

Network share

I’m assuming like me you downloading torrents to a network share, if not skip to Tranmssion Config

Using Autofs and /mnt/Transmission as the mount point:

sudo mkdir /mnt/Transmission

edit: /etc/autofs/auto.master

/- /etc/autofs/auto.server_name –timeout 15 browse

edit: /- /etc/autofs/auto.server_name

/mnt/Transmission IP of *server1*:*/path/to/share1*

sudo systemctl restart autofs

Tranmssion Config

sudo systemctl start transmisson
sudo systemctl stop transmisson

edit: /var/lib/transmission/.config/transmission-daemon/settings.json

You will want to update:

“download-dir”: “/mnt/Transmission/complete”,
“incomplete-dir”: “/mnt/Transmission/incomplete”,
“incomplete-dir-enabled”: true,
“rpc-password”: “password*,
“rpc-username”: “*username”,

optional limit to your network:

“rpc-whitelist”: “127.0.0.1,192.168.1.*”,

update 192.168.1 to your subnet.

sudo systemctl start transmisson
sudo systemctl enable transmisson

That’s it, like me you should now have a openvpn torrent server arch linux KVM.

Thanks Tom.

PS Feel Free to comment.

Sources:

https://wiki.archlinux.org/index.php/installation_guide
https://gist.github.com/tlatsas/5005963
http://allskyee.blogspot.com/2013/12/over-weekend-i-decided-to-give-arch.html
https://wiki.archlinux.org/index.php/Microcode
https://bbs.archlinux.org/viewtopic.php?id=241346
https://www.ostechnix.com/configure-static-dynamic-ip-address-arch-linux/
https://gist.github.com/superjamie/ac55b6d2c080582a3e64
https://wiki.archlinux.org/index.php/sysctl
https://wiki.archlinux.org/index.php/iptables
https://wiki.archlinux.org/index.php/autofs#Manual_NFS_configuration
https://discourse.osmc.tv/t/how-to-mounting-network-shares-with-autofs-alternative-to-fstab/74228
https://wiki.archlinux.org/index.php/transmission#Configuring_the_daemon


Paypal Two Factor Authentication, I wouldn’t bother… yet

Edit 04/08/2020 – Not sure when paypal’s 2fa offering updated, but this post is now redundant. All you need do now is login in to your paypal account, settings, security, “Manage 2-factor authentication” and select Authenticator APP.

Hi,

I just tried  using 2fa (Two Factor Authentication) with Paypal, by default I am offered one option and that is to be sent a SMS, or If I dig a bit further a TOTP (Time-based One-time Password algorithm) from Symantec but you either need to sign up to Symantec VIP or after going through some loops; you can use Google Authenticator.

Ok so here’s why you shouldn’t use sms:

https://www.howtogeek.com/310418/why-you-shouldnt-use-sms-for-two-factor-authentication/

So I opted to go through the loops and setup Google Authenticator.

So all seemed good now… Until made a purchase on ebay, to find I wasn’t prompted for my 2fa; apparently because my ebay & paypal account are linked. So if my ebay account is hacked, my 2fa on paypal is worthless. So now I looked at Ebay’s 2fa offering and I am presented with the same options as Paypal (and the same loops for TOTP).

At this point I disabled 2fa on paypal and have gone back to relying on passwords, I am using a password manager with a strong password generator; rather than relying 2fa options available. I recommend Roboform, Lastpass or Keepass.

If unlike me the above doesn’t put you off using Paypal’s 2fa, then feel free to try the following:

SMS – After logging in  click the settings cog (top right),  then SECURITY, then Security key and follow the on screen instructions.

Google Authenticator – https://medium.com/@dubistkomisch/set-up-2fa-two-factor-authentication-for-paypal-with-google-authenticator-or-other-totp-client-60fee63bfa4f – I suggest using the manual method,  but there is an  issue with current release of vipaccess; so ignore the first paragraph of manual method and do the following:

sudo apt-get update
sudo apt-get install python qrencode git
git clone https://github.com/cyrozap/python-vipaccess.git
cd python-vipaccess
sudo python setup.py install

Then proceed with paragraph 2 of the manual method.

I will end this blog by imploring Paypal & Ebay, to improve there 2fa offerings and reduce the loops to use methods such as Google Authenticator.

Thanks Toms.

P.S Please feel free to comment.

Raspian/Debian Thermometer

Hi,

Today’s post is about using the TEMPerV2:

https://www.modmypi.com/raspberry-pi/sensors-1061/temperaturepressurehumidity-1066/temper2-usb-dual-temperature-sensor

My version reports as:

lsusb
Bus 001 Device 004: ID 0b95:1790 ASIX Electronics Corp. AX88179 Gigabit Ethernet
Bus 001 Device 005: ID 413d:2107
Bus 001 Device 006: ID 0424:7800 Standard Microsystems Corp.
Bus 001 Device 003: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 002: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

I am currently using this with Raspbian in conjunction with a Zabbix server. Installing is as follows:

sudo apt-get install libhidapi-dev libhidapi-hidraw0 cmake git
git clone https://github.com/edorfaus/TEMPered.git

TEMPered/libtempered/temper_type.c needs modifying to work with this device, details be found here.

cd TEMPered 
mkdir build
cd build
cmake ..
make
sudo make install

On Raspbian/Debian the libs need to copied to another location, before TEMPered works as intended:

sudo cp /usr/local/lib/libtempered* /usr/lib/

TEMPered should now be working as intended, for example:

pi@pitemp:~ $ sudo tempered
/dev/hidraw1 0: temperature 26.56 °C

Zabbix

If you are using Zabbix:

https://www.zabbix.com/

like me then you can install zappix-agent

apt-get install zabbix-agent

And add the following to the bottom of: /etc/zabbix/zabbix_agentd.conf

UserParameter=cluster1.roomTemperature,tempered | grep -oP '(?<=/dev/hidraw1 0: temperature) [\d.]+'

Then restart Zabbix-agent:

systemctl restart zabbix-agent

Then add to your Zabbix  Server as an host item and Zabbix agent type.

SNMP (Not tested, but should work)

If your are using Nagios or PRTG, or if prefer SNMP can also use if it with Zabbix; advanced knowledge of SNMP is presumed:

And add the following to the bottom of:  /etc/snmp/snmpd.conf

pass .1.3.6.1.2.1.25.1.8 /bin/sh /usr/local/bin/snmp-cpu-temp

/usr/local/bin/snmp-cpu-temp

#!/bin/sh
if [ "$1" = "-g" ]
then
echo .1.3.6.1.2.1.25.1.8
echo gauge
tempered | grep -oP '(?<=/dev/hidraw1 0: temperature) [\d.]+'
fi
exit 0

Key: gauge

SNMP OID: .1.3.6.1.2.1.25.1.8

Edit 10/11/19 – /dev/hidraw1 needs to accessible by non root users.  This should be done with a udev rule, but I couldn’t get this this to work; if any has an answer to this please comment below. Anyway so I fudged it by adding /bin/chmod 666 /dev/hidraw1 to rc.local. On distos running systemd, a systemd unit will probably need to be created and enabled; I won’t advise how to that here as a google search will give results pretty quickly.

Cron

If you don’ want to use a network monitor server you could just set a cronjob to check the temperature and send an email alert if temperature is to high, for example:

sudo crontab -e
*/15 * * * * /bin/bash /home/pi/check-temp.sh

This will check the temperature every 15 minutes and send an alert if required.

/home/pi/check-temp.sh

#!/bin/bash
a=$(/usr/local/bin/tempered | grep -oP '(?<=/dev/hidraw1 0: temperature) [\d.]+')
b=40
export a
if [ $a \> $b ];
then
python /home/pi/alert.py
else
echo "Temperature" $a"c, normal";
fi;
sleep 10
unset a b

Will call /home/pi/alert.py and send alert if temperature is over 40 °c (to change this update b= ).

/home/pi/alert.py

# import necessary packages

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
import os

# create message object instance
msg = MIMEMultipart()

message = os.environ.get('a')

# setup the parameters of the message
password = "password"
msg['From'] = "[email protected]"
msg['To'] = "[email protected]"
msg['Subject'] = "Temperature Alert! Value in body is in Centigrade" 

# add in the message body
msg.attach(MIMEText(message, 'plain'))

#create server
server = smtplib.SMTP('mailserver.example.com: 25')

server.starttls()

# Login Credentials for sending the mail
server.login(msg['From'], password)


# send the message via the server.
server.sendmail(msg['From'], msg['To'], msg.as_string())
server.quit()

print "successfully sent email to %s:" % (msg['To'])

Thanks Tom.

P.S Please feel free to comment.

Sources:
https://github.com/edorfaus/TEMPered/issues/51#issuecomment-360364866

OpenVPN & Iptables

Hi,

Your VPN provider such as Private Internet Access or NordVPN,  will (should) have firewall rules in place; which provides protection to prevent access to your connected devices.  This is just an extra layer of security and is more peace of mind than anything.

-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -i tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i tun0 -j DROP
-A INPUT -s 192.168.1.0/24 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -s 127.0.0.0/8 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j DROP
-A OUTPUT -p tcp -m tcp --dport 22 -j DROP
-A OUTPUT -o tun0 -j ACCEPT
-A OUTPUT -o eth0 -j ACCEPT
-A OUTPUT -o wlan0 -j ACCEPT

The most important lines are:

-A INPUT -i tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i tun0 -j DROP

The first line of these 2 allows inbound connections from the vpn if a service (such as a webpage) has been requested outbound from your device. The 2nd line drops all other inbound traffic.

Thanks Tom.

P.S Please feel free to comment.

Docker stubby, run on start systemd; Raspbian

Hi,

Lets get the first question out of the way, why run stubby in a container:  I was hoping I wouldn’t have to compile from source (https://github.com/getdnsapi/getdns),  but stubby isn’t in stable Debian or Raspbian repositories; although buster works fine with Debian (x86), this is not the case with Raspbian (arm) had issues with dhcpd & iptables,  there are probably more issues, but I went back to stable before investigating further. The docker image compiles the source,  but the build environment is predefined; so this is a good compromise for me.

The second question: Why use systemd to start the container,  I like systemd and understand it; I don’t think any other reasons are required?

Setup

Install docker:

https://docs.docker.com/install/linux/docker-ce/debian/

sudo apt-get install git

git clone https://github.com/juzam/docker-getdns-stubby.git

cd ~/docker-getdns-stubby

The Dockerfile,  pulls the development branch (which on 29/11/18, wouldn’t compile);  Fixed by the developer 30/11/18, so we just need to change the exposed port:

mv Dockerfile Dockerfile.bak

nano or vi  Dockerfile

FROM debian:buster
MAINTAINER "Giovanni Angoli <[email protected]>"

RUN apt-get update && apt-get install -y libyaml-dev libssl-dev libtool-bin autoconf git make && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

RUN git clone https://github.com/getdnsapi/getdns.git

WORKDIR getdns

RUN git checkout develop && git submodule update --init && libtoolize -ci && autoreconf -fi && mkdir build
WORKDIR build
RUN ../configure --without-libidn --without-libidn2 --enable-stub-only --with-stubby && make && make install && ldconfig

COPY stubby.yml /usr/local/etc/stubby/stubby.yml

EXPOSE 53

CMD [ "/usr/local/bin/stubby" ]

If you wish to use to stubby with with pihole, then change EXPOSE to:

EXPOSE 5353

The stubby.yml provided this git repository uses IPv6, so needs updating if like myself using IPv4:

mv stubby.yml stubby.yml.bak

nano or vi stubby.yml

resolution_type: GETDNS_RESOLUTION_STUB
dns_transport_list:
  - GETDNS_TRANSPORT_TLS

tls_authentication: GETDNS_AUTHENTICATION_REQUIRED
tls_query_padding_blocksize: 256

edns_client_subnet_private: 1
idle_timeout: 10000
round_robin_upstreams: 0

listen_addresses:
  - 127.0.0.1@53
upstream_recursive_servers:
  - address_data: 9.9.9.9
    tls_auth_name: "dns.quad9.net"

If you wish to use to stubby with with pihole, I advise updating listen_addresses; as follows:

listen_addresses: 
  - 127.0.2.2@5353

sudo docker build -t getdns-stubby .

Systemd

nano or vi /lib/systemd/system/docker-stubby.service

[Unit]
Description=Stubby Container
After=docker.service

[Service]
RemainAfterExit=yes
ExecStart=/usr/bin/docker run -it -d --net=host getdns-stubby
ExecStop=/home/pi/stop-stubby.sh
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

nano or vi /home/pi/stop-stubby.sh

#!/bin/bash
/usr/bin/docker ps -q --filter ancestor=getdns-stubby | xargs -r docker stop

systemctl daemon-reload

systemctl enable docker-stubby

systemctl start docker-stubby

Testing

sudo apt-get install dnsutils

dig @127.0.0.1 quad9.net

expected result:

; <<>> DiG 9.10.3-P4-Raspbian <<>> @127.0.0.1 quad9.net
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51250
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65535
;; QUESTION SECTION:
;quad9.net. IN A

;; ANSWER SECTION:
quad9.net. 1200 IN A 216.21.3.77

;; Query time: 174 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Nov 21 00:03:58 UTC 2018
;; MSG SIZE rcvd: 63

If result is  different, please check the above instructions.

Now what?

You could now use the host which you have setup as a dns resolver, but I suggest going beyond that and use pihole:

https://pi-hole.net/

with stubby:

https://blog.sandchaschte.ch/en/pi-hole-with-dns-over-tls

Updating Stubby:

Every time docker-stubby. is started (including restarts), a new container is created, so when updating a clean up seems like a good idea; please follow the instructions below:

if using pihole:

# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 127.0.0.1

I suggest adding another nameserver temporarily, for example quad9:

nano or vi /etc/resolv.conf

nameserver 9.9.9.9

If docker-stubby. is the only docker on the host, then:

sudo systemctl stop docker-stubby.service
sudo docker system prune (and y)
sudo docker image rm getdns-stubby
cd ~/docker-getdns-stubby
sudo docker build -t getdns-stubby .
sudo systemctl start docker-stubby.service

if not:

sudo systemctl stop docker-stubby
docker ps -a
remove all containers for getdns-stubby with sudo docker rm for example:
sudo docker rm bf3aa2dd8bb1
sudo docker image rm getdns-stubby
cd ~/docker-getdns-stubby
sudo docker build -t getdns-stubby .
sudo systemctl start docker-stubby.service

Thanks Tom.

P.S Please feel free to comment.

Sources:

https://github.com/juzam/docker-getdns-stubby
https://blog.sandchaschte.ch/en/pi-hole-with-dns-over-tls
https://pi-hole.net/
https://github.com/getdnsapi/getdns.git
https://docs.docker.com/install/