Automated backup tool for Pi-hole v6+. It uses the Pi-hole Teleporter API to export your configuration and uploads the backup archive to S3-compatible object storage or Azure Blob Storage on a cron schedule.
Built with .NET 10, packaged as a lightweight Docker container for linux/amd64 and linux/arm64.
- Scheduled backups using standard cron expressions
- One-shot mode (run once, no schedule) when
BACKUP_CRONis omitted - Supports multiple storage providers:
- AWS S3
- Linode Object Storage
- Garage (self-hosted S3-compatible)
- Azure Blob Storage
- Multi-architecture Docker image (
amd64/arm64)
Copy the example and fill in your values:
cp .env.example .envUsing the pre-built image from GitHub Container Registry:
# compose.yml
services:
pihole-backup:
container_name: pihole-backup
image: ghcr.io/solairen/pihole-backup:latest
env_file: .envdocker compose up -dThe image is also available on Docker Hub:
moleszek/pihole-backup:latest
All configuration is done through environment variables. Create a .env file based on .env.example.
| Variable | Description |
|---|---|
PROVIDER |
Storage provider: AWS, Linode, Garage, or Azure |
PIHOLE_URL |
Full URL to your Pi-hole instance (e.g. https://pihole.local) |
PIHOLE_PASSWORD |
Pi-hole admin password |
| Variable | Default | Description |
|---|---|---|
BACKUP_CRON |
(none) | Cron expression for backup schedule (e.g. */2 * * * *). If omitted, runs once and exits |
LOG_LEVEL |
Information |
Serilog log level: Verbose, Debug, Information, Warning, Error, Fatal |
| Variable | Default | Description |
|---|---|---|
S3_ACCESS_KEY |
required | S3 access key |
S3_SECRET_KEY |
required | S3 secret key |
S3_BUCKET |
required | Target bucket name |
S3_REGION |
eu-central-1 |
AWS region |
S3_ENDPOINT |
https://s3.<region>.amazonaws.com |
Custom endpoint. Required for Garage and Linode |
Endpoint examples:
- AWS -- leave
S3_ENDPOINTempty; it is derived fromS3_REGION - Linode --
https://eu-central-1.linodeobjects.com - Garage --
http://<garage-host>:3900
| Variable | Description |
|---|---|
AZURE_TENANT_ID |
Azure AD tenant ID |
AZURE_CLIENT_ID |
Service principal client ID |
AZURE_CLIENT_SECRET |
Service principal client secret |
AZURE_STORAGE_ACCOUNT |
Storage account name |
AZURE_CONTAINER |
Blob container name |
- .NET 10 SDK
- Docker (for container builds)
dotnet restore src/pihole-backup/pihole-backup.csproj
dotnet build src/pihole-backup/pihole-backup.csproj -c Release# Export required environment variables first (see Configuration above)
dotnet run --project src/pihole-backup/pihole-backup.csprojdocker compose -f compose.build.yml buildOr directly with Docker:
docker build -f docker/Dockerfile -t pihole-backup:local .Pass a custom version number at build time:
docker build -f docker/Dockerfile --build-arg app_version=1.2.0 -t pihole-backup:1.2.0 ..
├── docker/
│ ├── Dockerfile # Production multi-stage build
│ └── Dockerfile-dev # Development container
├── src/pihole-backup/
│ ├── Config/
│ │ └── AppConfig.cs # Environment variable bindings
│ ├── Helpers/
│ │ └── ValidateConfig.cs # Startup configuration validation
│ ├── Models/
│ │ ├── AzureBlobOptions.cs
│ │ └── S3Options.cs
│ ├── Providers/
│ │ └── Providers.cs # Provider enum (AWS, Linode, Garage, Azure)
│ ├── Services/
│ │ ├── AWSS3Service.cs # S3-compatible upload
│ │ ├── AzureBlobStorageService.cs # Azure Blob upload
│ │ ├── IStorageService.cs # Storage interface
│ │ └── PiHoleService.cs # Pi-hole Teleporter API client
│ ├── Program.cs # Entry point and cron scheduler
│ └── pihole-backup.csproj
├── .devcontainer/ # VS Code Dev Container configuration
├── .github/
│ └── workflows/
│ ├── push-image.yml # Build and push on milestone close
│ └── test-docker.yml # Build test on pull requests
├── compose.yml # Run with pre-built image
├── compose.build.yml # Build image locally
├── .env.example # Environment variable template
├── global.json # .NET SDK version pin
├── CONTRIBUTING.md
├── CODE_OF_CONDUCT.md
├── CHANGELOG.md
└── LICENSE # GPL-3.0
- The application authenticates against the Pi-hole v6 API (
/api/auth) using the configured password - It requests a Teleporter export (
/api/teleporter) which returns a.tar.gzarchive of the Pi-hole configuration - The archive is uploaded to the configured storage provider under the
pihole/prefix with a timestamped filename (e.g.pihole/teleporter-2025-01-15_14-30.tar.gz) - The local file is deleted after a successful upload
- If a cron expression is set, the process repeats on schedule; otherwise it exits after a single run
The project includes a Dev Container configuration for VS Code. Open the project in VS Code and select Reopen in Container to get a fully configured development environment with:
- .NET 10 SDK
- Pre-commit hooks
- Hadolint (Dockerfile linter)
The project uses pre-commit for code quality checks. Install the hooks after cloning:
pip install pre-commit
pre-commit install- Pull requests trigger a Docker build test across
amd64andarm64platforms (no push) - Milestone close triggers a production build, pushes to both GitHub Container Registry and Docker Hub, and creates a GitHub Release with auto-generated release notes
See CONTRIBUTING.md for guidelines on reporting bugs, suggesting features, and submitting pull requests.
This project is licensed under the GNU General Public License v3.0.