{"id":598,"date":"2020-11-24T02:03:03","date_gmt":"2020-11-24T00:03:03","guid":{"rendered":"https:\/\/blog.chloesoe.ch\/?p=598"},"modified":"2021-03-15T22:58:30","modified_gmt":"2021-03-15T20:58:30","slug":"install-pihole-in-docker-compose-on-ubuntu-server","status":"publish","type":"post","link":"https:\/\/blog.chloesoe.ch\/?p=598","title":{"rendered":"Install PiHole in docker-compose on Ubuntu Server"},"content":{"rendered":"<h1>Overview<\/h1>\n<p>This will document how to install <a href=\"https:\/\/pi-hole.net\/\">PiHole<\/a> on an Ubuntu server. PiHole will run in docker-compose with couple including some volumes from the host, so data could be stored during updates. The docker container for pihole should be is ephemeral.<\/p>\n<h1>Base Installation<\/h1>\n<p><em>the following steps are done according to <a href=\"https:\/\/github.com\/pi-hole\/docker-pi-hole\">pi-hole\/docker-pi-hole<\/a><\/em><\/p>\n<p>Run this steps:<\/p>\n<ul>\n<li>\n<p>Install docker compose installed on yourserver.example.com with <code>sudo apt install docker-compose<\/code><\/p>\n<\/li>\n<li>\n<p>For the following use install folder <code>\/opt\/pihole<\/code><\/p>\n<\/li>\n<li>\n<p>create docker-compose.yaml in <code>\/opt\/pihole\/<\/code>, below is the final version incl the volumes which are added later:<\/p>\n<pre><code>* version: \"3\"\n# More info at https:\/\/github.com\/pi-hole\/docker-pi-hole\/ and https:\/\/docs.pi-hole.net\/\nservices:\npihole:\n  container_name: pihole\n  hostname: yourserver-pihole\n  image: pihole\/pihole:latest\n  ports:\n    - \"53:53\/tcp\"\n    - \"53:53\/udp\"\n    - \"67:67\/udp\"\n    - \"80:80\/tcp\"\n    - \"443:443\/tcp\"\n  environment:\n    ADMIN_EMAIL: 'pihole@example.com'\n    DNS1: '9.9.9.9'\n    DNS2: '1.1.1.1'\n    PIHOLE_BASE: '\/opt\/pihole'\n    TZ: 'Europe\/Zurich'\n    WEBPASSWORD: '...'\n  # Volumes store your data between container upgrades\n  volumes:\n    - '.\/etc-pihole\/:\/etc\/pihole\/'\n    - '.\/etc-dnsmasq.d\/:\/etc\/dnsmasq.d\/'\n    - '.\/letsencrypt:\/opt\/letsencrypt\/'\n    - '.\/letsencrypt\/lighttpd-external.conf:\/etc\/lighttpd\/external.conf'\n    - '.\/fakewebroot\/.well-known:\/var\/www\/html\/.well-known'\n  # Recommended but not required (DHCP needs NET_ADMIN)\n  #   https:\/\/github.com\/pi-hole\/docker-pi-hole#note-on-capabilities\n  cap_add:\n    - NET_ADMIN\n  restart: unless-stopped<\/code><\/pre>\n<\/li>\n<li>\n<p>You now can start it with with: <code>docker-compose up --detach<\/code><\/p>\n<\/li>\n<li>\n<p>You now can connect to <a href=\"http:\/\/yourserver.example.com\/admin\">http:\/\/yourserver.example.com\/admin<\/a>, make sure you don't login with the defined <code>WEBPASSWORD<\/code>, your conneciton isn't encrypted yet. <\/p>\n<\/li>\n<\/ul>\n<h1>Certificate with Let's Encrypt<\/h1>\n<p>The Admin interface isn't encrypted yet, therefore we want to run the let's encrypt (certbot) on the host machine.<\/p>\n<p><em>Below was done with information from <a href=\"https:\/\/discourse.pi-hole.net\/t\/enabling-https-for-your-pi-hole-web-interface\/5771\">https:\/\/discourse.pi-hole.net\/t\/enabling-https-for-your-pi-hole-web-interface\/5771<\/a><\/em><\/p>\n<ul>\n<li>We first create a folder <code>\/opt\/pihole\/fakewebroot<\/code> and <code>\/opt\/pihole\/letsencrypt<\/code>.<\/li>\n<li>Above we already added two volumes:\n<ul>\n<li><code>.\/letsencrypt:\/opt\/letsencrypt\/<\/code> to copy the combined.pem and fullchain.pem in<\/li>\n<li><code>.\/fakewebroot\/.well-known:\/var\/www\/html\/.well-known<\/code> which will be used by certbot for to safe the challenge<\/li>\n<\/ul>\n<\/li>\n<li>With this we can run the following command to get the initial certificate:\n<pre><code class=\"language-bash\">sudo certbot certonly --webroot \/opt\/pihole\/fakewebroot\/ -d yourserver.example.com<\/code><\/pre>\n<\/li>\n<li>Lighttpd needs a combined.pem which is not automatically created by certbot, so merge them to the letsencrypt folder in our pihole directory. Further copy the fullchain:\n<pre><code class=\"language-bash\">sudo cat \/etc\/letsencrypt\/live\/yourserver.example.com\/privkey.pem  \/etc\/letsencrypt\/live\/yourserver.example.com\/cert.pem > \/opt\/pihole\/letsencrypt\/combined.pem<\/code><\/pre>\n<\/li>\n<li>create a lighttpd-external.conf file in the letsencrypt folder, the file was already added via volumes in the beginnen, but here again:\n<ul>\n<li>Add file with volume command<br \/>\n<code><code>.\/letsencrypt\/lighttpd-external.conf:\/etc\/lighttpd\/external.conf <\/code><\/code><\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Add the following to the <code>lighthttpd-external.conf<\/code>, make sure you have the correct file names for <code>ssl.pemfile<\/code> and <code>ssl.ca-file<\/code>:<\/p>\n<pre><code>$HTTP[\"host\"] == \"yourserver.example.com\" {\n  # Ensure the Pi-hole Block Page knows that this is not a blocked domain\n  setenv.add-environment = (\"fqdn\" => \"true\")\n\n  # Enable the SSL engine with a LE cert, only for this specific host\n  $SERVER[\"socket\"] == \":443\" {\n    ssl.engine = \"enable\"\n    ssl.pemfile = \"\/opt\/letsencrypt\/combined.pem\"\n    ssl.ca-file =  \"\/opt\/letsencrypt\/fullchain.pem\"\n    ssl.honor-cipher-order = \"enable\"\n    ssl.cipher-list = \"EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH\"\n    ssl.use-sslv2 = \"disable\"\n    ssl.use-sslv3 = \"disable\"\n  }\n\n  # Redirect HTTP to HTTPS\n  $HTTP[\"scheme\"] == \"http\" {\n    $HTTP[\"host\"] =~ \".*\" {\n    url.redirect = (\".*\" => \"https:\/\/%0$0\")\n    }\n  }\n}<\/code><\/pre>\n<\/li>\n<\/ul>\n<h1>Renew Certificate Automatically<\/h1>\n<p>In the section before we already added the  well-known folder <code>\/opt\/pihole\/fakewebroot\/<\/code> and it is already added as volume in docker-compose.yaml<\/p>\n<p>We now need a post action for the timer renewing, create a post hook file. Add the file with <\/p>\n<pre><code class=\"language-bsh\">sudo vim \/etc\/letsencrypt\/renewal-hooks\/post\/redeploy-docker.sh<\/code><\/pre>\n<p>With this content:<\/p>\n<pre><code class=\"language-bash\">cat \/etc\/letsencrypt\/live\/yourserver.example.com\/privkey.pem \/etc\/letsencrypt\/live\/yourserver.example.com\/cert.pem &gt; \/opt\/pihole\/letsencrypt\/combined.pem\ncat \/etc\/letsencrypt\/live\/yourserver.example.com\/fullchain.pem \/etc\/letsencrypt\/live\/yourserver.example.com\/cert.pem &gt; \/opt\/pihole\/letsencrypt\/fullchain.pem\n\/usr\/bin\/docker-compose -f \/opt\/pihole\/docker-compose.yaml down &amp;&gt;\/dev\/null\n\/usr\/bin\/docker-compose -f \/opt\/pihole\/docker-compose.yaml up --detach &amp;&gt;\/dev\/null<\/code><\/pre>\n<p>And make it executable<\/p>\n<pre><code class=\"language-bash\">sudo chmod +x \/etc\/letsencrypt\/renewal-hooks\/post\/redeploy-docker.sh<\/code><\/pre>\n<p>This will copy the new certificate in to the correct folder and ensures, the docker container es restarted, so it will have the new ceritificate.<\/p>\n<p>You can test whether your script works properly with a dry-run<\/p>\n<pre><code class=\"language-bash\">sudo certbot renew --dry-run<\/code><\/pre>\n<p>If <code>docker ps<\/code> shows a new container id after that, the container was restarted successful. <\/p>\n<p>With <code>sudo openssl x509 -noout -text -in \/opt\/letsencrypt\/combined.pem | grep Validity -A3<\/code> you will see, whether the new certificate was copied correctly (doesn't really work shortly after the installation, because you have no new certificate)<\/p>\n<h1>Usage<\/h1>\n<p>Now you can use the IP address of yourserver.example.com as you DNS server address. <\/p>\n<p>You can now use <a href=\"https:\/\/yourserver.example.com\/admin\/\">https:\/\/yourserver.example.com\/admin\/<\/a> to check your server.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Overview This will document how to install PiHole on an Ubuntu server. PiHole will run in docker-compose with couple including some volumes from the host, so data could be stored during updates. The docker container for pihole should be is ephemeral. Base Installation the following steps are done according to pi-hole\/docker-pi-hole Run this steps: Install&#8230; <a href=\"https:\/\/blog.chloesoe.ch\/?p=598\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Install PiHole in docker-compose on Ubuntu Server<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13,7,17],"tags":[],"class_list":["post-598","post","type-post","status-publish","format-standard","hentry","category-docker","category-linux","category-webserver"],"_links":{"self":[{"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=\/wp\/v2\/posts\/598","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=598"}],"version-history":[{"count":7,"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=\/wp\/v2\/posts\/598\/revisions"}],"predecessor-version":[{"id":611,"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=\/wp\/v2\/posts\/598\/revisions\/611"}],"wp:attachment":[{"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=598"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=598"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=598"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}