Free tech learning for everyone, from basics to pro

Automation ProjectsProgramming and Application SecurityIntermediate

Project: automated network config backups to Git

In short: This project pulls running configurations from your lab devices over SSH and commits them to a Git repository every night. Git keeps every version, so you can see exactly what changed, when, and roll back if needed. It is a small, safe, read-only project that shows real automation value.

Goal and what you will build

Configuration backups are the first thing most teams automate, because they are read-only, useful from day one and easy to explain to a manager. In this project you will build a Python script that connects to each device in an inventory, collects the running configuration, saves it as a text file and commits the result to a Git repository. Run nightly, it gives you a full history of every change on every device.

You need: Python 3, Git, and two or three lab devices (physical, or virtual images in a simulator such as GNS3, EVE-NG or Cisco Modeling Labs). Use only equipment you own or are authorised to manage, and a read-only or backup-only account on each device.

Config backup pipelineInventorydevices.yamlConnectSSH viaNetmikoCollectshowrunning-configCleanstrip changinglinesCommitgit add +commitReportwhat changed
Figure 1. The script reads an inventory, pulls each configuration, cleans it and commits it, so Git records every change.
Copy to share vs Git backupsCopy to a shareFiles overwrittenNo change historyHard to compareSilent failuresGit repositoryEvery version keptgit diff shows changesWho and when recordedEasy restore
Figure 2. Storing configurations in Git turns a simple backup into a full change history you can search and compare.

Design

  • Inventory in YAML: hostname, management IP and Netmiko device type for each device. No passwords in this file.
  • Credentials from environment variables (or a secrets manager), never in the script or repository.
  • Clean-up: some lines change on every run, such as timestamps or ntp clock-period. Removing them stops false "changes".
  • Git: one file per device, one commit per run, with a clear message. Push to a private remote if you have one.
  • Error handling: one unreachable device must not stop the rest; failures are listed at the end.
# devices.yaml
- name: core-sw1
  host: 192.168.10.2
  device_type: cisco_ios
- name: edge-rtr1
  host: 192.168.10.1
  device_type: cisco_ios
- name: lab-fw1
  host: 192.168.10.254
  device_type: fortinet

Build it step by step

  1. Create a project folder with a virtual environment and run pip install netmiko pyyaml.
  2. Create a configs folder and run git init inside it. Configurations contain sensitive data such as password hashes and SNMP communities, so keep this repository private and access-controlled.
  3. Export credentials in your shell or service account: NET_USER and NET_PASS.
  4. Write the script below and run it by hand. Check the files and the Git log.
  5. Change a description on one lab device, run again and use git diff HEAD~1 to see the change.
  6. Schedule it with cron or a systemd timer.
#!/usr/bin/env python3
"""Back up device configs to a Git repository."""
import os, re, subprocess, datetime
from pathlib import Path
import yaml
from netmiko import ConnectHandler

REPO = Path("configs")
COMMANDS = {"cisco_ios": "show running-config", "fortinet": "show full-configuration"}
NOISE = re.compile(r"^(! Last configuration change|! NVRAM config last updated|ntp clock-period)")

def clean(text):
    return "\n".join(l for l in text.splitlines() if not NOISE.match(l)) + "\n"

def backup(dev):
    params = {"device_type": dev["device_type"], "host": dev["host"],
              "username": os.environ["NET_USER"], "password": os.environ["NET_PASS"]}
    with ConnectHandler(**params) as conn:
        out = conn.send_command(COMMANDS[dev["device_type"]], read_timeout=60)
    (REPO / f"{dev['name']}.cfg").write_text(clean(out), encoding="utf-8")

def main():
    devices = yaml.safe_load(open("devices.yaml", encoding="utf-8"))
    failed = []
    for dev in devices:
        try:
            backup(dev)
            print("OK  ", dev["name"])
        except Exception as e:                     # keep going on errors
            failed.append(dev["name"])
            print("FAIL", dev["name"], type(e).__name__)
    subprocess.run(["git", "-C", str(REPO), "add", "-A"], check=True)
    stamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
    subprocess.run(["git", "-C", str(REPO), "commit", "-q", "-m",
                    f"Backup {stamp} ({len(failed)} failed)"], check=False)
    if failed:
        print("Failed:", ", ".join(failed))

if __name__ == "__main__":
    main()
# crontab -e : run at 01:30 every night
30 1 * * * cd /opt/netbackup && . .venv/bin/activate && ./backup.py >> backup.log 2>&1

Tip: git commit exits with an error when nothing changed, which is why the script uses check=False there. No commit simply means no device was changed.

How to extend it

  • Run devices in parallel with Nornir or a thread pool to back up hundreds of devices quickly.
  • Send an email or chat message when a configuration changes, including the git diff.
  • Load the inventory from your source of truth instead of a YAML file.
  • Mask secrets such as SNMP communities before committing, if the repository is shared more widely.
  • Add a compliance check that runs on each new commit, linking this project to drift detection.

Showing it in your portfolio

Publish the code (never the real configurations or inventory) on GitHub with a README that explains the problem, the design diagram, how to install it and an example of the output. Include sample, sanitised configuration files and a screenshot or text excerpt of a git log and git diff showing a change being caught. In an interview, explain why you chose Git, how you protect credentials, and how the script copes with a device that is down. That story shows you think about operations, not just code.

Practice

Why remove lines such as "! Last configuration change" before committing?
They change on every run or every save, so Git would record a change each night even when nothing meaningful changed, hiding real changes in noise.
Where should the device password come from in this project?
From environment variables, a protected service account or a secrets manager, never from the script, inventory file or Git repository.
How would you see what changed on core-sw1 between yesterday and today?
Run git log on configs/core-sw1.cfg to find the commits, then git diff between them (for example git diff HEAD~1 -- core-sw1.cfg).

Key takeaways

  • Config backup is a safe, read-only first automation project.
  • Git keeps every version and shows exactly what changed and when.
  • Strip lines that change on every run to avoid false changes.
  • Keep credentials out of code; keep the config repository private.
  • Handle failures per device and schedule the job with cron or a timer.
Tracks your learning on this device only. See your progress on the learning paths.

About the author

Mohamed Fayas

Founder of FM TecHub. CCNA certified, with a BTEC HND in Network Engineering, and BEng (Hons) in Computer Networking and Cloud Security. He writes practical, plain-English guides on networking, security and cloud.

More about the author

Original content written by Mohamed Fayas for FM TecHub. © 2026 FM TecHub. You're welcome to share a link to this page; please don't copy the text elsewhere without permission.

Stay up to date by email

New notes, tools and security news from FM TecHub, explained simply. Free.

We only use your email to send these updates. See our privacy policy.