# Hexo Blog Container v0.0.4 - Enhanced Production Version # # This version includes optimizations based on v0.0.3-fixed testing results: # - Improved layer caching for faster rebuilds # - Enhanced security configurations # - Better resource management # - Optional SSL support preparation # - Monitoring improvements # # Author: AI Assistant # Version: 0.0.4 # Date: 2025-05-29 # ---- Build Arguments ---- ARG UBUNTU_VERSION=22.04 ARG TZ=Asia/Shanghai ARG PUID=1000 ARG PGID=1000 ARG NGINX_VERSION=1.18.0 # ---- Stage 1: Base Dependencies ---- FROM ubuntu:${UBUNTU_VERSION} AS base ARG TZ ENV DEBIAN_FRONTEND=noninteractive ENV TZ=${TZ} ENV LANG=zh_CN.UTF-8 # Configure timezone first (improves caching) RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && \ echo $TZ > /etc/timezone # Configure optimized Chinese mirrors for enhanced reliability RUN cp /etc/apt/sources.list /etc/apt/sources.list.backup && \ printf '%s\n' \ '# Optimized Tsinghua University mirror sources with fallback' \ 'deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse' \ 'deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse' \ 'deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse' \ 'deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse' \ '# Fallback to official sources' \ '# deb http://archive.ubuntu.com/ubuntu/ jammy main restricted universe multiverse' \ > /etc/apt/sources.list # Install base system packages with enhanced retry mechanism RUN for i in 1 2 3; do \ echo "Base packages attempt $i..." && \ apt-get clean && \ apt-get update --fix-missing && \ apt-get install -y --no-install-recommends --fix-missing \ ca-certificates \ curl \ wget \ gnupg \ lsb-release && \ echo "Base packages installation successful" && \ break || { \ echo "Attempt $i failed, waiting 10 seconds..."; \ sleep 10; \ }; \ done # ---- Stage 2: Runtime Dependencies ---- FROM base AS runtime-deps # Install runtime packages in optimized order (most stable first) RUN for i in 1 2 3; do \ echo "Runtime packages attempt $i..." && \ apt-get update --fix-missing && \ apt-get install -y --no-install-recommends --fix-missing \ # Core system locales \ tzdata \ # Git and SSH git \ openssh-server \ # Web server nginx-full \ # Utilities gettext-base \ supervisor \ logrotate \ # Monitoring tools htop \ iotop \ # Security tools fail2ban && \ echo "Runtime packages installation successful" && \ break || { \ echo "Runtime attempt $i failed, waiting 15 seconds..."; \ sleep 15; \ }; \ done && \ # Configure locale sed -i 's/# zh_CN.UTF-8 UTF-8/zh_CN.UTF-8 UTF-8/' /etc/locale.gen && \ locale-gen && \ update-locale LANG=zh_CN.UTF-8 && \ # Clean up apt-get autoremove -y && \ apt-get autoclean && \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* # ---- Stage 3: Configuration Builder ---- FROM runtime-deps AS config-builder # Create directory structure RUN mkdir -p /etc/container/{templates,ssl,monitoring} && \ mkdir -p /app/scripts && \ mkdir -p /home/hexo && \ mkdir -p /var/log/container && \ mkdir -p /backup # Create enhanced Git repository with improved hooks RUN git init --bare /home/hexo/hexo.git && \ git config --global init.defaultBranch main # Create enhanced post-receive hook with better error handling and monitoring RUN printf '%s\n' \ '#!/bin/bash' \ 'set -euo pipefail' \ '' \ '# Enhanced post-receive hook with monitoring and error recovery' \ '# Version: 0.0.4 - Production ready with enhanced logging' \ '' \ 'readonly LOG_FILE="/var/log/container/deployment.log"' \ 'readonly DEPLOY_TIME=$(date "+%%Y-%%m-%%d %%H:%%M:%%S")' \ 'readonly TARGET_DIR="/home/www/hexo"' \ 'readonly BACKUP_DIR="/backup/auto"' \ '' \ 'log_deploy() {' \ ' local message="[$DEPLOY_TIME] $*"' \ ' echo "$message"' \ ' if [[ -w "/var/log/container" ]] || [[ -w "$LOG_FILE" ]]; then' \ ' echo "$message" >> "$LOG_FILE"' \ ' fi' \ ' # Send to syslog for monitoring' \ ' logger -t "hexo-deploy" "$message"' \ '}' \ '' \ 'create_backup() {' \ ' if [[ -d "$TARGET_DIR" ]] && [[ "$(ls -A "$TARGET_DIR")" ]]; then' \ ' mkdir -p "$BACKUP_DIR"' \ ' local backup_name="backup-$(date +%%Y%%m%%d-%%H%%M%%S)"' \ ' tar -czf "$BACKUP_DIR/$backup_name.tar.gz" -C "$TARGET_DIR" . 2>/dev/null || true' \ ' # Keep only last 5 backups' \ ' ls -t "$BACKUP_DIR"/backup-*.tar.gz 2>/dev/null | tail -n +6 | xargs -r rm -f' \ ' log_deploy "[BACKUP] Created: $backup_name.tar.gz"' \ ' fi' \ '}' \ '' \ 'rollback_on_error() {' \ ' log_deploy "[ERROR] Deployment failed, attempting rollback..."' \ ' local latest_backup=$(ls -t "$BACKUP_DIR"/backup-*.tar.gz 2>/dev/null | head -n1)' \ ' if [[ -n "$latest_backup" ]]; then' \ ' rm -rf "$TARGET_DIR"/* 2>/dev/null || true' \ ' tar -xzf "$latest_backup" -C "$TARGET_DIR" 2>/dev/null && \ ' log_deploy "[ROLLBACK] Restored from: $(basename "$latest_backup")" || \ ' log_deploy "[ROLLBACK] Failed to restore backup"' \ ' fi' \ '}' \ '' \ '# Main deployment process' \ 'trap rollback_on_error ERR' \ '' \ 'log_deploy "=== Git Push Deployment Started ==="' \ '' \ '# Create backup before deployment' \ 'create_backup' \ '' \ '# Ensure target directory exists' \ 'mkdir -p "$TARGET_DIR"' \ 'log_deploy "Target directory prepared: $TARGET_DIR"' \ '' \ '# Checkout files' \ 'if git --git-dir=/home/hexo/hexo.git --work-tree="$TARGET_DIR" checkout -f; then' \ ' log_deploy "[SUCCESS] Files checked out successfully"' \ 'else' \ ' log_deploy "[FAIL] Failed to checkout files"' \ ' exit 1' \ 'fi' \ '' \ '# Set proper ownership and permissions' \ 'chown -R hexo:hexo "$TARGET_DIR" 2>/dev/null || true' \ 'find "$TARGET_DIR" -type f -exec chmod 644 {} \\;' \ 'find "$TARGET_DIR" -type d -exec chmod 755 {} \\;' \ 'log_deploy "[SUCCESS] Permissions updated"' \ '' \ '# Check for special files and handle them' \ 'if [[ -f "$TARGET_DIR/nginx.conf" ]]; then' \ ' log_deploy "[CONFIG] Custom nginx.conf detected - reload required"' \ ' touch /tmp/nginx-reload-required' \ 'fi' \ '' \ 'if [[ -f "$TARGET_DIR/.env" ]]; then' \ ' log_deploy "[CONFIG] Environment file detected"' \ ' chmod 600 "$TARGET_DIR/.env"' \ 'fi' \ '' \ '# Update deployment timestamp' \ 'echo "$DEPLOY_TIME" > "$TARGET_DIR/.deployment-timestamp"' \ '' \ 'log_deploy "=== Git Push Deployment Completed Successfully ==="' \ 'log_deploy "Files deployed: $(find "$TARGET_DIR" -type f | wc -l)"' \ 'log_deploy ""' > /home/hexo/hexo.git/hooks/post-receive RUN chmod +x /home/hexo/hexo.git/hooks/post-receive # Create enhanced SSH configuration with fail2ban integration RUN printf '%s\n' \ '# Enhanced SSH Configuration for Hexo Blog Container v0.0.4' \ '# Production-ready with security hardening and monitoring' \ 'Port 22' \ 'ListenAddress 0.0.0.0' \ 'ListenAddress ::' \ '' \ '# Protocol and Authentication' \ 'Protocol 2' \ 'PermitRootLogin no' \ 'PasswordAuthentication no' \ 'PubkeyAuthentication yes' \ 'AuthorizedKeysFile .ssh/authorized_keys' \ 'PermitEmptyPasswords no' \ 'ChallengeResponseAuthentication no' \ '' \ '# Security Settings' \ 'MaxAuthTries 3' \ 'MaxSessions 5' \ 'MaxStartups 2:30:10' \ 'LoginGraceTime 30' \ 'ClientAliveInterval 300' \ 'ClientAliveCountMax 2' \ '' \ '# Access Control' \ 'AllowUsers hexo' \ 'DenyUsers root' \ 'DenyGroups root' \ '' \ '# Features' \ 'X11Forwarding no' \ 'AllowTcpForwarding yes' \ 'GatewayPorts no' \ 'PermitTunnel no' \ 'UsePAM yes' \ 'PrintMotd no' \ 'TCPKeepAlive yes' \ '' \ '# Logging and Monitoring' \ 'SyslogFacility AUTH' \ 'LogLevel VERBOSE' \ '' \ '# File transfer' \ 'Subsystem sftp internal-sftp' \ '' \ '# Banner' \ 'Banner /etc/ssh/banner.txt' > /etc/container/templates/sshd_config.template # Create SSH banner RUN printf '%s\n' \ '*****************************************************' \ '* Hexo Blog Docker Container - Authorized Access *' \ '* Version: 0.0.4 - Production Environment *' \ '* Monitoring: Active | Logging: Enabled *' \ '*****************************************************' \ '' > /etc/container/templates/banner.txt # Create enhanced Nginx configuration with performance optimizations RUN printf '%s\n' \ '# Enhanced Nginx Configuration for Hexo Blog Container v0.0.4' \ '# Optimized for performance, security, and monitoring' \ '' \ 'user hexo;' \ 'worker_processes auto;' \ 'worker_rlimit_nofile 65535;' \ 'pid /var/run/nginx.pid;' \ '' \ 'events {' \ ' worker_connections 4096;' \ ' use epoll;' \ ' multi_accept on;' \ ' accept_mutex off;' \ '}' \ '' \ 'http {' \ ' # Basic Settings' \ ' sendfile on;' \ ' tcp_nopush on;' \ ' tcp_nodelay on;' \ ' keepalive_timeout 65;' \ ' keepalive_requests 1000;' \ ' reset_timedout_connection on;' \ ' types_hash_max_size 2048;' \ ' server_tokens off;' \ ' client_max_body_size 10m;' \ ' client_body_buffer_size 128k;' \ ' client_header_buffer_size 1k;' \ ' large_client_header_buffers 4 8k;' \ ' client_body_timeout 12;' \ ' client_header_timeout 12;' \ ' send_timeout 10;' \ ' ' \ ' # MIME' \ ' include /etc/nginx/mime.types;' \ ' default_type application/octet-stream;' \ ' ' \ ' # Logging Format' \ ' log_format main '\''$remote_addr - $remote_user [$time_local] "$request" '\'' \ ' '\''$status $body_bytes_sent "$http_referer" '\'' \ ' '\''"$http_user_agent" "$http_x_forwarded_for"'\'';' \ ' ' \ ' log_format detailed '\''$remote_addr - $remote_user [$time_local] '\'' \ ' '\''"$request" $status $body_bytes_sent '\'' \ ' '\''"$http_referer" "$http_user_agent" '\'' \ ' '\''rt=$request_time uct="$upstream_connect_time" '\'' \ ' '\''uht="$upstream_header_time" urt="$upstream_response_time"'\'';' \ ' ' \ ' access_log /var/log/nginx/access.log main;' \ ' error_log /var/log/nginx/error.log warn;' \ ' ' \ ' # Gzip Compression' \ ' gzip on;' \ ' gzip_vary on;' \ ' gzip_min_length 1000;' \ ' gzip_proxied any;' \ ' gzip_comp_level 6;' \ ' gzip_types' \ ' application/atom+xml' \ ' application/geo+json' \ ' application/javascript' \ ' application/x-javascript' \ ' application/json' \ ' application/ld+json' \ ' application/manifest+json' \ ' application/rdf+xml' \ ' application/rss+xml' \ ' application/xhtml+xml' \ ' application/xml' \ ' font/eot' \ ' font/otf' \ ' font/ttf' \ ' image/svg+xml' \ ' text/css' \ ' text/javascript' \ ' text/plain' \ ' text/xml;' \ ' ' \ ' # Security Headers' \ ' add_header X-Frame-Options "SAMEORIGIN" always;' \ ' add_header X-Content-Type-Options "nosniff" always;' \ ' add_header X-XSS-Protection "1; mode=block" always;' \ ' add_header Referrer-Policy "strict-origin-when-cross-origin" always;' \ ' add_header Content-Security-Policy "default-src '\''self'\''; script-src '\''self'\''; style-src '\''self'\'' '\''unsafe-inline'\''; img-src '\''self'\'' data: https:; font-src '\''self'\''; connect-src '\''self'\''; frame-ancestors '\''self'\''" always;' \ ' ' \ ' # Rate Limiting' \ ' limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;' \ ' limit_req_zone $binary_remote_addr zone=strict:10m rate=2r/s;' \ ' ' \ ' # Cache for static assets' \ ' map $sent_http_content_type $expires {' \ ' default off;' \ ' text/html 1h;' \ ' text/css 1y;' \ ' application/javascript 1y;' \ ' ~image/ 1y;' \ ' ~font/ 1y;' \ ' }' \ ' ' \ ' expires $expires;' \ ' ' \ ' # Main server block' \ ' server {' \ ' listen 80 default_server;' \ ' listen [::]:80 default_server;' \ ' server_name _;' \ ' root /home/www/hexo;' \ ' index index.html index.htm;' \ ' ' \ ' # Rate limiting for general requests' \ ' limit_req zone=general burst=20 nodelay;' \ ' ' \ ' # Health check endpoint (no rate limiting)' \ ' location = /health {' \ ' access_log off;' \ ' return 200 "healthy\\n";' \ ' add_header Content-Type text/plain;' \ ' add_header X-Health-Check "ok";' \ ' }' \ ' ' \ ' # Monitoring endpoint (restricted)' \ ' location = /status {' \ ' limit_req zone=strict burst=5;' \ ' access_log off;' \ ' return 200 "{\\"status\\":\\"ok\\",\\"version\\":\\"0.0.4\\",\\"timestamp\\":\\"$(date -Iseconds)\\"}\\n";' \ ' add_header Content-Type application/json;' \ ' }' \ ' ' \ ' # Main content location' \ ' location / {' \ ' try_files $uri $uri/ /index.html;' \ ' ' \ ' # Cache control for HTML files' \ ' location ~* \\.html$ {' \ ' add_header Cache-Control "public, no-cache, must-revalidate";' \ ' }' \ ' }' \ ' ' \ ' # Static assets with aggressive caching' \ ' location ~* \\.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {' \ ' expires 1y;' \ ' add_header Cache-Control "public, immutable";' \ ' add_header Vary "Accept-Encoding";' \ ' ' \ ' # Optional: serve pre-compressed files' \ ' location ~* \\.(css|js)$ {' \ ' gzip_static on;' \ ' }' \ ' }' \ ' ' \ ' # Security - Block hidden files and sensitive files' \ ' location ~ /\\. {' \ ' deny all;' \ ' access_log off;' \ ' log_not_found off;' \ ' }' \ ' ' \ ' location ~* \\.(sql|log|env|config)$ {' \ ' deny all;' \ ' access_log off;' \ ' log_not_found off;' \ ' }' \ ' ' \ ' # Block unwanted bots' \ ' location ~* (wp-admin|wp-login|xmlrpc|admin|login) {' \ ' deny all;' \ ' access_log off;' \ ' log_not_found off;' \ ' }' \ ' ' \ ' # Custom error pages' \ ' error_page 404 /404.html;' \ ' error_page 500 502 503 504 /50x.html;' \ ' ' \ ' location = /404.html {' \ ' internal;' \ ' }' \ ' ' \ ' location = /50x.html {' \ ' internal;' \ ' }' \ ' }' \ '}' > /etc/container/templates/nginx.conf.template # Create Supervisor configuration for process management RUN printf '%s\n' \ '[supervisord]' \ 'nodaemon=true' \ 'pidfile=/var/run/supervisord.pid' \ 'logfile=/var/log/container/supervisord.log' \ 'logfile_maxbytes=50MB' \ 'logfile_backups=10' \ 'loglevel=info' \ '' \ '[program:sshd]' \ 'command=/usr/sbin/sshd -D' \ 'autostart=true' \ 'autorestart=true' \ 'stderr_logfile=/var/log/container/sshd.err.log' \ 'stdout_logfile=/var/log/container/sshd.out.log' \ 'user=root' \ '' \ '[program:nginx]' \ 'command=nginx -g "daemon off;"' \ 'autostart=true' \ 'autorestart=true' \ 'stderr_logfile=/var/log/container/nginx.err.log' \ 'stdout_logfile=/var/log/container/nginx.out.log' \ 'user=root' \ '' \ '[program:log-rotator]' \ 'command=/app/scripts/log-rotator.sh' \ 'autostart=true' \ 'autorestart=true' \ 'stderr_logfile=/var/log/container/log-rotator.err.log' \ 'stdout_logfile=/var/log/container/log-rotator.out.log' \ 'user=root' > /etc/container/templates/supervisord.conf.template # Copy start script COPY start.sh /app/start.sh # ---- Stage 4: Production Runtime ---- FROM config-builder AS production ARG PUID ARG PGID ENV PUID=${PUID} ENV PGID=${PGID} ENV SUPERVISOR_ENABLED=true # Copy configuration templates and scripts COPY --from=config-builder /etc/container/templates /etc/container/templates/ COPY --from=config-builder /home/hexo/hexo.git /home/hexo/hexo.git # Create enhanced startup scripts RUN printf '%s\n' \ '#!/bin/bash' \ '# Log rotation script for Hexo Blog Container' \ 'set -euo pipefail' \ '' \ 'while true; do' \ ' # Rotate deployment logs' \ ' if [[ -f "/var/log/container/deployment.log" ]] && [[ $(stat -f "%%z" "/var/log/container/deployment.log" 2>/dev/null || stat -c "%%s" "/var/log/container/deployment.log") -gt 10485760 ]]; then' \ ' mv "/var/log/container/deployment.log" "/var/log/container/deployment.log.$(date +%%Y%%m%%d-%%H%%M%%S)"' \ ' touch "/var/log/container/deployment.log"' \ ' chown hexo:hexo "/var/log/container/deployment.log"' \ ' # Keep only last 5 log files' \ ' ls -t /var/log/container/deployment.log.* 2>/dev/null | tail -n +6 | xargs -r rm -f' \ ' fi' \ ' ' \ ' # Sleep for 1 hour' \ ' sleep 3600' \ 'done' > /app/scripts/log-rotator.sh RUN chmod +x /app/scripts/log-rotator.sh # Create hexo user with proper UID/GID RUN groupadd -g ${PGID} hexo && \ useradd -r -u ${PUID} -g hexo -d /home/hexo -s /bin/bash hexo && \ mkdir -p /home/hexo/.ssh && \ mkdir -p /home/www/hexo && \ chown -R hexo:hexo /home/hexo && \ chown -R hexo:hexo /home/www/hexo # Set up logging and permissions RUN mkdir -p /var/run/sshd && \ chmod +x /app/start.sh && \ chmod +x /home/hexo/hexo.git/hooks/post-receive && \ mkdir -p /var/log/container && \ chown hexo:hexo /var/log/container && \ chmod 755 /var/log/container && \ mkdir -p /backup/auto && \ chown hexo:hexo /backup && \ chmod 755 /backup # Configure SSH with enhanced security RUN mkdir -p /root/.ssh && \ chmod 700 /root/.ssh # Remove default nginx configurations to prevent conflicts RUN rm -f /etc/nginx/sites-enabled/default && \ rm -f /etc/nginx/sites-available/default && \ rm -f /etc/nginx/conf.d/default.conf # Configure fail2ban for SSH protection RUN printf '%s\n' \ '[sshd]' \ 'enabled = true' \ 'port = ssh' \ 'filter = sshd' \ 'logpath = /var/log/auth.log' \ 'maxretry = 3' \ 'bantime = 3600' \ 'findtime = 600' > /etc/fail2ban/jail.local # Create default index page with version info RUN printf '%s\n' \ '' \ '' \ '
' \ ' ' \ ' ' \ '高性能博客容器 - 生产就绪版本
' \ 'Version: 0.0.4-enhanced
' \ 'Status: 🟢 Running
' \ 'Build Date: 2025-05-29
' \ 'Nginx with performance optimizations
' \ 'Secure key-based authentication
' \ 'Automated deployment with backup
' \ 'Health checks and logging
' \ '