651 lines
22 KiB
Groff
651 lines
22 KiB
Groff
# 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' \
|
|
'<!DOCTYPE html>' \
|
|
'<html lang="zh-CN">' \
|
|
'<head>' \
|
|
' <meta charset="UTF-8">' \
|
|
' <meta name="viewport" content="width=device-width, initial-scale=1.0">' \
|
|
' <title>Hexo Blog Docker v0.0.4</title>' \
|
|
' <style>' \
|
|
' body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; margin: 0; padding: 40px; background: linear-gradient(135deg, #667eea 0%%, #764ba2 100%%); color: white; }' \
|
|
' .container { max-width: 800px; margin: 0 auto; text-align: center; }' \
|
|
' .header { margin-bottom: 40px; }' \
|
|
' .version { background: rgba(255,255,255,0.1); padding: 20px; border-radius: 10px; margin: 20px 0; }' \
|
|
' .features { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin: 40px 0; }' \
|
|
' .feature { background: rgba(255,255,255,0.1); padding: 20px; border-radius: 10px; }' \
|
|
' .footer { margin-top: 40px; opacity: 0.8; }' \
|
|
' a { color: #ffeb3b; text-decoration: none; }' \
|
|
' a:hover { text-decoration: underline; }' \
|
|
' </style>' \
|
|
'</head>' \
|
|
'<body>' \
|
|
' <div class="container">' \
|
|
' <div class="header">' \
|
|
' <h1>🚀 Hexo Blog Docker</h1>' \
|
|
' <p>高性能博客容器 - 生产就绪版本</p>' \
|
|
' </div>' \
|
|
' ' \
|
|
' <div class="version">' \
|
|
' <h2>版本信息</h2>' \
|
|
' <p><strong>Version:</strong> 0.0.4-enhanced</p>' \
|
|
' <p><strong>Status:</strong> 🟢 Running</p>' \
|
|
' <p><strong>Build Date:</strong> 2025-05-29</p>' \
|
|
' </div>' \
|
|
' ' \
|
|
' <div class="features">' \
|
|
' <div class="feature">' \
|
|
' <h3>🌐 Web Server</h3>' \
|
|
' <p>Nginx with performance optimizations</p>' \
|
|
' </div>' \
|
|
' <div class="feature">' \
|
|
' <h3>🔐 SSH Access</h3>' \
|
|
' <p>Secure key-based authentication</p>' \
|
|
' </div>' \
|
|
' <div class="feature">' \
|
|
' <h3>📦 Git Deploy</h3>' \
|
|
' <p>Automated deployment with backup</p>' \
|
|
' </div>' \
|
|
' <div class="feature">' \
|
|
' <h3>📊 Monitoring</h3>' \
|
|
' <p>Health checks and logging</p>' \
|
|
' </div>' \
|
|
' </div>' \
|
|
' ' \
|
|
' <div class="footer">' \
|
|
' <p>Ready for your content! Deploy via Git push to get started.</p>' \
|
|
' <p><a href="/health">Health Check</a> | <a href="/status">Status API</a></p>' \
|
|
' </div>' \
|
|
' </div>' \
|
|
'</body>' \
|
|
'</html>' > /home/www/hexo/index.html
|
|
|
|
# Expose ports
|
|
EXPOSE 80 22
|
|
|
|
# Enhanced health check with multiple endpoints
|
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
|
|
CMD curl -f http://localhost/health && \
|
|
curl -f http://localhost/status && \
|
|
pgrep nginx > /dev/null && \
|
|
pgrep sshd > /dev/null || exit 1
|
|
|
|
# Set proper ownership for all files
|
|
RUN chown -R hexo:hexo /home/www/hexo /home/hexo
|
|
|
|
# Start with enhanced process management
|
|
CMD ["/app/start.sh"]
|
|
|
|
# Labels for metadata
|
|
LABEL maintainer="AI Assistant" \
|
|
version="0.0.4" \
|
|
description="Enhanced Hexo Blog Docker Container with monitoring and security" \
|
|
org.opencontainers.image.title="Hexo Blog Docker" \
|
|
org.opencontainers.image.description="Production-ready Hexo blog container with Nginx, SSH, and Git deployment" \
|
|
org.opencontainers.image.version="0.0.4" \
|
|
org.opencontainers.image.created="2025-05-29" \
|
|
org.opencontainers.image.vendor="AI Assistant" \
|
|
org.opencontainers.image.licenses="MIT"
|