https://github.com/solairen/pihole-backup
Backup PiHole and send it to S3 compatible storage object or Azure Blob Object
https://github.com/solairen/pihole-backup
azure csharp pihole s3
Last synced: 3 months ago
JSON representation
Backup PiHole and send it to S3 compatible storage object or Azure Blob Object
- Host: GitHub
- URL: https://github.com/solairen/pihole-backup
- Owner: solairen
- License: gpl-3.0
- Created: 2026-03-22T19:09:17.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-04-08T07:44:17.000Z (3 months ago)
- Last Synced: 2026-04-08T09:31:13.963Z (3 months ago)
- Topics: azure, csharp, pihole, s3
- Language: C#
- Homepage:
- Size: 52.7 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# Pi-hole Backup
Automated backup tool for [Pi-hole](https://pi-hole.net/) 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`.
## Features
- Scheduled backups using standard cron expressions
- One-shot mode (run once, no schedule) when `BACKUP_CRON` is omitted
- Supports multiple storage providers:
- **AWS S3**
- **Linode Object Storage**
- **Garage** (self-hosted S3-compatible)
- **Azure Blob Storage**
- Multi-architecture Docker image (`amd64` / `arm64`)
## Quick Start
### 1. Create an environment file
Copy the example and fill in your values:
```sh
cp .env.example .env
```
### 2. Run with Docker Compose
Using the pre-built image from GitHub Container Registry:
```yaml
# compose.yml
services:
pihole-backup:
container_name: pihole-backup
image: ghcr.io/solairen/pihole-backup:latest
env_file: .env
```
```sh
docker compose up -d
```
The image is also available on Docker Hub:
```text
moleszek/pihole-backup:latest
```
## Configuration
All configuration is done through environment variables. Create a `.env` file based on [.env.example](.env.example).
### Required Variables
| 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 |
### Optional Variables
| 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` |
### S3 Provider Variables (AWS, Linode, Garage)
| 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..amazonaws.com` | Custom endpoint. Required for Garage and Linode |
**Endpoint examples:**
- **AWS** -- leave `S3_ENDPOINT` empty; it is derived from `S3_REGION`
- **Linode** -- `https://eu-central-1.linodeobjects.com`
- **Garage** -- `http://:3900`
### Azure Provider Variables
| 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 |
## Building from Source
### Prerequisites
- [.NET 10 SDK](https://dotnet.microsoft.com/download)
- Docker (for container builds)
### Build the Application
```sh
dotnet restore src/pihole-backup/pihole-backup.csproj
dotnet build src/pihole-backup/pihole-backup.csproj -c Release
```
### Run Locally
```sh
# Export required environment variables first (see Configuration above)
dotnet run --project src/pihole-backup/pihole-backup.csproj
```
### Build the Docker Image
```sh
docker compose -f compose.build.yml build
```
Or directly with Docker:
```sh
docker build -f docker/Dockerfile -t pihole-backup:local .
```
Pass a custom version number at build time:
```sh
docker build -f docker/Dockerfile --build-arg app_version=1.2.0 -t pihole-backup:1.2.0 .
```
## Project Structure
```text
.
├── 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
```
## How It Works
1. The application authenticates against the Pi-hole v6 API (`/api/auth`) using the configured password
2. It requests a Teleporter export (`/api/teleporter`) which returns a `.tar.gz` archive of the Pi-hole configuration
3. 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`)
4. The local file is deleted after a successful upload
5. If a cron expression is set, the process repeats on schedule; otherwise it exits after a single run
## Development
### Dev Container
The project includes a [Dev Container](.devcontainer/devcontainer.json) 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)
### Pre-commit Hooks
The project uses [pre-commit](https://pre-commit.com/) for code quality checks. Install the hooks after cloning:
```sh
pip install pre-commit
pre-commit install
```
## CI/CD
- **Pull requests** trigger a Docker build test across `amd64` and `arm64` platforms (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
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on reporting bugs, suggesting features, and submitting pull requests.
## License
This project is licensed under the [GNU General Public License v3.0](LICENSE).