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
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,7 @@ ENTRYPOINT ["/bin/ddns"]
FROM scratch AS minimal
COPY --from=build /bin/ddns /bin/
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

USER 1000:1000

ENTRYPOINT ["/bin/ddns"]
77 changes: 77 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,83 @@ docker-compose pull cloudflare-ddns
docker-compose up --detach --build cloudflare-ddns
```

### 🏥 Docker Health Monitoring

The `cloudflare-ddns` binary includes a built-in healthcheck command that verifies DDNS records are being updated correctly. This healthcheck can be used with Docker to monitor the health of your container.

#### How the Healthcheck Works

When you run `/bin/ddns --healthcheck`, the updater performs the following operations:

1. **Configuration Validation**: Verifies that all configuration settings are valid
2. **IP Detection**: Detects the current public IP address(es)
3. **DNS Record Update**: Attempts to update the configured DNS records with the detected IP addresses
4. **Status Reporting**: Returns exit code `0` if all operations succeed, or `1` if any operation fails

The healthcheck uses the same configuration as the main updater process (environment variables like `CLOUDFLARE_API_TOKEN`, `DOMAINS`, etc.), so it reflects the actual state of your DDNS setup.

#### Docker Compose Healthcheck Example

You can add a healthcheck to your `docker-compose.yml` to monitor the container's health:

```yaml
services:
cloudflare-ddns:
image: favonia/cloudflare-ddns:latest
container_name: cloudflare-ddns
network_mode: host
restart: unless-stopped
user: "1000:1000"
read_only: true
cap_drop: [all]
security_opt: [no-new-privileges:true]
environment:
- CLOUDFLARE_API_TOKEN=YOUR-CLOUDFLARE-API-TOKEN
- DOMAINS=example.org,www.example.org
- PROXIED=true
- IP6_PROVIDER=none # Disable IPv6 if not supported (recommended for most Docker setups)
healthcheck:
test: ["CMD", "/bin/ddns", "--healthcheck"]
interval: 5m
timeout: 30s
start_period: 30s
retries: 3
```

#### Healthcheck Configuration Options

The `healthcheck` section supports the following options:

- **`test`**: The command to run for the healthcheck. Use `["CMD", "/bin/ddns", "--healthcheck"]`
- **`interval`**: How often to run the healthcheck (e.g., `5m` for every 5 minutes). Should match or be longer than your `UPDATE_CRON` setting
- **`timeout`**: Maximum time allowed for the healthcheck to complete (e.g., `30s`)
- **`start_period`**: Grace period before the first healthcheck runs, allowing the container to start up (e.g., `30s`)
- **`retries`**: Number of consecutive failures required to mark the container as unhealthy (e.g., `3`)

#### Best Practices

- **Interval Timing**: Set the healthcheck `interval` to match your `UPDATE_CRON` schedule. For example, if you update DNS records every 5 minutes (`UPDATE_CRON=@every 5m`), set `interval: 5m`
- **Timeout**: Ensure the `timeout` is long enough to allow IP detection and DNS updates to complete (30 seconds is usually sufficient)
- **IPv6 Considerations**: ⚠️ **Important!** The healthcheck will fail if either IPv4 or IPv6 detection fails. If your Docker environment doesn't support IPv6 (which is common), set `IP6_PROVIDER=none` in your environment variables to disable IPv6 and prevent healthcheck failures. Similarly, set `IP4_PROVIDER=none` if your network doesn't support IPv4.
- **Monitoring**: Use Docker's health status with `docker ps` to see if your container is healthy. You can also integrate with monitoring systems that check Docker container health

#### Monitoring Container Health

View the health status using Docker commands:

```bash
# Check current health status
docker ps

# View detailed health check logs
docker inspect cloudflare-ddns | grep -A 10 "Health"

# Monitor health check output in real-time
docker logs -f cloudflare-ddns 2>&1 | grep healthcheck
```

The container will be marked as `healthy` when all configured checks pass, or `unhealthy` if any validation fails. This integrates with Docker Compose, Kubernetes, and monitoring systems that check container health status.

## ❓ Frequently Asked Questions

<details>
Expand Down
40 changes: 40 additions & 0 deletions cmd/ddns/ddns.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,50 @@
}

func main() {
// Check for healthcheck flag
for _, arg := range os.Args[1:] {
if arg == "--healthcheck" {
os.Exit(healthcheckMain())
return
}
}
// This is to make os.Exit work with defer
os.Exit(realMain())
}

// healthcheckMain runs a healthcheck to verify DDNS records are being updated correctly.
func healthcheckMain() int {
ctx := context.Background()

Check failure on line 80 in cmd/ddns/ddns.go

View workflow job for this annotation

GitHub Actions / Lint

File is not properly formatted (gci)

Check failure on line 80 in cmd/ddns/ddns.go

View workflow job for this annotation

GitHub Actions / Lint

File is not properly formatted (gci)
// Set up pretty printer (suppress output for cleaner healthcheck)
ppfmt, ok := config.SetupPP(os.Stdout)
if !ok {
fmt.Fprintln(os.Stderr, "Healthcheck FAILED: Could not set up printer")
return 1
}

// Read the config and get the handler and the setter
c, s, configOK := initConfig(ppfmt)
if !configOK {
fmt.Fprintln(os.Stderr, "Healthcheck FAILED: Configuration errors")
return 1
}

// Run the update check
msg := updater.UpdateIPs(ctx, ppfmt, c, s)

if msg.MonitorMessage.OK {
fmt.Println("Healthcheck OK: DDNS records updated successfully")

Check failure on line 99 in cmd/ddns/ddns.go

View workflow job for this annotation

GitHub Actions / Lint

use of `fmt.Println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)

Check failure on line 99 in cmd/ddns/ddns.go

View workflow job for this annotation

GitHub Actions / Lint

use of `fmt.Println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
return 0
}

fmt.Fprintln(os.Stderr, "Healthcheck FAILED: DDNS records update failed")
if len(msg.MonitorMessage.Lines) > 0 {
fmt.Fprintln(os.Stderr, msg.MonitorMessage.Format())
}
return 1
}

func realMain() int {
// Get the contexts and start catching SIGINT and SIGTERM
ctx := context.Background()
Expand Down
Loading