Update config file during compose (Pihole cronjob schedule)

I’m migrating my pihole from VM to docker. My setup is that it is shut down automatically at 12am and starts again at 7am.

But the default pihole cron job schedule for updating its block lists falls in that range.

In non-docker deployment, I would just edit the /etc/cron.d/pihole manually, but that’s not possible in docker since it’s not permanent.

Can I just edit the /etc/cron.d/pihole through COMMAND in docker-compose? I’m not sure how the pihole container is created, is there a way to view the script of docker images?

I guess your post in the pihole forum is more likely to get an answer.

I have no idea what the cron job does, but if it’s related to updating the Gravity Database, then it’s something the container already does on every start (unless SKIPGRAVITYONBOOT=1 is specified).

Appart from that, you could run a cron job on your host and use docker exec to execute commands inside the container.

Don’t you create the pihole container using docker-compose or docker run yourself? Thus, I would be surprised if you wouldn’t exactly know how the pihole container is created, as you provide the configuration it uses to create it. When it commes to how the image is created, the pihole github repository is linked at the bottom of the Dockerhub image description.

Thanks for the reply.

I didn’t know about SKIPGRAVITYONBOOT=1, but I think this would only be triggered whenever I restart the container? The problem is I only put the machine to sleep.

By the way, how can I edit a certain config file in docker-compose? I’m thinking of editing the cron file at /etc/cron.d/pihole to change the schedule or just append another schedule to keep it simple.

I tried to do an echo ... >> /etc/cron.d/pihole' at the COMMAND` section of docker-compose but it fails to boot.

If I understood you currectly your problem is not that you WANT to edit the cron file, but you feel that you need it, because something changes the file.

My first thought was that it was obviously in the image, and you delete the container occasionally, so when ou start it again, you have the oiginal cron file. Then you wrote

So how exactly does that file change? Depending on on what that cronjob does (can you tell us about that?) I see a few options:

  1. If you knew the content of the file, create it locally, change the file locally, outside the container and mount it into the container. In this case you need to either mount a folder to /etc/cron.d with all of its content or make sure you edit the cron.d/pihole without creating a copy of that file and renaming it to the original file after editing. You would not do that intentionally, but some text editor does that and that way your file in the container would not change.
  2. Define /etc/cron.d as a named volume in the container, so even if the container is regenerated, the file will not be regenerated.
  3. Don’t change the file at all and use the pihole image as it supposed to be used. Let it do what is should do and if you need an additional cron job, run that outside the container and use docker exec or docker compose exec to run a command in a container if it is necessary. I would prefer this option, but as @meyay wrote, we don’t know what that cron job does and I will not try to find it out from the source code

Sorry for not explaining the issue in detail.

  • The pihole image creates a cron file (/etc/cron.d/pihole) for updating its adblock list and log rotation.
  • The default cron schedule however is during the time my machine is put to sleep

I wanted to update /etc/cron.d/pihole or append to it another cron schedule that is within my machine’s uptime. It’s also preferred to not have to create the file locally and mount it so that I can easily transfer/upgrade the container.

  • Is there a way to edit/append the /etc/cron.d/pihole in docker-compose?
  • I tried to define /etc/cron.d as a named volume in docker-compose but when I do, the /etc/cron.d/pihole file is not created.
version: "3"

# More info at https://github.com/pi-hole/docker-pi-hole/ and https://docs.pi-hole.net/
    container_name: pihole
    image: pihole/pihole:latest
    # For DHCP it is recommended to remove these ports and instead add: network_mode: "host"
      - "53:53/tcp"
      - "53:53/udp"
      - "67:67/udp" # Only required if you are using Pi-hole as your DHCP server
      - "80:80/tcp"
      TZ: 'America/Chicago'
      # WEBPASSWORD: 'set a secure password here or it will be random'
    # Volumes store your data between container upgrades
      - './etc-pihole:/etc/pihole'
      - './etc-dnsmasq.d:/etc/dnsmasq.d'    
      - './etc-cron.d:/etc/cron.d'
    #   https://github.com/pi-hole/docker-pi-hole#note-on-capabilities
      - NET_ADMIN # Recommended but not required (DHCP needs NET_ADMIN)      
    restart: unless-stopped

After creating the container with that, the contents of the /etc/cron.d/ directory is just:

But without mounting the /etc/cron.d/ directory, the contents are:



The /etc/cron.d/pihole file looks like this:

# Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
# Updates ad sources every week
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
# This file is under source-control of the Pi-hole installation and update
# scripts, any changes made to this file will be overwritten when the software
# is updated or re-installed. Please make any changes to the appropriate crontab
# or other cron file snippets.

# Pi-hole: Update the ad sources once a week on Sunday at a random time in the
#          early morning. Download any updates from the adlists
#          Squash output to log, then splat the log to stdout on error to allow for
#          standard crontab job error handling.
41 4   * * 7   root    PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updateGravity >/var/log/pihole/pihole_updateGravity.log || cat /var/log/pihole/pihole_updateGravity.log

# Pi-hole: Flush the log daily at 00:00
#          The flush script will use logrotate if available
#          parameter "once": logrotate only once (default is twice)
#          parameter "quiet": don't print messages
00 00   * * *   root    PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole flush once quiet

@reboot root /usr/sbin/logrotate --state /var/lib/logrotate/pihole /etc/pihole/logrotate

# Pi-hole: Grab local version and branch every 10 minutes
*/10 *  * * *   root    PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker local

# Pi-hole: Grab remote version every 24 hours
37 15  * * *   root    PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker remote
@reboot root    PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker remote reboot

Is it possible to just append this at the bottom (new cron schedule @ 7PM):

19 00   * * 7   root    PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updateGravity >/var/log/pihole/pihole_updateGravity.log || cat /var/log/pihole/pihole_updateGravity.log
19 00   * * *   root    PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole flush once quiet

But I think the missing files when mounting /etc/cron.d/ directory will still be an issue even if I get to append this to the cron file.

That is exactly the opposite. You should never move containers. Use prebuilt images or mount files into the container so you can run a container from the same image anywhere.

What you tried is not a named volume but a bind mount. You just mounted an empty folder into the container so it is suprising that you had anything copied to the folder. Perheps there was a cronjob that copied that file back, I don’t know. This is a named volume:

- cron-d:/etc/cron.d

Short answer: No. Longer answer is that everything is possible. Almost, but it requires more work which is not really necessary. The compose yaml is just a yaml configuration to define the container. If you want to edit any file, you need to write the command. You could build an image with a new entrypoint and add your own customization but if you can build a new image, you can just add a different pihole cron file.

That is actually what I meant. Not create an external file (/etc/cron.d/pihole) and having to copy that when recreating the container on another machine if I transfer machines or upgrade the container.

I thought mounted/named volumes will just make the directory persistent and whatever file the container script creates should still be there. Currently, even if I create an external /etc/cron.d/pihole file and persist the /etc/cron.d/ directory, my container would still not work because there are other files that are missing due to mounting /etc/cron.d/?

I tried this but I get
service "pihole" refers to undefined volume cron.d: invalid compose project

You missed the point. @rimelek was highlighting that you actualy do not use named volumes and use bind mounts instead (recognized from the host path you used). His example showed how a named volume would look like (just a handle, not a host path!), of course you still need to declare the volume in your compose file.

A bind mount and a named volume both get mounted into the container filesystem and eclipse the original content of the container folder (yes, even those that were inherited from the image!). The difference with named volumes is, that docker will copy the original content of the target folder back into the named volume, before mounting it. A named volume will be listed when the command docker volume ls is executed - bind mounts are not.

Thank you for that explanation. I understand it now.

I was able to create a named volume, and the files are persisted now.

I was also able to append a line to the /etc/cron.d/pihole file:

    command: >
      /bin/bash -c "echo '#test-line' >> /etc/cron.d/pihole"

I checked the file in the named volume, and I was able to see the #test-line.
However, the container fails to boot with this error in the log:

[cmd] /bin/bash exited 0
Stopping pihole-FTL
Stopping cron
Stopping lighttpd
[cont-finish.d] executing container finish scripts...
[cont-finish.d] done.
[s6-finish] waiting for services.
[s6-finish] sending all processes the TERM signal.
[s6-finish] sending all processes the KILL signal and exiting.

Then I tried to comment out the following in docker-compose:

    # command: >
      # /bin/bash -c "echo '#test-line' >> /etc/cron.d/pihole"

And the container booted up successfully, all while the /etc/cron.d/pihole is still the same with the #test-line.

I didn’t wrote this by accident:

When I wrote, you need to write the command, I meant a command in general, not the command parameter in the compose file. You can’t change that, because that controlls what will run when the container starts and you don’t want to change that, because nothing else will start then. This is why I mentioned a custom entrypoint file:

and also mentioned that there is no point of doing that if you can also create a custom image with a custom pihole file.

Even if you manage to customize your entrypoint, you can’t run it every time the container starts since you would append a new line every time and your file is on a volume now. So you should either use a volume and manually change the pihole file once or change the entrypoint which I don’t recommend to you because there is more chance to do it wrong.

I got you. That is very clear now mate. Thank you so much!