Containers

10 Best Docker Container Stacks I am using in 2024

Learn about the top 10 docker container stacks I am using in 2024 in the home lab for infrastructure services

I have been using tons of Docker stacks this year and moving into 2025, that doesn’t look to be slowing down for me. I have several standalone Docker container hosts, as well as a production swarm cluster in the home lab that I have been running for some months now that is extremely awesome, with tools like Portainer. Check out my write up showing how Docker Swarm is awesome with Portainer and how you can build the exact same thing as I am using. I have been committed to checking in my docker compose code to my repo to have proper versioning of my code and keep up with things much better. Let’s look at the 10 best docker container stacks I am using in the lab at the end of 2024.

What are docker container stacks?

A docker “stack” is kind of a general term that many different tools use to describe a way to group multiple containers together in a “stack” to work as one application. Docker-compose makes this possible and is really the reason behind it. You can bring up your docker container stack as one unit, even if it is made up of 8, 10 or multiple containers.

I have been organizing my docker container stacks in a repository this year in a self-hosted repository in GitLab and keeping up with the stacks I am using in a much more organized way. Let’s now look at the stacks that I have on my 10 best docker container stacks I am using in 2024.

1. Nginx Proxy Manager

The docker container stack that I want to start with is what I have built my docker container environment around, Nginx Proxy Manager (NPM). With NPM, I create the network that I use for the other container stacks in my environment. I like to build my other stacks around the proxy service that I am using as I have found this seems to work out well and leads to consistency from a networking perspective.

Nginx proxy manager
Nginx proxy manager

This way I can force all traffic to go through the NPM proxy function and the network it provisions. For my environment, NPM provides SSL termination for my containerized solutions in the home lab and I love it. Traefik is awesome to and provides a solution that is well-suited for either Docker or Kubernetes environments. But, NPM is just very straightforward and easy with the GUI. If you need to provide an easy way to add SSL certificates to your environment, NPM is a great choice.

version: '3.8'
services:
  npm:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: always
    networks:
      - nginxproxy
    ports:
      - '80:80'
      - '81:81'
      - '443:443'
    volumes:
      - "/home/linuxadmin/homelabservices/nginxproxymanager/data:/data"
      - "/home/linuxadmin/homelabservices/nginxproxymanager/letsencrypt:/etc/letsencrypt"
    container_name: nginxproxy

  npmdb:
    image: 'jc21/mariadb-aria:latest'
    restart: always
    networks:
      - nginxproxy
    environment:
      MYSQL_ROOT_PASSWORD: 'npm'
      MYSQL_DATABASE: 'npm'
      MYSQL_USER: 'npm'
      MYSQL_PASSWORD: 'npm'
    volumes:
      - /home/linuxadmin/homelabservices/nginxproxymanager/mysql:/var/lib/mysql

networks:
  nginxproxy:
    driver: bridge
    name: nginxproxy

2. GitLab

I have tried other self-hosted code repos and CI/CD solutions and still keep coming back to GitLab. I think it is the best one out there with the most mature tools and capabilities. If you want a single solution that can do everything in a seamless way, I think GitLab is my top pick here.

Gitlab
Gitlab

There are many other great self-hosted solutions like Gitea that I like very much and am still trying out and playing around with. But, for my tastes currently, the the CI/CD capabilities with Gitea are still a bit immature. Here is my GitLab stack for running Gitlab and a runner:

version: '3.8'
services:
  gitlab:
    image: gitlab/gitlab-ee:latest
    hostname: 'gitlab.mydomain.com'
    restart: always 
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'https://gitlab.mydomain.com'
        letsencrypt['enabled'] = false
        # Reverse proxy nginx config
        nginx['listen_port'] = 80
        nginx['listen_https'] = false
        nginx['redirect_http_to_https'] = false
        nginx['proxy_set_headers'] = {
          "X-Forwarded-Proto" => "https",
          "X-Forwarded-Ssl" => "on",
          "Host" => "gitlab.mydomain.com",
          "X-Real-IP" => "$$remote_addr",
          "X-Forwarded-For" => "$$proxy_add_x_forwarded_for",
          "Upgrade" => "$$http_upgrade",
          "Connection" => "$$connection_upgrade"
        }
    networks:
      - nginxproxy
    volumes:
      - '/home/linuxadmin/homelabservices/gitlab/data:/var/opt/gitlab'
      - '/home/linuxadmin/homelabservices/gitlab/config:/etc/gitlab'
      - '/home/linuxadmin/homelabservices/gitlab/logs:/var/log/gitlab'
    container_name: gitlab
   

  gitlab-runner:
    image: gitlab/gitlab-runner:latest
    restart: always
    networks:
      - nginxproxy
    volumes:
      - '/home/linuxadmin/homelabservices/gitlab-runner/config:/etc/gitlab-runner'
      - '/var/run/docker.sock:/var/run/docker.sock'
    container_name: gitlab_runner

networks:
  nginxproxy:
    external: true

3. phpIPAM

Another docker container stack that I think is excellent, especially for home lab environments is phpIPAM. With phpIPAM you can have a solution to kee track of ip addressing in your environment. With phpIPAM you can continuously scan your network for new IP addresses and discover hosts and addresses in the environment

Phpipam
Phpipam
version: '3.8'
services:
  phpipam-web:
    image: phpipam/phpipam-www:latest
    ports:
      - "8100:80"
    environment:
      - TZ=America/Chicago
      - IPAM_DATABASE_HOST=phpipam-mariadb
      - IPAM_DATABASE_PASS=password
      - IPAM_DATABASE_WEBHOST=%
      - IPAM_TRUST_X_FORWARDED=true
    restart: always
    volumes:
      - "/home/linuxadmin/homelabservices/phpipam/phpipam-logo:/phpipam/css/images/logo"
      - "/home/linuxadmin/homelabservices/phpipam/phpipam-ca:/usr/local/share/ca-certificates:ro"
    networks:
      - nginxproxy
    depends_on:
      - phpipam-mariadb
    container_name: phpipam-web

  phpipam-cron:
    image: phpipam/phpipam-cron:latest
    environment:
      - TZ=America/Chicago
      - IPAM_DATABASE_HOST=phpipam-mariadb
      - IPAM_DATABASE_PASS=password
      - SCAN_INTERVAL=1h
    restart: always
    volumes:
      - "/home/linuxadmin/homelabservices/phpipam/phpipam-ca:/usr/local/share/ca-certificates:ro"
    networks:
      - nginxproxy
    depends_on:
      - phpipam-mariadb
    command: |
      sh -c "echo '*/15 * * * * /usr/bin/php /phpipam/functions/scripts/pingCheck.php' >> /etc/crontabs/root &&
             echo '*/15 * * * * /usr/bin/php /phpipam/functions/scripts/discoveryCheck.php' >> /etc/crontabs/root &&
             crond -f" 
    container_name: phpipam-cron

  phpipam-mariadb:
    image: mariadb:latest
    environment:
      - MYSQL_ROOT_PASSWORD=password
    restart: always
    volumes:
      - "/home/linuxadmin/homelabservices/phpipam/phpipam-db-data:/var/lib/mysql"
    networks:
      - nginxproxy
    container_name: phpipam-mariadb

networks:
  nginxproxy:
    external: true

4. Watchtower

The Watchtower docker container stack is a great way to keep your containers updated across the board. When you run Watchtower, it watches all the other containers and makes sure these stay updated if there is a new container image released. Also, Watchtower will notify the appropriate parties if there is an update that is processed for a container image.

version: '3.8'
services:
  watchtower:
    image: containrrr/watchtower
    container_name: watchtower
    restart: always
    networks:
      - nginxproxy
    environment:
      WATCHTOWER_SCHEDULE: "0 0 1 * * *"
      TZ: America/Chicago
      WATCHTOWER_CLEANUP: "true"
      WATCHTOWER_DEBUG: "true"
      WATCHTOWER_NOTIFICATIONS: "email"
      WATCHTOWER_NOTIFICATION_EMAIL_FROM: "[email protected]"
      WATCHTOWER_NOTIFICATION_EMAIL_TO: "[email protected]"
      # you have to use a network alias here, if you use your own certificate
      WATCHTOWER_NOTIFICATION_EMAIL_SERVER: "10.1.149.19"
      WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT: "8025"
      WATCHTOWER_NOTIFICATION_EMAIL_DELAY: 2
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

networks:
  nginxproxy:
    external: true

5. Container monitoring stack

The container monitoring stack is a great way to keep a check on your containers and their performance, health, and other metrics. This includes prometheus, cadvisor, and node exporter.

services:
  prometheus:
    image: portainer/template-swarm-monitoring:prometheus-v2.44.0
    user: "1001"
    environment: 
      - PUID=1001
      - PGID=1001
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--log.level=error'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=7d'
    volumes:
      - /mnt/cephfs/prometheus:/prometheus
      - /mnt/cephfs/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    networks:
      - nginxproxy
    restart: unless-stopped

  cadvisor:
    image: gcr.io/cadvisor/cadvisor:v0.47.0
    command: -logtostderr -docker_only
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker:/var/lib/docker:ro
      - /dev/disk:/dev/disk:ro
    networks:
      - nginxproxy
    restart: unless-stopped

  node-exporter:
    image: prom/node-exporter:v1.5.0
    command:
      - '--path.sysfs=/host/sys'
      - '--path.procfs=/host/proc'
      - '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'
      - '--no-collector.ipvs'
    volumes:
      - /:/rootfs:ro
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
    networks:
      - nginxproxy
    restart: unless-stopped

networks:
  nginxproxy:
    external: true

6. TICK Stack container stack

TICK stack represents Telegraph, InfluxDB, Chronograf, and Kapacitor containers. This is a great stack of containers also for monitoring that can be used and is quite popular for this use case.

version: '3.8'

services:
  grafana:
    image: grafana/grafana
    ports:
      - 3000:3000
    environment:
      - GF_PANELS_DISABLE_SANITIZE_HTML=true
    networks:
      - nginxproxy
    volumes:
      - /mnt/cephfs/grafana/grafana-volume:/var/lib/grafana
    restart: unless-stopped

  influxdb:
    image: influxdb:latest
    ports:
      - 8086:8086
      - 8089:8089/udp
    networks:
      - nginxproxy
    volumes:
      - /mnt/cephfs/influxdb/influxdb-volume:/var/lib/influxdb2
    restart: unless-stopped

  chronograf:
    user: "1000"
    image: chronograf:latest
    hostname: chronograf
    ports:
      - 8888:8888
    networks:
      - nginxproxy
    volumes:
      - /mnt/cephfs/chronograf/chronograf-data:/var/lib/chronograf
    restart: unless-stopped

  telegraf:
    image: telegraf:latest
    hostname: telegraf
    networks:
      - nginxproxy
    volumes:
      - /mnt/cephfs/telegraf/etc/telegraf.conf:/etc/telegraf/telegraf.conf
    restart: unless-stopped

  kapacitor:
    user: "1000"
    image: kapacitor:latest
    hostname: kapacitor
    networks:
      - nginxproxy
    volumes:
      - /mnt/cephfs/kapacitor/kapacitor-data:/var/lib/kapacitor
      - /mnt/cephfs/kapacitor/kapacitor-data/etc/kapacitor.conf:/etc/kapacitor/kapacitor.conf
    restart: unless-stopped

networks:
  nginxproxy:
    external: true

7. Gitea

In addition to using GitLab, I have been testing Gitea as well and it looks like it is a great solution. I still prefer GitLab at the moment as I continue to learn the ins and out of Gitea, but it is a great solution that allows you to self-host a code repository and now Gitea also has Gitea actions that provides CI/CD capabilities.

Gitea
Gitea
version: "3.8"

services:
  gitea:
    image: gitea/gitea:latest
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__database__DB_TYPE=mysql
      - GITEA__database__HOST=gitea-db:3306
      - GITEA__database__NAME=gitea
      - GITEA__database__USER=gitea
      - GITEA__database__PASSWD=gitea
      - GITEA__security__INSTALL_LOCK=true
      - GITEA__security__SECRET_KEY=342bc7e3db20204ec9af2bb4ecbfa26688ad96d85fd82494e173b99b38fa2cf3
      - GITEA__service__DISABLE_REGISTRATION=true
      - GITEA__admin__USERNAME=admin
      - GITEA__admin__PASSWORD=password
      - [email protected]
      - GITEA__mailer__ENABLED=true
      - GITEA__mailer__SMTP_ADDR=10.1.149.19:8025
      - [email protected]
      - GITEA__mailer__PROTOCOL=mail
      - GITEA__security__ALLOWED_DOMAINS=gitea.mydomain.com
      - GITEA__security__ALLOW_LOCALNETWORKS=true
    networks:
      - nginxproxy
    volumes:
      - /mnt/cephfs/gitea/data:/data
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure

  gitea-db:
    image: mysql:8
    environment:
      - MYSQL_ROOT_PASSWORD=gitea
      - MYSQL_USER=gitea
      - MYSQL_PASSWORD=gitea
      - MYSQL_DATABASE=gitea
    networks:
      - nginxproxy
    volumes:
      - /mnt/cephfs/gitea-db/mysql-data:/var/lib/mysql
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s           # Interval between health checks
      timeout: 5s             # Timeout for each health check attempt
      retries: 5              # Number of retries before marking as unhealthy
      start_period: 30s       # Initial delay before starting health checks

  gitea-runner:
    image: gitea/act_runner:nightly
    environment:
      CONFIG_FILE: /config.yaml
      GITEA_INSTANCE_URL: "gitea.mydomain.com}"
      GITEA_RUNNER_REGISTRATION_TOKEN: "password"
      GITEA_RUNNER_NAME: "gitearunnerdkr01"
      GITEA_RUNNER_LABELS: "docker"
    volumes:
      - /mnt/cephfs/gitea-runner/config.yaml:/config.yaml
      - /mnt/cephfs/gitea-runner/cache:/cache
      - /mnt/cephfs/gitea-runner/data:/data
      - /var/run/docker.sock:/var/run/docker.sock

networks:
  nginxproxy:
    external: true

8. Hashicorp Vault

Another great docker stack solution to mention is Hashicorp Vault. I use Vault with my Packer builds, terraform, and other use cases to securely store secrets in the environment. Using Vault, you can have a secure location for your secrets that can be dynamically pulled during CI/CD operations and other infrastructure automation.

Hashicorp vault
Hashicorp vault
version: "3.8"

services:
  vault:
    image: hashicorp/vault:latest
    volumes:
      - /mnt/cephfs/vault/config:/vault/config
      - /mnt/cephfs/vault/data:/vault/file
    networks:
      - nginxproxy
    cap_add:
      - IPC_LOCK
    command: "vault server -config=/vault/config/vault-config.json"
    restart: unless-stopped

networks:
  nnginxproxy:
    external: true

9. Pi-Hole

If you are looking for a great all-in-one DNS solution that also has good security features, ad-blocking, and malware protection, Pi-Hole is a good place to start. I use it on my “family” side of the network as an additional protection against malware, etc.

Pihole
Pihole
version: '3.8'

services:
  pihole:
    image: pihole/pihole:latest
    ports:
      - "53:53/tcp"
      - "53:53/udp"
    dns:
      - 127.0.0.1
      - 1.1.1.1
    environment:
      TZ: 'America/Chicago'
      WEBPASSWORD: 'password'
      PIHOLE_DNS_: 1.1.1.1;9.9.9.9
      DNSSEC: 'false'
      VIRTUAL_HOST: pihole01.mydomain.com
      WEBTHEME: default-dark
      PIHOLE_DOMAIN: lan
    volumes:
      - /mnt/cephfs/pihole/pihole:/etc/pihole
      - /mnt/cephfs/pihole/dnsmasq.d:/etc/dnsmasq.d
    deploy:
      restart_policy:
        condition: any
        delay: 5s
        max_attempts: 3
    networks:
      - nginxproxy

networks:
  nginxproxy:
    external: true

10. Unifi network application

I imagine a lot of you are running Unifi in your network. You can easily self-host a docker stack for running your Unifi network application/controller in the environment. This allows you to self-host the controller in your network.

Unifi network application
Unifi network application
version: '3.8'

services:
  unifi:
    image: jacobalberty/unifi:latest
    restart: always
    networks:
      - nginxproxy
    volumes:
      - /mnt/cephfs/unifi/data/lib:/var/lib/unifi
      - /mnt/cephfs/unifi/data/log:/var/log/unifi
      - /mnt/cephfs/unifi/data/run:/var/run/unifi
    ports:
      - '3478:3478/udp'
      - '10001:10001/udp'
      - '6789:6789/tcp'
      - '8080:8080/tcp'
      - '8880:8880/tcp'
      - '8843:8843/tcp'
    environment:
      - TZ=America/Chicago

networks:
  nginxproxy:
    external: true

Wrapping up

Are these the only docker stacks you can deploy, of course not! But these are just 10 of the most handy docker stacks that I am using and working with in my home lab environment and that provide critical services for my needs in the environment. Check them out and see if these are ones that you can take advantage of as well. Let me know other solutions you might be using as well.

Subscribe to VirtualizationHowto via Email ๐Ÿ””

Enter your email address to subscribe to this blog and receive notifications of new posts by email.



Brandon Lee

Brandon Lee is the Senior Writer, Engineer and owner at Virtualizationhowto.com, and a 7-time VMware vExpert, with over two decades of experience in Information Technology. Having worked for numerous Fortune 500 companies as well as in various industries, He has extensive experience in various IT segments and is a strong advocate for open source technologies. Brandon holds many industry certifications, loves the outdoors and spending time with family. Also, he goes through the effort of testing and troubleshooting issues, so you don't have to.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.