{"id":48770539,"url":"https://github.com/solairen/pihole-backup","last_synced_at":"2026-04-13T10:01:30.035Z","repository":{"id":349948184,"uuid":"1188925576","full_name":"solairen/pihole-backup","owner":"solairen","description":"Backup PiHole and send it to S3 compatible storage object or Azure Blob Object","archived":false,"fork":false,"pushed_at":"2026-04-08T07:44:17.000Z","size":54,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-08T09:31:13.963Z","etag":null,"topics":["azure","csharp","pihole","s3"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/solairen.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"buy_me_a_coffee":"solairen"}},"created_at":"2026-03-22T19:09:17.000Z","updated_at":"2026-04-08T07:44:21.000Z","dependencies_parsed_at":"2026-04-13T10:01:10.183Z","dependency_job_id":null,"html_url":"https://github.com/solairen/pihole-backup","commit_stats":null,"previous_names":["solairen/pihole-backup"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/solairen/pihole-backup","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solairen%2Fpihole-backup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solairen%2Fpihole-backup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solairen%2Fpihole-backup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solairen%2Fpihole-backup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/solairen","download_url":"https://codeload.github.com/solairen/pihole-backup/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solairen%2Fpihole-backup/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31747177,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T09:16:15.125Z","status":"ssl_error","status_checked_at":"2026-04-13T09:16:05.023Z","response_time":93,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azure","csharp","pihole","s3"],"created_at":"2026-04-13T10:00:50.835Z","updated_at":"2026-04-13T10:01:30.024Z","avatar_url":"https://github.com/solairen.png","language":"C#","funding_links":["https://buymeacoffee.com/solairen"],"categories":[],"sub_categories":[],"readme":"# Pi-hole Backup\n\nAutomated 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.\n\nBuilt with .NET 10, packaged as a lightweight Docker container for `linux/amd64` and `linux/arm64`.\n\n## Features\n\n- Scheduled backups using standard cron expressions\n- One-shot mode (run once, no schedule) when `BACKUP_CRON` is omitted\n- Supports multiple storage providers:\n  - **AWS S3**\n  - **Linode Object Storage**\n  - **Garage** (self-hosted S3-compatible)\n  - **Azure Blob Storage**\n- Multi-architecture Docker image (`amd64` / `arm64`)\n\n## Quick Start\n\n### 1. Create an environment file\n\nCopy the example and fill in your values:\n\n```sh\ncp .env.example .env\n```\n\n### 2. Run with Docker Compose\n\nUsing the pre-built image from GitHub Container Registry:\n\n```yaml\n# compose.yml\nservices:\n  pihole-backup:\n    container_name: pihole-backup\n    image: ghcr.io/solairen/pihole-backup:latest\n    env_file: .env\n```\n\n```sh\ndocker compose up -d\n```\n\nThe image is also available on Docker Hub:\n\n```text\nmoleszek/pihole-backup:latest\n```\n\n## Configuration\n\nAll configuration is done through environment variables. Create a `.env` file based on [.env.example](.env.example).\n\n### Required Variables\n\n| Variable | Description |\n| --- | --- |\n| `PROVIDER` | Storage provider: `AWS`, `Linode`, `Garage`, or `Azure` |\n| `PIHOLE_URL` | Full URL to your Pi-hole instance (e.g. `https://pihole.local`) |\n| `PIHOLE_PASSWORD` | Pi-hole admin password |\n\n### Optional Variables\n\n| Variable | Default | Description |\n| --- | --- | --- |\n| `BACKUP_CRON` | *(none)* | Cron expression for backup schedule (e.g. `*/2 * * * *`). If omitted, runs once and exits |\n| `LOG_LEVEL` | `Information` | Serilog log level: `Verbose`, `Debug`, `Information`, `Warning`, `Error`, `Fatal` |\n\n### S3 Provider Variables (AWS, Linode, Garage)\n\n| Variable | Default | Description |\n| --- | --- | --- |\n| `S3_ACCESS_KEY` | **required** | S3 access key |\n| `S3_SECRET_KEY` | **required** | S3 secret key |\n| `S3_BUCKET` | **required** | Target bucket name |\n| `S3_REGION` | `eu-central-1` | AWS region |\n| `S3_ENDPOINT` | `https://s3.\u003cregion\u003e.amazonaws.com` | Custom endpoint. Required for Garage and Linode |\n\n**Endpoint examples:**\n\n- **AWS** -- leave `S3_ENDPOINT` empty; it is derived from `S3_REGION`\n- **Linode** -- `https://eu-central-1.linodeobjects.com`\n- **Garage** -- `http://\u003cgarage-host\u003e:3900`\n\n### Azure Provider Variables\n\n| Variable | Description |\n| --- | --- |\n| `AZURE_TENANT_ID` | Azure AD tenant ID |\n| `AZURE_CLIENT_ID` | Service principal client ID |\n| `AZURE_CLIENT_SECRET` | Service principal client secret |\n| `AZURE_STORAGE_ACCOUNT` | Storage account name |\n| `AZURE_CONTAINER` | Blob container name |\n\n## Building from Source\n\n### Prerequisites\n\n- [.NET 10 SDK](https://dotnet.microsoft.com/download)\n- Docker (for container builds)\n\n### Build the Application\n\n```sh\ndotnet restore src/pihole-backup/pihole-backup.csproj\ndotnet build src/pihole-backup/pihole-backup.csproj -c Release\n```\n\n### Run Locally\n\n```sh\n# Export required environment variables first (see Configuration above)\ndotnet run --project src/pihole-backup/pihole-backup.csproj\n```\n\n### Build the Docker Image\n\n```sh\ndocker compose -f compose.build.yml build\n```\n\nOr directly with Docker:\n\n```sh\ndocker build -f docker/Dockerfile -t pihole-backup:local .\n```\n\nPass a custom version number at build time:\n\n```sh\ndocker build -f docker/Dockerfile --build-arg app_version=1.2.0 -t pihole-backup:1.2.0 .\n```\n\n## Project Structure\n\n```text\n.\n├── docker/\n│   ├── Dockerfile            # Production multi-stage build\n│   └── Dockerfile-dev        # Development container\n├── src/pihole-backup/\n│   ├── Config/\n│   │   └── AppConfig.cs      # Environment variable bindings\n│   ├── Helpers/\n│   │   └── ValidateConfig.cs # Startup configuration validation\n│   ├── Models/\n│   │   ├── AzureBlobOptions.cs\n│   │   └── S3Options.cs\n│   ├── Providers/\n│   │   └── Providers.cs      # Provider enum (AWS, Linode, Garage, Azure)\n│   ├── Services/\n│   │   ├── AWSS3Service.cs          # S3-compatible upload\n│   │   ├── AzureBlobStorageService.cs # Azure Blob upload\n│   │   ├── IStorageService.cs       # Storage interface\n│   │   └── PiHoleService.cs         # Pi-hole Teleporter API client\n│   ├── Program.cs            # Entry point and cron scheduler\n│   └── pihole-backup.csproj\n├── .devcontainer/            # VS Code Dev Container configuration\n├── .github/\n│   └── workflows/\n│       ├── push-image.yml    # Build and push on milestone close\n│       └── test-docker.yml   # Build test on pull requests\n├── compose.yml               # Run with pre-built image\n├── compose.build.yml         # Build image locally\n├── .env.example              # Environment variable template\n├── global.json               # .NET SDK version pin\n├── CONTRIBUTING.md\n├── CODE_OF_CONDUCT.md\n├── CHANGELOG.md\n└── LICENSE                   # GPL-3.0\n```\n\n## How It Works\n\n1. The application authenticates against the Pi-hole v6 API (`/api/auth`) using the configured password\n2. It requests a Teleporter export (`/api/teleporter`) which returns a `.tar.gz` archive of the Pi-hole configuration\n3. 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`)\n4. The local file is deleted after a successful upload\n5. If a cron expression is set, the process repeats on schedule; otherwise it exits after a single run\n\n## Development\n\n### Dev Container\n\nThe 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:\n\n- .NET 10 SDK\n- Pre-commit hooks\n- Hadolint (Dockerfile linter)\n\n### Pre-commit Hooks\n\nThe project uses [pre-commit](https://pre-commit.com/) for code quality checks. Install the hooks after cloning:\n\n```sh\npip install pre-commit\npre-commit install\n```\n\n## CI/CD\n\n- **Pull requests** trigger a Docker build test across `amd64` and `arm64` platforms (no push)\n- **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\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on reporting bugs, suggesting features, and submitting pull requests.\n\n## License\n\nThis project is licensed under the [GNU General Public License v3.0](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolairen%2Fpihole-backup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsolairen%2Fpihole-backup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolairen%2Fpihole-backup/lists"}