This guide provides Ansible playbooks to deploy m1/netcheck (Rust variant with Prometheus metrics) on Debian 10+, Ubuntu 20.04+, and RHEL 9+ compatible systems.
| Aspect | Details |
|---|---|
| Project | m1/netcheck |
| Supported OS | Debian 10+, Ubuntu 20.04+, RHEL 9+, AlmaLinux, Rocky Linux |
| Deployment | Docker Compose with security hardening |
| Automation | Full stack: Docker, netcheck, optional Prometheus/Grafana |
| Security | Non-root container, capability drops, resource limits, firewall |
Create inventory.yml:
all:
vars:
ansible_user: admin
ansible_ssh_private_key_file: ~/.ssh/id_ed25519
ansible_python_interpreter: /usr/bin/python3
children:
netcheck_servers:
hosts:
netcheck-prod-01:
ansible_host: 192.168.1.100
netcheck_domain: netcheck.example.com
netcheck-prod-02:
ansible_host: 192.168.1.101
netcheck_domain: netcheck2.example.com
Create playbooks/netcheck.yml:
---
- name: Deploy Netcheck Network Monitor
hosts: netcheck_servers
become: true
gather_facts: true
vars:
# Application settings
app_name: netcheck
app_root: /opt/netcheck
app_port: 8080
app_user: netcheck
app_group: netcheck
# Docker settings
docker_image: "ghcr.io/m1/netcheck:latest"
docker_container_name: netcheck
docker_network_name: netcheck_monitoring
# Monitoring targets
netcheck_targets:
- "external=https://one.one.one.one,https://dns.google"
- "internal=http://kubernetes.default.svc.cluster.local:443"
# Timing configuration
netcheck_timeout: "5s"
netcheck_connect_timeout: "3s"
netcheck_failure_threshold: "3"
netcheck_wait_time: "10s"
# Security settings
firewall_enabled: true
firewall_allowed_tcp_ports:
- 22 # SSH
# - 80 # HTTP (if using reverse proxy)
# - 443 # HTTPS (if using reverse proxy)
# Resource limits
resource_limits_cpu: "0.5"
resource_limits_memory: "64M"
# Optional: Prometheus stack
deploy_prometheus: false
deploy_grafana: false
tasks:
# ==========================================
# System Preparation
# ==========================================
- name: Install prerequisites
ansible.builtin.package:
name:
- apt-transport-https
- ca-certificates
- curl
- gnupg
- lsb-release
- git
state: present
when: ansible_os_family == "Debian"
- name: Install prerequisites (RHEL)
ansible.builtin.package:
name:
- curl
- git
- yum-utils
state: present
when: ansible_os_family == "RedHat"
# ==========================================
# Docker Installation
# ==========================================
- name: Add Docker GPG key (Debian/Ubuntu)
ansible.builtin.apt_key:
url: https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg
state: present
when: ansible_os_family == "Debian"
- name: Add Docker repository (Debian/Ubuntu)
ansible.builtin.apt_repository:
repo: "deb [arch=amd64] https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable"
state: present
filename: docker
when: ansible_os_family == "Debian"
- name: Add Docker repository (RHEL)
ansible.builtin.yum_repository:
name: docker-ce
description: Docker CE Repository
baseurl: "https://download.docker.com/linux/centos/{{ ansible_distribution_major_version }}/$basearch/stable"
gpgkey: https://download.docker.com/linux/centos/gpg
gpgcheck: true
when: ansible_os_family == "RedHat"
- name: Install Docker packages
ansible.builtin.package:
name:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-compose-plugin
state: present
notify: Restart Docker
- name: Enable and start Docker
ansible.builtin.service:
name: docker
state: started
enabled: true
- name: Create application user
ansible.builtin.user:
name: "{{ app_user }}"
group: "{{ app_group }}"
system: true
create_home: false
shell: /usr/sbin/nologin
# ==========================================
# Directory Structure
# ==========================================
- name: Create application directory
ansible.builtin.file:
path: "{{ app_root }}"
state: directory
owner: "{{ app_user }}"
group: "{{ app_group }}"
mode: "0755"
- name: Create Docker Compose directory
ansible.builtin.file:
path: "{{ app_root }}/docker"
state: directory
owner: "{{ app_user }}"
group: "{{ app_group }}"
mode: "0755"
# ==========================================
# Docker Compose Configuration
# ==========================================
- name: Deploy Docker Compose file
ansible.builtin.template:
src: templates/docker-compose.yml.j2
dest: "{{ app_root }}/docker/docker-compose.yml"
owner: "{{ app_user }}"
group: "{{ app_group }}"
mode: "0644"
notify: Restart Netcheck
# ==========================================
# Firewall Configuration
# ==========================================
- name: Install UFW (Debian/Ubuntu)
ansible.builtin.package:
name: ufw
state: present
when:
- firewall_enabled
- ansible_os_family == "Debian"
- name: Configure UFW
ansible.builtin.command:
cmd: "ufw {{ item }}"
loop:
- default deny incoming
- default allow outgoing
- allow ssh
when:
- firewall_enabled
- ansible_os_family == "Debian"
notify: Restart UFW
- name: Enable UFW
ansible.builtin.command:
cmd: ufw --force enable
when:
- firewall_enabled
- ansible_os_family == "Debian"
notify: Restart UFW
# ==========================================
# Systemd Service (for Docker Compose)
# ==========================================
- name: Create systemd service for Docker Compose
ansible.builtin.template:
src: templates/netcheck.service.j2
dest: /etc/systemd/system/netcheck.service
mode: "0644"
notify:
- Reload systemd
- Restart Netcheck
- name: Enable and start Netcheck service
ansible.builtin.service:
name: netcheck
state: started
enabled: true
# ==========================================
# Verification
# ==========================================
- name: Wait for Netcheck to be ready
ansible.builtin.wait_for:
port: "{{ app_port }}"
host: 127.0.0.1
timeout: 30
register: netcheck_ready
retries: 5
delay: 5
- name: Verify Netcheck metrics endpoint
ansible.builtin.uri:
url: "http://127.0.0.1:{{ app_port }}/metrics"
method: GET
status_code: 200
register: metrics_check
failed_when: metrics_check.status != 200
- name: Display Netcheck status
ansible.builtin.debug:
msg: |
Netcheck deployed successfully!
Metrics endpoint: http://{{ ansible_host }}:{{ app_port }}/metrics
Container: {{ docker_container_name }}
handlers:
- name: Restart Docker
ansible.builtin.service:
name: docker
state: restarted
- name: Reload systemd
ansible.builtin.systemd:
daemon_reload: true
- name: Restart Netcheck
ansible.builtin.command:
cmd: docker compose -f {{ app_root }}/docker/docker-compose.yml up -d --force-recreate
args:
chdir: "{{ app_root }}/docker"
- name: Restart UFW
ansible.builtin.service:
name: ufw
state: restarted
templates/docker-compose.yml.j2version: "3.8"
services:
netcheck:
image: {{ docker_image }}
container_name: {{ docker_container_name }}
restart: unless-stopped
ports:
- "127.0.0.1:{{ app_port }}:8080"
command:
- run
- --target
- "{{ netcheck_targets | join(',') }}"
- --timeout
- "{{ netcheck_timeout }}"
- --connect-timeout
- "{{ netcheck_connect_timeout }}"
- --failure-threshold
- "{{ netcheck_failure_threshold }}"
- --wait-time
- "{{ netcheck_wait_time }}"
# Security hardening
user: "1000:1000"
read_only: true
tmpfs:
- /tmp:noexec,nosuid,size=64m
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
# Resource limits
deploy:
resources:
limits:
cpus: '{{ resource_limits_cpu }}'
memory: {{ resource_limits_memory }}
reservations:
cpus: '0.1'
memory: 16M
# Health check
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/metrics"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
# Logging
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
- {{ docker_network_name }}
networks:
{{ docker_network_name }}:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/16
templates/netcheck.service.j2[Unit]
Description=Netcheck Network Monitor
Documentation=https://github.com/m1/netcheck
After=network.target docker.service
Requires=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory={{ app_root }}/docker
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
ExecReload=/usr/bin/docker compose up -d --force-recreate
[Install]
WantedBy=multi-user.target
# Syntax check
ansible-playbook -i inventory.yml playbooks/netcheck.yml --check
# Deploy
ansible-playbook -i inventory.yml playbooks/netcheck.yml
# Deploy with specific tags
ansible-playbook -i inventory.yml playbooks/netcheck.yml --tags "docker,netcheck"
# SSH to target server
ssh admin@192.168.1.100
# Check container status
docker ps -a --filter name=netcheck
# View metrics
curl http://localhost:8080/metrics
# Check logs
docker logs netcheck
Add to playbook vars:
deploy_prometheus: true
deploy_grafana: true
prometheus_retention: "15d"
grafana_admin_password: "change-me-strong-password"
grafana_domain: "grafana.example.com"
Add to docker-compose.yml.j2:
environment:
- ALERTMANAGER_URL=http://alertmanager:9093/api/v1/alerts
depends_on:
- alertmanager
netcheck_targets:
- "external=https://one.one.one.one,https://dns.google,https://api.github.com"
- "internal=http://kubernetes.default.svc.cluster.local:443"
- "database=postgres://db.example.com:5432"
Add to playbook:
- name: Apply sysctl hardening
ansible.posix.sysctl:
name: "{{ item.name }}"
value: "{{ item.value }}"
state: present
reload: true
loop:
- { name: 'net.ipv4.tcp_syncookies', value: '1' }
- { name: 'net.ipv4.conf.all.rp_filter', value: '1' }
- { name: 'net.ipv4.conf.default.rp_filter', value: '1' }
- { name: 'net.ipv4.conf.all.accept_redirects', value: '0' }
- { name: 'net.ipv4.conf.default.accept_redirects', value: '0' }
- name: Install and configure Fail2ban
ansible.builtin.package:
name: fail2ban
state: present
- name: Create Fail2ban jail for Netcheck
ansible.builtin.template:
src: templates/jail-netcheck.conf.j2
dest: /etc/fail2ban/jail.d/netcheck.conf
mode: "0644"
notify: Restart Fail2ban
- name: Backup Netcheck configuration
hosts: netcheck_servers
become: true
tasks:
- name: Create backup directory
ansible.builtin.file:
path: /var/backups/netcheck
state: directory
mode: "0700"
- name: Backup Docker Compose file
ansible.builtin.copy:
src: "{{ app_root }}/docker/docker-compose.yml"
dest: "/var/backups/netcheck/docker-compose-{{ ansible_date_time.date }}.yml"
remote_src: true
| Issue | Solution |
|---|---|
| Docker not starting | Check Docker service: systemctl status docker |
| Container exits | View logs: docker logs netcheck |
| Firewall blocking | Verify UFW/firewalld rules |
| Metrics not visible | Check port binding in Compose file |
| Ansible connection fails | Verify SSH key and sudo access |
Any questions?
Feel free to contact us. Find all contact information on our contact page.