Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions backup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# NetBox Docker Backup Script

This script provides a simple and flexible backup solution for NetBox Docker deployments.

## Features

- NetBox media backup
- Reports backup
- PostgreSQL database backup
- Optional FTP upload
- Environment-based configuration

## Requirements

- Docker
- Python 3.8+
- NetBox Docker deployment

## Usage

```bash
cp backup.env.example backup.env
python3 backup.py
22 changes: 22 additions & 0 deletions backup/backup.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# --------------------------------------------------
# FTP
# --------------------------------------------------
FTP_SERVER=ftp.example.com
FTP_USER=username
FTP_PASSWORD=password
FTP_DIR=/

# --------------------------------------------------
# PostgreSQL (Docker)
# --------------------------------------------------
PG_USER=netbox
PG_PASSWORD=netbox
PG_DB=netbox
PG_CONTAINER=netbox-postgres

# --------------------------------------------------
# Paths (host-mounted volumes)
# --------------------------------------------------
BACKUP_DIR=/opt/netbox/backups
NETBOX_VOLUME=/opt/netbox/netbox/media
REPORTS_VOLUME=/opt/netbox/netbox/reports
119 changes: 119 additions & 0 deletions backup/backup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#!/usr/bin/env python3

import os
import tarfile
import subprocess
from ftplib import FTP
from dotenv import load_dotenv
from datetime import datetime
from pathlib import Path
import sys


# --------------------------------------------------
# Load environment variables
# --------------------------------------------------
ENV_FILE = os.getenv("BACKUP_ENV", "backup.env")
load_dotenv(ENV_FILE)


def required(var_name: str) -> str:
value = os.getenv(var_name)
if not value:
print(f"[ERROR] Missing required environment variable: {var_name}")
sys.exit(1)
return value


# --------------------------------------------------
# Required configuration
# --------------------------------------------------
FTP_SERVER = os.getenv("FTP_SERVER")
FTP_USER = os.getenv("FTP_USER")
FTP_PASSWORD = os.getenv("FTP_PASSWORD")
FTP_DIR = os.getenv("FTP_DIR", "/")

PG_USER = required("PG_USER")
PG_PASSWORD = required("PG_PASSWORD")
PG_DB = required("PG_DB")
PG_CONTAINER = required("PG_CONTAINER")

BACKUP_DIR = required("BACKUP_DIR")
NETBOX_VOLUME = required("NETBOX_VOLUME")
REPORTS_VOLUME = required("REPORTS_VOLUME")

# --------------------------------------------------
# Prepare paths & filenames
# --------------------------------------------------
DATE = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
Path(BACKUP_DIR).mkdir(parents=True, exist_ok=True)

NETBOX_BACKUP_FILE = f"{BACKUP_DIR}/netbox_media_{DATE}.tar.gz"
REPORTS_BACKUP_FILE = f"{BACKUP_DIR}/netbox_reports_{DATE}.tar.gz"
POSTGRES_BACKUP_FILE = f"{BACKUP_DIR}/postgres_{DATE}.sql.gz"


# --------------------------------------------------
# Helper functions
# --------------------------------------------------
def create_tar_gz(source: str, destination: str):
print(f"[INFO] Creating archive: {destination}")
with tarfile.open(destination, "w:gz") as tar:
tar.add(source, arcname=os.path.basename(source))


def backup_postgres():
print("[INFO] Backing up PostgreSQL database...")
command = (
f"docker exec {PG_CONTAINER} "
f"pg_dump -U {PG_USER} {PG_DB} | gzip"
)

with open(POSTGRES_BACKUP_FILE, "wb") as f:
subprocess.run(
command,
shell=True,
check=True,
env={**os.environ, "PGPASSWORD": PG_PASSWORD},
stdout=f,
)


def upload_to_ftp(local_file: str):
if not FTP_SERVER:
print("[INFO] FTP upload skipped (FTP_SERVER not set)")
return

print(f"[INFO] Uploading {os.path.basename(local_file)} to FTP...")
with FTP(FTP_SERVER) as ftp:
ftp.login(user=FTP_USER, passwd=FTP_PASSWORD)
ftp.cwd(FTP_DIR)
with open(local_file, "rb") as f:
ftp.storbinary(f"STOR {os.path.basename(local_file)}", f)


# --------------------------------------------------
# Main execution
# --------------------------------------------------
try:
print("[INFO] Starting NetBox backup process")

create_tar_gz(NETBOX_VOLUME, NETBOX_BACKUP_FILE)
create_tar_gz(REPORTS_VOLUME, REPORTS_BACKUP_FILE)
backup_postgres()

upload_to_ftp(NETBOX_BACKUP_FILE)
upload_to_ftp(REPORTS_BACKUP_FILE)
upload_to_ftp(POSTGRES_BACKUP_FILE)

print("[INFO] Backup completed successfully")

finally:
print("[INFO] Cleaning up local backup files")
for file in [
NETBOX_BACKUP_FILE,
REPORTS_BACKUP_FILE,
POSTGRES_BACKUP_FILE,
]:
if os.path.exists(file):
os.remove(file)