From d7285511f00dcd7c4c7e986ee4275e09723cb5d3 Mon Sep 17 00:00:00 2001 From: LC mac Date: Wed, 14 Jan 2026 00:53:58 +0800 Subject: [PATCH] feat: add Docker image build target and deployment docs --- Makefile | 29 ++++-- README.md | 284 ++++++++++++++++++++++-------------------------------- 2 files changed, 135 insertions(+), 178 deletions(-) diff --git a/Makefile b/Makefile index 1d16221..bbd3e17 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,20 @@ APP_NAME = ddns-updater -BIN_DIR = bin -VERSION = 1.0.0 +BIN_DIR = bin +VERSION = 1.0.0 # Go parameters -GOCMD = go +GOCMD = go GOBUILD = $(GOCMD) build GOCLEAN = $(GOCMD) clean -GORUN = $(GOCMD) run +GORUN = $(GOCMD) run + +# Docker image (override: make build-dockerimg IMAGE=kccleoc/ddns-updater:latest) +IMAGE ?= kccleoc/ddns-updater:latest # Build targets -.PHONY: all build clean run init-config install install-linux install-macos service-linux service-macos +.PHONY: all build build-all clean run init-config install \ + install-linux install-macos service-linux service-macos \ + build-dockerimg push-dockerimg all: build @@ -22,8 +27,8 @@ build: # Build for multiple platforms build-all: mkdir -p $(BIN_DIR) - GOOS=linux GOARCH=amd64 $(GOBUILD) -o $(BIN_DIR)/$(APP_NAME)-linux-amd64 main.go - GOOS=linux GOARCH=arm64 $(GOBUILD) -o $(BIN_DIR)/$(APP_NAME)-linux-arm64 main.go + GOOS=linux GOARCH=amd64 $(GOBUILD) -o $(BIN_DIR)/$(APP_NAME)-linux-amd64 main.go + GOOS=linux GOARCH=arm64 $(GOBUILD) -o $(BIN_DIR)/$(APP_NAME)-linux-arm64 main.go GOOS=darwin GOARCH=amd64 $(GOBUILD) -o $(BIN_DIR)/$(APP_NAME)-darwin-amd64 main.go GOOS=darwin GOARCH=arm64 $(GOBUILD) -o $(BIN_DIR)/$(APP_NAME)-darwin-arm64 main.go @echo "Built all platform binaries in $(BIN_DIR)/" @@ -90,3 +95,13 @@ service-macos: @echo " launchctl start com.ddns-updater" @echo "\nView logs with:" @echo " tail -f /usr/local/var/log/ddns-updater.log" + +# Build Docker image (parameterized) +# Usage: make build-dockerimg IMAGE=kccleoc/ddns-updater:latest +build-dockerimg: + docker build -t $(IMAGE) . + +# Push Docker image +# Usage: make push-dockerimg IMAGE=kccleoc/ddns-updater:latest +push-dockerimg: + docker push $(IMAGE) diff --git a/README.md b/README.md index c5cf085..f9dcf09 100644 --- a/README.md +++ b/README.md @@ -13,219 +13,161 @@ A lightweight dynamic DNS updater for Cloudflare written in Go. Automatically de - Graceful shutdown handling - Cross-platform (Linux, macOS) -## Quick Start +## Building and running -### 1. Generate configuration template +### 1. Generate config ```bash -make init-config +go run main.go -init-config > config.yaml +# edit config.yaml with your Cloudflare token, zone_id, zone_name, and subdomains ``` -This creates `config.yaml` with default settings. - -### 2. Get Cloudflare credentials - -#### Generate API Token - -1. Log in to [Cloudflare Dashboard](https://dash.cloudflare.com) -2. Go to **Profile** → **API Tokens** -3. Click **Create Token** -4. Use the **Edit zone DNS** template or create a custom token with: - - **Permissions**: Zone → DNS → Edit, Zone → Zone → Read - - **Zone Resources**: Include → Specific zone → (select your domain) -5. Copy the token (you'll only see it once) - -#### Find Zone ID - -1. In Cloudflare Dashboard, select your domain -2. Scroll down on the **Overview** page -3. Find **Zone ID** in the right sidebar under **API** section -4. Copy the Zone ID - -### 3. Configure - -Edit `config.yaml`: +Key fields: ```yaml cloudflare: - api_token: "your-token-here" # From step 2 - zone_id: "your-zone-id-here" # From step 2 - zone_name: "example.com" # Your domain - subdomains: - - name: "home" # Updates home.example.com - proxied: false - - name: "vpn" - proxied: true # Route through Cloudflare proxy -``` - -### 4. Run locally (test) - -```bash -make run -``` - -Logs will show IP detection and DNS updates in real-time. - -## Production Deployment - -### Linux (systemd) - -#### Install and set up service - -```bash -# Build and install binary -make install-linux - -# Edit config with your credentials -sudo nano /etc/ddns-updater/config.yaml - -# Create systemd service -make service-linux - -# Enable and start -sudo systemctl daemon-reload -sudo systemctl enable ddns-updater -sudo systemctl start ddns-updater - -# Check status -sudo systemctl status ddns-updater - -# View logs -sudo journalctl -u ddns-updater -f -``` - -#### Service management - -```bash -sudo systemctl stop ddns-updater # Stop service -sudo systemctl restart ddns-updater # Restart service -sudo systemctl disable ddns-updater # Disable auto-start -``` - -### macOS (launchd) - -#### Install and set up service - -```bash -# Build and install binary -make install-macos - -# Edit config with your credentials -sudo nano /usr/local/etc/ddns-updater.yaml - -# Create launchd service -make service-macos - -# Load and start -launchctl load ~/Library/LaunchAgents/com.ddns-updater.plist -launchctl start com.ddns-updater - -# View logs -tail -f /usr/local/var/log/ddns-updater.log -``` - -#### Service management - -```bash -launchctl stop com.ddns-updater # Stop service -launchctl unload ~/Library/LaunchAgents/com.ddns-updater.plist # Unload service -``` - -## Configuration Reference - -```yaml -# Check interval in minutes (how often to check for IP changes) -check_interval: 5 - -cloudflare: - api_token: "your-api-token" + api_token: "your-token" zone_id: "your-zone-id" zone_name: "example.com" subdomains: - - name: "subdomain" - proxied: false # true = route through Cloudflare proxy (orange cloud) - + - name: "lc" + proxied: false logging: - file: "ddns-updater.log" - level: "info" # debug, info, warn, error - -retry: - max_attempts: 3 - delay_seconds: 5 - -webhook: - enabled: false - url: "" # Optional webhook for notifications + file: "/config/logs/ddns-updater.log" ``` -## Building from Source +### 2. Local binary (Linux/macOS) ```bash -# Build for current platform make build - -# Build for all platforms -make build-all - -# Clean build artifacts -make clean +./bin/ddns-updater -config config.yaml ``` -Built binaries will be in `./bin/` +*** -## Troubleshooting +## Production: Linux (systemd) -### Authentication errors - -- Verify API token has correct permissions (Zone → DNS → Edit, Zone → Zone → Read) -- Confirm token is scoped to the correct zone -- Check token hasn't expired - -### DNS record not found - -- Ensure `zone_name` matches your Cloudflare domain exactly -- Verify subdomain exists in Cloudflare DNS settings -- Check subdomain name doesn't include the domain (use `home`, not `home.example.com`) - -### Service won't start - -**Linux:** +1. Install: ```bash -sudo journalctl -u ddns-updater -n 50 +sudo make install +sudo mkdir -p /etc/ddns-updater +sudo cp config.yaml /etc/ddns-updater/config.yaml +sudo chmod 600 /etc/ddns-updater/config.yaml ``` -**macOS:** +2. Create `/etc/systemd/system/ddns-updater.service`: -```bash -cat /usr/local/var/log/ddns-updater.err +```ini +[Unit] +Description=DDNS Updater +After=network-online.target + +[Service] +ExecStart=/usr/local/bin/ddns-updater -config /etc/ddns-updater/config.yaml +Restart=always +RestartSec=10 +User=root + +[Install] +WantedBy=multi-user.target ``` -### Docker deployment - -Build the image: +3. Enable: ```bash -docker build -t yourname/ddns-updater:latest . +sudo systemctl daemon-reload +sudo systemctl enable --now ddns-updater +sudo systemctl status ddns-updater ``` -Run with a local config file: +*** + +## Production: macOS (launchd) + +1. Install: ```bash -cp config.yaml.example config.yaml # or make init-config -# edit config.yaml with your Cloudflare settings +sudo make install +sudo mkdir -p /usr/local/etc /usr/local/var/log +sudo cp config.yaml /usr/local/etc/ddns-updater.yaml +sudo chmod 600 /usr/local/etc/ddns-updater.yaml +``` +2. Create `~/Library/LaunchAgents/com.ddns-updater.plist` pointing at: + +```xml + + /usr/local/bin/ddns-updater + -config + /usr/local/etc/ddns-updater.yaml + +``` + +3. Load: + +```bash +launchctl load ~/Library/LaunchAgents/com.ddns-updater.plist +launchctl start com.ddns-updater +``` + +*** + +## Docker usage + +### 1. Prepare appdata on host (e.g. Unraid) + +```bash +mkdir -p /mnt/user/appdata/ddns-updater/logs +cp config.yaml /mnt/user/appdata/ddns-updater/config.yaml +chmod -R 775 /mnt/user/appdata/ddns-updater +``` + +Ensure `logging.file` in `/mnt/user/appdata/ddns-updater/config.yaml` is: + +```yaml +logging: + file: "/config/logs/ddns-updater.log" +``` + +### 2. Dockerfile (multi-stage) + +Already in repo, using `/config/config.yaml` inside the container and writing logs to `/config/logs`. + +### 3. Run with docker + +```bash docker run -d \ --name ddns-updater \ --restart unless-stopped \ - -v $(pwd)/config.yaml:/config/config.yaml:ro \ - yourname/ddns-updater:latest + -v /mnt/user/appdata/ddns-updater:/config \ + kccleoc/ddns-updater:latest ``` -Or with Docker Compose: +### 4. Docker Compose (Unraid 7 friendly) + +```yaml +services: + ddns-updater: + image: kccleoc/ddns-updater:latest + container_name: ddns-updater + restart: unless-stopped + user: "0:0" + volumes: + - /mnt/user/appdata/ddns-updater:/config +``` + +Bring it up from the Compose UI (or CLI): ```bash docker compose up -d ``` -The container runs in the foreground inside Docker; restarts are handled by Docker’s restart policy. +## Makefile (Docker image build) + +Usage examples: + +```bash +make build-dockerimg IMAGE=kccleoc/ddns-updater:latest +make push-dockerimg IMAGE=kccleoc/ddns-updater:latest +```