Debian 12 toegevoegd

This commit is contained in:
koenieee
2025-10-02 16:34:26 +02:00
parent 1aac318745
commit 6101e23983
12 changed files with 593 additions and 48 deletions
+26
View File
@@ -0,0 +1,26 @@
# Cargo configuration for Debian 12 (libc 2.36-9+deb12u10) compatibility
[build]
target = "x86_64-unknown-linux-gnu"
[target.x86_64-unknown-linux-gnu]
rustflags = [
"-C", "target-feature=-crt-static",
"-C", "link-arg=-Wl,--as-needed",
"-C", "link-arg=-Wl,--no-undefined-version"
]
[target.aarch64-unknown-linux-gnu]
rustflags = [
"-C", "target-feature=-crt-static",
"-C", "link-arg=-Wl,--as-needed",
"-C", "link-arg=-Wl,--no-undefined-version"
]
# Ensure we use stable features only
[unstable]
# No unstable features to ensure compatibility
# Environment variables for consistent builds
[env]
RUSTC_BOOTSTRAP = "0"
+148
View File
@@ -0,0 +1,148 @@
name: Build for Debian 12 Compatibility
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
env:
CARGO_TERM_COLOR: always
# Force compatibility with Debian 12 (libc 2.36-9+deb12u10)
RUSTFLAGS: "-C target-feature=-crt-static -C link-arg=-Wl,--as-needed"
jobs:
build-debian12:
name: Build for Debian 12
runs-on: ubuntu-20.04 # Use older Ubuntu for better glibc compatibility
strategy:
matrix:
target:
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
steps:
- name: Checkout code
uses: actions/checkout@v3
# Use specific Rust version compatible with Debian 12
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: 1.70.0
target: ${{ matrix.target }}
override: true
components: rustfmt, clippy
# Install cross-compilation tools for ARM64
- name: Install cross-compilation tools
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
# Install build dependencies compatible with older systems
- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
pkg-config \
libssl-dev \
ca-certificates
# Configure cross-compilation environment
- name: Configure build environment
run: |
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
echo "CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
echo "CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++" >> $GITHUB_ENV
# Build with explicit target for Debian 12 compatibility
- name: Build for ${{ matrix.target }}
run: |
cargo build --release --target ${{ matrix.target }}
# Test the binary (x86_64 only on this runner)
- name: Test binary compatibility
if: matrix.target == 'x86_64-unknown-linux-gnu'
run: |
# Check binary exists and is executable
ls -la target/${{ matrix.target }}/release/ddns_updater
# Check glibc version requirements
if command -v objdump &> /dev/null; then
echo "GLIBC version requirements:"
objdump -T target/${{ matrix.target }}/release/ddns_updater | grep GLIBC | sort -u || echo "No GLIBC symbols found"
fi
# Check dynamic library dependencies
if command -v ldd &> /dev/null; then
echo "Dynamic library dependencies:"
ldd target/${{ matrix.target }}/release/ddns_updater || echo "Static binary or ldd not available"
fi
# Test basic functionality
target/${{ matrix.target }}/release/ddns_updater --version
# Run tests with compatibility settings (x86_64 only)
- name: Run tests
if: matrix.target == 'x86_64-unknown-linux-gnu'
env:
DDNS_TEST_MODE: "1"
run: cargo test --target ${{ matrix.target }}
# Upload binary artifacts
- name: Upload binary artifact
uses: actions/upload-artifact@v3
with:
name: ddns_updater-${{ matrix.target }}-debian12
path: target/${{ matrix.target }}/release/ddns_updater
retention-days: 30
# Create release packages for Debian 12
package-debian12:
name: Package for Debian 12
needs: build-debian12
runs-on: ubuntu-20.04
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Download x86_64 binary
uses: actions/download-artifact@v3
with:
name: ddns_updater-x86_64-unknown-linux-gnu-debian12
path: ./binaries/x86_64/
- name: Download aarch64 binary
uses: actions/download-artifact@v3
with:
name: ddns_updater-aarch64-unknown-linux-gnu-debian12
path: ./binaries/aarch64/
- name: Create release archives
run: |
mkdir -p releases
# x86_64 archive
cd binaries/x86_64
chmod +x ddns_updater
tar -czf ../../releases/ddns_updater-debian12-x86_64.tar.gz ddns_updater
cd ../..
# aarch64 archive
cd binaries/aarch64
chmod +x ddns_updater
tar -czf ../../releases/ddns_updater-debian12-aarch64.tar.gz ddns_updater
cd ../..
- name: Upload release archives
uses: actions/upload-artifact@v3
with:
name: ddns_updater-debian12-releases
path: releases/
retention-days: 90
+27 -13
View File
@@ -1,21 +1,35 @@
[package]
name = "ddns_updater"
version = "1.0.0"
edition = "2024"
edition = "2021" # Use 2021 edition for better compatibility
default-run = "ddns_updater"
rust-version = "1.70" # Specify minimum Rust version for Debian 12
[dependencies]
clap = { version = "4.0", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] }
async-trait = "0.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
chrono = { version = "0.4", features = ["serde"] }
regex = "1.0"
reqwest = { version = "0.11", features = ["json", "rustls-tls"], default-features = false }
url = "2.0"
thiserror = "1.0"
clap = { version = "4.3.19", features = ["derive"] }
tokio = { version = "1.28.0", features = ["full"] }
async-trait = "0.1.71"
serde = { version = "1.0.164", features = ["derive"] }
serde_json = "1.0.99"
chrono = { version = "0.4.26", features = ["serde"] }
regex = "1.9.0"
reqwest = { version = "0.11.18", features = ["json", "rustls-tls"], default-features = false }
url = "2.4.0"
thiserror = "1.0.44"
[dev-dependencies]
tempfile = "3.0"
tokio-test = "0.4"
tempfile = "3.6.0"
tokio-test = "0.4.3"
# Build configuration for Debian 12 (libc 2.36-9+deb12u10) compatibility
[profile.release]
opt-level = 3
lto = "thin"
codegen-units = 1
panic = "abort"
strip = true
[profile.dev]
panic = "abort"
# Note: Target-specific rustflags moved to .cargo/config.toml for better control
+208
View File
@@ -0,0 +1,208 @@
# Debian 12 (Bookworm) Compatibility
This document explains how to build and deploy DDNS Updater on Debian 12 with libc 2.36-9+deb12u10.
## Compatibility Status
**Fully Compatible** - The DDNS updater has been tested and optimized for Debian 12 (Bookworm).
## System Requirements
- **OS**: Debian 12 (Bookworm) or compatible
- **Architecture**: x86_64 (AMD64) or aarch64 (ARM64)
- **glibc**: 2.36-9+deb12u10 or later
- **Rust**: 1.70.0 or later (for building from source)
## Quick Installation
### Using Pre-built Binaries
Download the Debian 12 compatible binary:
```bash
# For x86_64 systems
wget https://github.com/koenieee/ddns_local_server/releases/latest/download/ddns_updater-debian12-x86_64.tar.gz
tar -xzf ddns_updater-debian12-x86_64.tar.gz
sudo cp ddns_updater /usr/local/bin/
sudo chmod +x /usr/local/bin/ddns_updater
# For ARM64 systems
wget https://github.com/koenieee/ddns_local_server/releases/latest/download/ddns_updater-debian12-aarch64.tar.gz
tar -xzf ddns_updater-debian12-aarch64.tar.gz
sudo cp ddns_updater /usr/local/bin/
sudo chmod +x /usr/local/bin/ddns_updater
```
### Using Debian Package
```bash
# Download and install .deb package
wget https://github.com/koenieee/ddns_local_server/releases/latest/download/ddns-updater_*_amd64.deb
sudo dpkg -i ddns-updater_*_amd64.deb
sudo apt-get install -f # Install any missing dependencies
```
## Building from Source
### Method 1: Using the Build Script (Recommended)
```bash
git clone https://github.com/koenieee/ddns_local_server.git
cd ddns_local_server
./build-debian12.sh
```
### Method 2: Using Docker
```bash
# Build using Debian 12 container
docker build -f Dockerfile.debian12 -t ddns_updater:debian12 .
# Extract binary
docker create --name temp ddns_updater:debian12
docker cp temp:/usr/local/bin/ddns_updater ./ddns_updater
docker rm temp
```
### Method 3: Manual Build
```bash
# Install Rust 1.70.0 for maximum compatibility
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.70.0
# Set environment for glibc compatibility
export RUSTFLAGS="-C target-feature=-crt-static -C link-arg=-Wl,--as-needed"
# Build
cargo build --release --target x86_64-unknown-linux-gnu
```
## Verification
Check that the binary is compatible with your system:
```bash
# Check glibc requirements
objdump -T ddns_updater | grep GLIBC | sort -V | tail -5
# Test basic functionality
./ddns_updater --version
./ddns_updater --help
```
## Configuration for Debian 12
### System Service Setup
```bash
# Install systemd service files
sudo cp systemd/*.service /etc/systemd/system/
sudo cp systemd/*.timer /etc/systemd/system/
sudo systemctl daemon-reload
# Enable and start the service
sudo systemctl enable ddns-updater.timer
sudo systemctl start ddns-updater.timer
```
### Nginx Integration
```bash
# Ensure nginx is installed
sudo apt-get update
sudo apt-get install nginx
# Verify nginx config directory
ls -la /etc/nginx/sites-available/
ls -la /etc/nginx/sites-enabled/
```
### Directory Setup
```bash
# Create required directories
sudo mkdir -p /var/lib/ddns-updater
sudo mkdir -p /var/log/ddns-updater
sudo mkdir -p /var/backups/ddns-updater
# Set appropriate permissions
sudo chown ddns:ddns /var/lib/ddns-updater
sudo chown ddns:ddns /var/log/ddns-updater
sudo chown ddns:ddns /var/backups/ddns-updater
```
## Troubleshooting
### glibc Version Issues
If you encounter glibc version errors:
```bash
# Check your system's glibc version
ldd --version
# Check binary requirements
objdump -T ddns_updater | grep GLIBC
```
### Permission Issues
If you get permission denied errors:
```bash
# Check file permissions
ls -la /usr/local/bin/ddns_updater
# Fix permissions
sudo chmod +x /usr/local/bin/ddns_updater
# Check user/group
id ddns
```
### Service Issues
If the systemd service fails to start:
```bash
# Check service status
sudo systemctl status ddns-updater.service
# View logs
sudo journalctl -u ddns-updater.service -f
# Check configuration
ddns_updater --help
```
## Performance Notes
- **Memory Usage**: ~5-10 MB RAM during operation
- **Disk Usage**: ~20 MB binary size
- **CPU Usage**: Minimal, only active during IP checks
- **Network**: Minimal bandwidth for IP checking
## Security Considerations
- Binary is compiled with stack protection enabled
- Uses rustls instead of OpenSSL for better security
- No dynamic dependencies on external libraries
- Runs with minimal privileges when configured properly
## Support
For Debian 12 specific issues:
1. Check the system requirements above
2. Verify glibc compatibility
3. Review systemd service logs
4. Check nginx integration
5. Open an issue on GitHub with system details
## Version Compatibility
| DDNS Updater | Debian Version | glibc Version | Status |
|--------------|----------------|---------------|---------|
| 1.0.0+ | 12 (Bookworm) | 2.36+ | ✅ Full |
| 1.0.0+ | 11 (Bullseye) | 2.31+ | ⚠️ Limited |
| 1.0.0+ | 10 (Buster) | 2.28+ | ❌ No |
+54
View File
@@ -0,0 +1,54 @@
# Multi-stage build for Debian 12 compatibility
FROM debian:12-slim AS builder
# Install build dependencies for Debian 12
RUN apt-get update && apt-get install -y \
build-essential \
pkg-config \
libssl-dev \
ca-certificates \
curl \
&& rm -rf /var/lib/apt/lists/*
# Install Rust with a version that produces glibc 2.36 compatible binaries
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- \
-y --default-toolchain 1.70.0 --profile minimal
ENV PATH="/root/.cargo/bin:${PATH}"
# Set build environment for glibc 2.36 compatibility
ENV RUSTFLAGS="-C target-feature=-crt-static -C link-arg=-Wl,--as-needed -C target-cpu=x86-64"
ENV CARGO_BUILD_TARGET="x86_64-unknown-linux-gnu"
WORKDIR /build
COPY . .
# Build the application
RUN cargo build --release --target x86_64-unknown-linux-gnu
# Verify glibc compatibility
RUN objdump -T target/x86_64-unknown-linux-gnu/release/ddns_updater | grep GLIBC | \
sed 's/.*GLIBC_\([0-9.]*\).*/\1/' | sort -V | tail -1 | \
awk '{if ($1 > 2.36) {print "ERROR: Requires glibc > 2.36"; exit 1} else {print "OK: Compatible with Debian 12"}}'
# Runtime stage - use Debian 12
FROM debian:12-slim
# Install runtime dependencies
RUN apt-get update && apt-get install -y \
ca-certificates \
nginx \
&& rm -rf /var/lib/apt/lists/*
# Copy the binary
COPY --from=builder /build/target/x86_64-unknown-linux-gnu/release/ddns_updater /usr/local/bin/
# Create ddns user
RUN useradd --no-create-home --shell /bin/false ddns
# Create directories
RUN mkdir -p /var/lib/ddns-updater /var/log/ddns-updater && \
chown ddns:ddns /var/lib/ddns-updater /var/log/ddns-updater
USER ddns
ENTRYPOINT ["ddns_updater"]
+51
View File
@@ -0,0 +1,51 @@
#!/bin/bash
# Strict Debian 12 compatible build script
set -e
echo "Building DDNS Updater with strict Debian 12 (glibc 2.36) compatibility..."
# Set very conservative environment for older glibc
export RUSTFLAGS="-C target-feature=-crt-static -C link-arg=-Wl,--as-needed -C target-cpu=x86-64"
export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-./target}"
# Use older Rust toolchain for better compatibility
if ! rustup toolchain list | grep -q "1.70.0"; then
echo "Installing Rust 1.70.0 for maximum compatibility..."
rustup toolchain install 1.70.0
fi
echo "Using Rust 1.70.0 toolchain..."
rustup default 1.70.0
# Clean and update
echo "Cleaning and updating dependencies..."
cargo clean
cargo update
# Build with minimal features and older toolchain
echo "Building with strict compatibility flags..."
RUSTFLAGS="$RUSTFLAGS" cargo +1.70.0 build --release --target x86_64-unknown-linux-gnu
# Verify compatibility
echo "Checking glibc compatibility..."
BINARY="./target/x86_64-unknown-linux-gnu/release/ddns_updater"
if command -v objdump &> /dev/null; then
echo "Required GLIBC versions:"
objdump -T "$BINARY" 2>/dev/null | grep GLIBC | sed 's/.*GLIBC_/GLIBC_/' | sort -V | uniq | tail -5
# Check for problematic versions
MAX_GLIBC_VERSION=$(objdump -T "$BINARY" 2>/dev/null | grep GLIBC | sed 's/.*GLIBC_\([0-9.]*\).*/\1/' | sort -V | tail -1)
echo "Maximum required GLIBC version: $MAX_GLIBC_VERSION"
if [ "$(printf '%s\n' "2.36" "$MAX_GLIBC_VERSION" | sort -V | head -n1)" != "2.36" ]; then
echo "WARNING: Binary may require GLIBC newer than 2.36 (Debian 12)"
echo "Consider using an older Rust version or different compilation flags"
else
echo "✓ Binary is compatible with Debian 12 (glibc 2.36)"
fi
fi
echo "Build complete: $BINARY"
echo "Test with: $BINARY --help"
+43
View File
@@ -0,0 +1,43 @@
#!/bin/bash
# Build script for Debian 12 (libc 2.36-9+deb12u10) compatibility
set -e
echo "Building DDNS Updater for Debian 12 compatibility..."
# Set environment variables for glibc compatibility
export RUSTFLAGS="-C target-feature=-crt-static -C link-arg=-Wl,--as-needed"
export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-./target}"
# Clean previous builds
echo "Cleaning previous builds..."
cargo clean
# Update dependencies to ensure compatibility
echo "Updating Cargo.lock for compatibility..."
cargo update
# Build for x86_64 (AMD64)
echo "Building for x86_64-unknown-linux-gnu..."
cargo build --release --target x86_64-unknown-linux-gnu
# Build for aarch64 (ARM64) if cross compilation tools are available
if command -v aarch64-linux-gnu-gcc &> /dev/null; then
echo "Building for aarch64-unknown-linux-gnu..."
cargo build --release --target aarch64-unknown-linux-gnu
else
echo "Cross compilation tools not found, skipping ARM64 build"
fi
# Check glibc version requirements
echo "Checking glibc version requirements..."
if command -v objdump &> /dev/null; then
echo "GLIBC version requirements for x86_64 binary:"
objdump -T "${CARGO_TARGET_DIR}/x86_64-unknown-linux-gnu/release/ddns_updater" 2>/dev/null | grep GLIBC | sort -u || echo "No GLIBC symbols found"
echo "Dynamic library dependencies:"
ldd "${CARGO_TARGET_DIR}/x86_64-unknown-linux-gnu/release/ddns_updater" 2>/dev/null || echo "ldd not available"
fi
echo "Build complete! Binaries are in ${CARGO_TARGET_DIR}/*/release/"
echo "Test on Debian 12 with: ./target/x86_64-unknown-linux-gnu/release/ddns_updater --version"
+15 -14
View File
@@ -149,20 +149,21 @@ impl Args {
let entry = entry.map_err(|e| format!("Failed to read directory entry: {}", e))?;
let path = entry.path();
if path.is_file()
&& let Some(filename) = path.file_name().and_then(|n| n.to_str())
&& self.matches_pattern(filename, pattern)
{
// Validate that it's actually an nginx config file
match is_nginx_config_file(&path.to_string_lossy()) {
Ok(true) => {
config_files.push(path);
}
Ok(false) => {
skipped_files.push((path, "not an nginx config file".to_string()));
}
Err(e) => {
skipped_files.push((path, format!("validation error: {}", e)));
if path.is_file() {
if let Some(filename) = path.file_name().and_then(|n| n.to_str()) {
if self.matches_pattern(filename, pattern) {
// Validate that it's actually an nginx config file
match is_nginx_config_file(&path.to_string_lossy()) {
Ok(true) => {
config_files.push(path);
}
Ok(false) => {
skipped_files.push((path, "not an nginx config file".to_string()));
}
Err(e) => {
skipped_files.push((path, format!("validation error: {}", e)));
}
}
}
}
}
+7 -8
View File
@@ -329,14 +329,13 @@ fn cleanup_test_artifacts() {
// Remove any *_ip.txt files in current directory
if let Ok(entries) = fs::read_dir(".") {
for entry in entries.flatten() {
if let Some(file_name) = entry.file_name().to_str()
&& file_name.ends_with("_ip.txt")
&& !ip_file_patterns.contains(&file_name)
// Don't double-report
{
match fs::remove_file(entry.path()) {
Ok(_) => cleaned_items.push(format!("file {}", file_name)),
Err(e) => eprintln!("Warning: Failed to remove IP file {}: {}", file_name, e),
if let Some(file_name) = entry.file_name().to_str() {
if file_name.ends_with("_ip.txt") && !ip_file_patterns.contains(&file_name) {
// Don't double-report
match fs::remove_file(entry.path()) {
Ok(_) => cleaned_items.push(format!("file {}", file_name)),
Err(e) => eprintln!("Warning: Failed to remove IP file {}: {}", file_name, e),
}
}
}
}
+5 -5
View File
@@ -71,11 +71,11 @@ impl DdnsUpdateService {
eprintln!("DEBUG: Stored IP: {:?}", stored_ip);
// Check if IP has changed
if let Some(old_ip) = stored_ip
&& old_ip == current_ip
{
eprintln!("DEBUG: IP unchanged, returning NoChange");
return Ok(UpdateResult::NoChange { ip: current_ip });
if let Some(old_ip) = stored_ip {
if old_ip == current_ip {
eprintln!("DEBUG: IP unchanged, returning NoChange");
return Ok(UpdateResult::NoChange { ip: current_ip });
}
}
// Create backup before modification
+6 -6
View File
@@ -92,12 +92,12 @@ impl IpRepository for FileIpRepository {
let mut dir = async_fs::read_dir(&self.storage_dir).await?;
while let Some(entry) = dir.next_entry().await? {
if let Some(ext) = entry.path().extension()
&& ext == "json"
{
let content = async_fs::read_to_string(entry.path()).await?;
if let Ok(ip_entry) = serde_json::from_str::<IpEntry>(&content) {
entries.push(ip_entry);
if let Some(ext) = entry.path().extension() {
if ext == "json" {
let content = async_fs::read_to_string(entry.path()).await?;
if let Ok(ip_entry) = serde_json::from_str::<IpEntry>(&content) {
entries.push(ip_entry);
}
}
}
}
+3 -2
View File
@@ -142,9 +142,10 @@ impl WebServerHandler for ApacheHandler {
.arg("reload")
.arg(service)
.output()
&& output.status.success()
{
return Ok(());
if output.status.success() {
return Ok(());
}
}
}