Fix certificate renewal cron job and add host-side scheduling
All checks were successful
HAProxy Manager Build and Push / Build-and-Push (push) Successful in 1m0s
All checks were successful
HAProxy Manager Build and Push / Build-and-Push (push) Successful in 1m0s
- Fixed crontab permissions (600) and ownership for proper cron execution - Added PATH environment variable to crontab to prevent command not found issues - Created dedicated renewal script with comprehensive logging and error handling - Added retry logic (3 attempts) for HAProxy reload with socket health checks - Implemented host-side renewal script for external cron scheduling via docker exec - Added crontab configuration examples for various renewal schedules - Updated README with detailed certificate renewal documentation This resolves issues where the cron job would not run or hang during execution. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -7,10 +7,15 @@ COPY haproxy_manager.py /haproxy/
|
||||
COPY scripts /haproxy/scripts
|
||||
RUN chmod +x /haproxy/scripts/*
|
||||
RUN pip install -r requirements.txt
|
||||
RUN echo "0 */12 * * * root test -x /usr/bin/certbot && /usr/bin/certbot -q renew && echo \"reload\" | socat stdio /tmp/haproxy-cli" > /var/spool/cron/crontabs/root
|
||||
# Create log directories
|
||||
RUN mkdir -p /var/log && touch /var/log/haproxy-manager.log /var/log/haproxy-manager-errors.log
|
||||
RUN chmod 755 /var/log/haproxy-manager.log /var/log/haproxy-manager-errors.log
|
||||
# Set up cron for certificate renewal with proper permissions and environment
|
||||
RUN mkdir -p /var/spool/cron/crontabs && \
|
||||
echo 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' > /var/spool/cron/crontabs/root && \
|
||||
echo '0 */12 * * * /haproxy/scripts/renew-certificates.sh >> /var/log/haproxy-manager.log 2>&1' >> /var/spool/cron/crontabs/root && \
|
||||
chmod 600 /var/spool/cron/crontabs/root && \
|
||||
chown root:crontab /var/spool/cron/crontabs/root
|
||||
EXPOSE 80 443 8000
|
||||
# Add health check
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
|
||||
49
README.md
49
README.md
@@ -299,6 +299,54 @@ GET /api/certificates/example.com/cert
|
||||
Authorization: Bearer your-api-key
|
||||
```
|
||||
|
||||
## Certificate Renewal
|
||||
|
||||
The HAProxy Manager includes automatic certificate renewal with multiple scheduling options:
|
||||
|
||||
### Automatic Renewal (Container-based)
|
||||
By default, a cron job runs inside the container every 12 hours to check and renew certificates:
|
||||
- Runs at minute 0 of every 12th hour (12:00 AM, 12:00 PM)
|
||||
- Automatically reloads HAProxy if certificates are renewed
|
||||
- Logs all renewal attempts to `/var/log/haproxy-manager.log`
|
||||
- Errors logged to `/var/log/haproxy-manager-errors.log`
|
||||
|
||||
### Manual Renewal via API
|
||||
Trigger certificate renewal manually using the API:
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/api/certificates/renew \
|
||||
-H "Authorization: Bearer your-api-key"
|
||||
```
|
||||
|
||||
### Host-side Renewal (Recommended for Production)
|
||||
For more control over scheduling, run renewals from the host machine using the provided script:
|
||||
|
||||
```bash
|
||||
# Make the script executable
|
||||
chmod +x scripts/host-renew-certificates.sh
|
||||
|
||||
# Add to host crontab (edit with: crontab -e)
|
||||
0 */12 * * * /path/to/haproxy-manager-base/scripts/host-renew-certificates.sh
|
||||
|
||||
# Or run manually
|
||||
./scripts/host-renew-certificates.sh
|
||||
```
|
||||
|
||||
The host-side script:
|
||||
- Executes the renewal process inside the running container
|
||||
- Maintains separate host-side logs at `/var/log/haproxy-manager-host-renewal.log`
|
||||
- Automatically detects if the container is running
|
||||
- Supports custom container names via `CONTAINER_NAME` environment variable
|
||||
|
||||
See [scripts/host-crontab-example.txt](scripts/host-crontab-example.txt) for more crontab configuration examples.
|
||||
|
||||
### Renewal Script Features
|
||||
The renewal script ([scripts/renew-certificates.sh](scripts/renew-certificates.sh)) includes:
|
||||
- Comprehensive logging with timestamps
|
||||
- Retry logic for HAProxy reload (3 attempts with 5-second delays)
|
||||
- HAProxy socket health checks before reload
|
||||
- Proper error handling and exit codes
|
||||
- Detection of whether certificates actually needed renewal
|
||||
|
||||
## Logging and Monitoring
|
||||
|
||||
The HAProxy Manager includes comprehensive logging and error tracking:
|
||||
@@ -306,6 +354,7 @@ The HAProxy Manager includes comprehensive logging and error tracking:
|
||||
### Log Files
|
||||
- `/var/log/haproxy-manager.log` - General application logs
|
||||
- `/var/log/haproxy-manager-errors.log` - Error logs for alerting
|
||||
- `/var/log/haproxy-manager-host-renewal.log` - Host-side renewal logs (when using host script)
|
||||
|
||||
### Logged Operations
|
||||
All API operations are logged with timestamps and success/failure status:
|
||||
|
||||
26
scripts/host-crontab-example.txt
Normal file
26
scripts/host-crontab-example.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
# HAProxy Manager - Host-side Crontab Example
|
||||
# Add this to your host machine's crontab to schedule certificate renewals
|
||||
#
|
||||
# Edit your crontab with: crontab -e
|
||||
# View your crontab with: crontab -l
|
||||
#
|
||||
# The script will run inside the container and handle all logging internally.
|
||||
# Host-side logs will be written to /var/log/haproxy-manager-host-renewal.log
|
||||
|
||||
# Run certificate renewal every 12 hours at the top of the hour
|
||||
0 */12 * * * /path/to/haproxy-manager-base/scripts/host-renew-certificates.sh
|
||||
|
||||
# Alternative: Run at specific times (e.g., 2 AM and 2 PM daily)
|
||||
# 0 2,14 * * * /path/to/haproxy-manager-base/scripts/host-renew-certificates.sh
|
||||
|
||||
# Alternative: Run once daily at 3 AM
|
||||
# 0 3 * * * /path/to/haproxy-manager-base/scripts/host-renew-certificates.sh
|
||||
|
||||
# Custom container name example (if your container has a different name):
|
||||
# 0 */12 * * * CONTAINER_NAME=my-haproxy /path/to/haproxy-manager-base/scripts/host-renew-certificates.sh
|
||||
|
||||
# Custom log file location example:
|
||||
# 0 */12 * * * LOG_FILE=/custom/path/renewal.log /path/to/haproxy-manager-base/scripts/host-renew-certificates.sh
|
||||
|
||||
# With both custom settings:
|
||||
# 0 */12 * * * CONTAINER_NAME=my-haproxy LOG_FILE=/custom/path/renewal.log /path/to/haproxy-manager-base/scripts/host-renew-certificates.sh
|
||||
39
scripts/host-renew-certificates.sh
Executable file
39
scripts/host-renew-certificates.sh
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Host-side Certificate Renewal Script
|
||||
# This script can be run from the host machine via cron to trigger certificate renewal
|
||||
# inside the HAProxy Manager container using docker exec
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration - Customize these values
|
||||
CONTAINER_NAME="${CONTAINER_NAME:-haproxy-manager}"
|
||||
LOG_FILE="${LOG_FILE:-/var/log/haproxy-manager-host-renewal.log}"
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $*" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $*" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
log_info "Starting host-side certificate renewal process"
|
||||
|
||||
# Check if container is running
|
||||
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
||||
log_error "Container '${CONTAINER_NAME}' is not running"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Execute renewal script inside container
|
||||
log_info "Executing renewal script in container '${CONTAINER_NAME}'"
|
||||
if docker exec "$CONTAINER_NAME" /haproxy/scripts/renew-certificates.sh; then
|
||||
log_info "Certificate renewal completed successfully"
|
||||
exit 0
|
||||
else
|
||||
log_error "Certificate renewal failed"
|
||||
exit 1
|
||||
fi
|
||||
109
scripts/renew-certificates.sh
Normal file
109
scripts/renew-certificates.sh
Normal file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Certificate Renewal Script for HAProxy Manager
|
||||
# This script handles Let's Encrypt certificate renewal with proper logging and error handling
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
LOG_FILE="${LOG_FILE:-/var/log/haproxy-manager.log}"
|
||||
ERROR_LOG_FILE="${ERROR_LOG_FILE:-/var/log/haproxy-manager-errors.log}"
|
||||
HAPROXY_SOCKET="${HAPROXY_SOCKET:-/tmp/haproxy-cli}"
|
||||
MAX_RETRIES=3
|
||||
RETRY_DELAY=5
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $*" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $*" | tee -a "$LOG_FILE" >> "$ERROR_LOG_FILE"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [WARNING] $*" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Check if certbot is available
|
||||
if ! command -v certbot &> /dev/null; then
|
||||
log_error "certbot command not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if HAProxy socket exists and is accessible
|
||||
check_haproxy_socket() {
|
||||
if [ ! -S "$HAPROXY_SOCKET" ]; then
|
||||
log_warning "HAProxy socket not found at $HAPROXY_SOCKET"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Test socket connectivity
|
||||
if ! echo "show info" | socat stdio "$HAPROXY_SOCKET" &> /dev/null; then
|
||||
log_warning "HAProxy socket exists but is not responding"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Reload HAProxy configuration
|
||||
reload_haproxy() {
|
||||
local retry_count=0
|
||||
|
||||
while [ $retry_count -lt $MAX_RETRIES ]; do
|
||||
if check_haproxy_socket; then
|
||||
log_info "Reloading HAProxy via socket"
|
||||
if echo "reload" | socat stdio "$HAPROXY_SOCKET"; then
|
||||
log_info "HAProxy reloaded successfully"
|
||||
return 0
|
||||
else
|
||||
log_warning "HAProxy reload command failed (attempt $((retry_count + 1))/$MAX_RETRIES)"
|
||||
fi
|
||||
else
|
||||
log_warning "HAProxy socket check failed (attempt $((retry_count + 1))/$MAX_RETRIES)"
|
||||
fi
|
||||
|
||||
retry_count=$((retry_count + 1))
|
||||
if [ $retry_count -lt $MAX_RETRIES ]; then
|
||||
sleep $RETRY_DELAY
|
||||
fi
|
||||
done
|
||||
|
||||
log_error "Failed to reload HAProxy after $MAX_RETRIES attempts"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Main renewal process
|
||||
log_info "Starting certificate renewal process"
|
||||
|
||||
# Run certbot renewal
|
||||
if certbot renew --quiet --no-random-sleep-on-renew 2>&1 | tee -a "$LOG_FILE"; then
|
||||
RENEWAL_EXIT_CODE=${PIPESTATUS[0]}
|
||||
|
||||
if [ $RENEWAL_EXIT_CODE -eq 0 ]; then
|
||||
log_info "Certificate renewal completed successfully"
|
||||
|
||||
# Check if any certificates were actually renewed
|
||||
if grep -q "Cert not yet due for renewal" "$LOG_FILE" 2>/dev/null; then
|
||||
log_info "No certificates needed renewal at this time"
|
||||
else
|
||||
log_info "Certificates were renewed, reloading HAProxy"
|
||||
if reload_haproxy; then
|
||||
log_info "Certificate renewal and HAProxy reload completed successfully"
|
||||
else
|
||||
log_error "Certificate renewal succeeded but HAProxy reload failed"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
log_error "Certificate renewal failed with exit code $RENEWAL_EXIT_CODE"
|
||||
exit $RENEWAL_EXIT_CODE
|
||||
fi
|
||||
else
|
||||
log_error "Certificate renewal command failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Certificate renewal process completed"
|
||||
exit 0
|
||||
Reference in New Issue
Block a user