Production-like monitoring stack deployed via Docker, automated with CI/CD, and integrated into a multi-VM network with NAT routing.
This project implements a centralized monitoring platform with:
- 📊 Metrics → Prometheus
- 📈 Visualization → Grafana
- 📜 Logs → Loki + Promtail
- 🚨 Alerts → Alertmanager
- 🌐 Reverse proxy → Nginx
- ⚙️ Automation → GitHub Actions + Ansible
- 🌍 Networking → NAT + nftables + jump host
[ Host PC ]
↓
[ routerVM (NAT + nftables) ]
↓
[ monitoringVM (Docker stack) ]
↓
┌──────────────────────────────┐
│ Docker Network │
│ │
│ Prometheus Grafana │
│ Alertmanager Loki │
│ Promtail Node Exporter │
│ Nginx (entrypoint) │
└──────────────────────────────┘
Client → routerVM (DNAT)
→ monitoringVM
→ nginx → services (grafana/prometheus/etc)
→ response via SNAT (masquerade)
- Docker / Docker Compose
- Prometheus
- Grafana
- Loki + Promtail
- Alertmanager
- Nginx
- Ansible
- GitHub Actions (CI/CD)
- nftables (NAT + firewall)
monitoring-deploy/
│
├── docker/
│ ├── docker-compose.yml
│ ├── nginx/
│ │ └── nginx.conf
│ ├── prometheus/
│ │ ├── prometheus.yml
│ │ └── alerts.yml
│ ├── alertmanager/
│ │ └── alertmanager.yml
│ ├── promtail/
│ │ └── promtail-config.yaml
│ └── loki/
│ └── local-config.yaml
│
├── ansible/
│ ├── inventory.ini
│ └── playbook.yml
│
├── .github/workflows/
│ └── deploy.yml
│
└── README.md
git clone https://github.com/YOUR_USERNAME/monitoring-deploy.git
cd monitoring-deploycd docker
docker-compose up -dPush changes:
git add .
git commit -m "deploy update"
git pushGitHub Actions will:
- SSH into monitoring VM
- Pull latest code
- Restart Docker stack
Depending on your setup:
http://<routerVM_IP>:3000 → Grafana
http://<routerVM_IP>:9090 → Prometheus
http://<routerVM_IP>:9093 → Alertmanager
http://<routerVM_IP>/grafana/
http://<routerVM_IP>/prometheus/
http://<routerVM_IP>/alertmanager/
GitHub Actions performs:
- SSH into monitoring VM
- Pull latest repo
- Stop old containers
- Deploy updated stack
bind: address already in use
Cause: Old services (systemd or Docker) still running.
Fix:
docker-compose down
docker rm -f $(docker ps -aq)container name "/grafana" is already in use
Cause: Manual container existed outside docker-compose.
Fix:
docker rm -f grafanaconfig.yaml is a directory
Cause:
Wrong file name (.yml vs .yaml)
Fix: Ensure correct file:
promtail-config.yaml
Everything worked on VM but not from host.
Cause: Broken NAT / firewall rules.
Cause: Interface-specific rule:
iif "enp1s0"
Traffic came from another interface.
Fix: Remove interface restriction:
dnat without iifiptables: No chain DOCKER
Cause: nftables restart wiped Docker rules
Fix:
systemctl restart dockerRequest reached container but response never returned.
Cause: Missing masquerade for external network.
Fix:
iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -j MASQUERADEdestination path already exists
Fix:
rm -rf ~/monitoring
git clone ...- Docker modifies system networking (iptables/nftables)
- NAT requires both DNAT and SNAT
- Interface-specific rules can silently break routing
- Always verify packet flow with tcpdump
- CI/CD must clean previous state
- HTTPS (Let's Encrypt)
- Reverse proxy routing (single domain)
- Alertmanager → Telegram integration
- Multi-node monitoring
- High availability setup
DevOps / Linux enthusiast focused on automation, infrastructure, and monitoring systems.