Files
hexo-deploy/arch/origin/Dockerfile.improved
2025-06-02 11:27:10 +08:00

350 lines
10 KiB
Docker

# ---- Stage 1: Builder/Base ----
# This stage sets up the base environment, installs build tools, creates scripts and templates
FROM ubuntu:22.04 AS builder
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Shanghai
# Set the timezone
RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone
# Install all required packages in a single layer
RUN apt-get update && \
apt-get install -y --no-install-recommends \
locales \
git \
nginx-full \
gettext-base && \
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 && \
rm -rf /var/lib/apt/lists/*
# Create non-root user for security
RUN groupadd -r hexo && useradd -r -g hexo -d /home/hexo -s /bin/bash hexo
# Make essential directories for artifacts
RUN mkdir -p /root/hexo.git/hooks && \
mkdir -p /etc/container/templates && \
mkdir -p /app && \
mkdir -p /home/hexo
# Configure git hook with proper permissions
RUN git init --bare /home/hexo/hexo.git && \
echo "#!/bin/bash" > /home/hexo/hexo.git/hooks/post-receive && \
echo "git --work-tree=/home/www/hexo --git-dir=/home/hexo/hexo.git checkout -f" >> /home/hexo/hexo.git/hooks/post-receive && \
echo "chown -R hexo:hexo /home/www/hexo" >> /home/hexo/hexo.git/hooks/post-receive && \
chmod +x /home/hexo/hexo.git/hooks/post-receive && \
chown -R hexo:hexo /home/hexo/hexo.git
# Backup original nginx.conf
RUN cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
# Create improved SSH Config Template
RUN echo 'Port ${SSH_PORT:-22}' > /etc/container/templates/sshd_config.template && \
echo 'ListenAddress 0.0.0.0' >> /etc/container/templates/sshd_config.template && \
echo 'ListenAddress ::' >> /etc/container/templates/sshd_config.template && \
echo 'PermitRootLogin ${PERMIT_ROOT_LOGIN:-no}' >> /etc/container/templates/sshd_config.template && \
echo 'PubkeyAuthentication yes' >> /etc/container/templates/sshd_config.template && \
echo 'AuthorizedKeysFile .ssh/authorized_keys' >> /etc/container/templates/sshd_config.template && \
echo 'PasswordAuthentication no' >> /etc/container/templates/sshd_config.template && \
echo 'ChallengeResponseAuthentication no' >> /etc/container/templates/sshd_config.template && \
echo 'UsePAM yes' >> /etc/container/templates/sshd_config.template && \
echo 'X11Forwarding no' >> /etc/container/templates/sshd_config.template && \
echo 'PrintMotd no' >> /etc/container/templates/sshd_config.template && \
echo 'AcceptEnv LANG LC_*' >> /etc/container/templates/sshd_config.template && \
echo 'Subsystem sftp /usr/lib/openssh/sftp-server' >> /etc/container/templates/sshd_config.template && \
echo 'AllowUsers hexo' >> /etc/container/templates/sshd_config.template
# Create Nginx Config Template with security headers
RUN cat > /etc/container/templates/nginx.conf.template << 'EOF'
# Nginx Configuration Template
user ${NGINX_USER:-hexo};
worker_processes ${NGINX_WORKERS:-auto};
pid /var/run/nginx.pid;
events {
worker_connections ${NGINX_CONNECTIONS:-1024};
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Performance
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
server {
listen ${HTTP_PORT:-80};
server_name ${SERVER_NAME:-localhost};
root ${WEB_ROOT:-/home/www/hexo};
index index.html index.htm;
# Security
server_tokens off;
location / {
try_files $uri $uri/ =404;
}
# Static files caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
}
EOF
# Create improved start script
RUN cat > /app/start.sh << 'EOF'
#!/bin/bash
# Color definitions
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Log file and rotation settings
LOG_DIR="/var/log/container"
LOG_FILE="$LOG_DIR/services.log"
MAX_LOG_SIZE=10485760 # 10MB
# --- Logging functions ---
_log() {
local level_color=$1
local level_name=$2
shift 2
echo -e "${level_color}[${level_name}]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $@"
}
log_info() { _log "$BLUE" "INFO" "$@"; }
log_success() { _log "$GREEN" "SUCCESS" "$@"; }
log_warning() { _log "$YELLOW" "WARNING" "$@"; }
log_error() { _log "$RED" "ERROR" "$@"; }
# --- Setup logging ---
setup_logging() {
mkdir -p "$LOG_DIR"
touch "$LOG_FILE"
log_info "Logging to console and $LOG_FILE"
exec > >(tee -a "$LOG_FILE") 2> >(tee -a "$LOG_FILE" >&2)
}
# --- Render configuration files ---
render_config() {
log_info "Rendering configuration templates..."
local rendered=0
if envsubst < /etc/container/templates/sshd_config.template > /etc/ssh/sshd_config; then
log_success "SSHD configuration rendered"; ((rendered++))
else
log_error "Failed to render SSHD configuration";
fi
if envsubst < /etc/container/templates/nginx.conf.template > /etc/nginx/nginx.conf; then
log_success "Nginx configuration rendered"; ((rendered++))
else
log_error "Failed to render Nginx configuration";
fi
if [ "$rendered" -eq 2 ]; then
log_success "All configuration files rendered"
return 0
else
log_error "Failed to render some configuration files"
return 1
fi
}
# --- Start services ---
start_services() {
log_info "Starting SSH service..."
if [ ! -f "/etc/ssh/ssh_host_rsa_key" ]; then
log_info "Generating SSH host keys..."
ssh-keygen -A
fi
/usr/sbin/sshd -D &
SSH_PID=$!
log_info "Starting Nginx service..."
nginx -g "daemon off;" &
NGINX_PID=$!
sleep 2
if kill -0 $SSH_PID 2>/dev/null && kill -0 $NGINX_PID 2>/dev/null; then
log_success "All services started successfully"
return 0
else
log_error "Failed to start some services"
return 1
fi
}
# --- Monitor services ---
monitor_services() {
log_info "Starting service monitoring..."
while true; do
sleep 30
if ! kill -0 $SSH_PID 2>/dev/null; then
log_error "SSH service stopped, attempting restart..."
/usr/sbin/sshd -D &
SSH_PID=$!
fi
if ! kill -0 $NGINX_PID 2>/dev/null; then
log_error "Nginx service stopped, attempting restart..."
nginx -g "daemon off;" &
NGINX_PID=$!
fi
done
}
# --- Cleanup function ---
cleanup() {
log_info "Received shutdown signal, gracefully stopping services..."
if [ ! -z "$NGINX_PID" ] && kill -0 $NGINX_PID 2>/dev/null; then
log_info "Stopping Nginx (PID:$NGINX_PID)"
kill -TERM $NGINX_PID
wait $NGINX_PID 2>/dev/null
log_success "Nginx stopped"
fi
if [ ! -z "$SSH_PID" ] && kill -0 $SSH_PID 2>/dev/null; then
log_info "Stopping SSH (PID:$SSH_PID)"
kill -TERM $SSH_PID
wait $SSH_PID 2>/dev/null
log_success "SSH stopped"
fi
log_info "Container shutdown complete"
exit 0
}
trap cleanup SIGTERM SIGINT
# --- Main execution ---
main() {
setup_logging
log_info "===== Container Starting ====="
log_info "Time: $(date)"
log_info "Timezone: $TZ"
log_info "User: $(whoami)"
if ! render_config; then
log_error "Configuration rendering failed"
exit 1
fi
if ! /usr/sbin/sshd -t; then
log_error "SSH configuration test failed"
exit 1
fi
if ! nginx -t; then
log_error "Nginx configuration test failed"
exit 1
fi
if ! start_services; then
exit 1
fi
log_success "===== All services started successfully ====="
monitor_services
}
main
EOF
RUN chmod +x /app/start.sh
# ---- Stage 2: Production ----
# This stage builds the final runtime image with only necessary dependencies
FROM ubuntu:22.04 AS production
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Shanghai
ENV PUID=1000
ENV PGID=1000
ENV LANG=zh_CN.UTF-8
# Copy timezone and locale settings from builder
COPY --from=builder /etc/localtime /etc/localtime
COPY --from=builder /etc/timezone /etc/timezone
COPY --from=builder /usr/lib/locale/zh_CN.utf8 /usr/lib/locale/zh_CN.utf8/
COPY --from=builder /etc/default/locale /etc/default/locale
# Install only runtime dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
openssh-server \
git \
nginx-full \
gettext-base \
curl && \
rm -rf /var/lib/apt/lists/*
# Create hexo user
RUN groupadd -r hexo && \
useradd -r -g hexo -d /home/hexo -s /bin/bash hexo
# Create necessary directories
RUN mkdir -p /home/hexo/.ssh && \
mkdir -p /home/www/hexo && \
mkdir -p /home/www/ssl && \
mkdir -p /var/run/sshd && \
mkdir -p /var/log/container && \
mkdir -p /var/log/nginx
# Copy artifacts from builder stage
COPY --from=builder /home/hexo/hexo.git /home/hexo/hexo.git
COPY --from=builder /etc/container/templates /etc/container/templates/
COPY --from=builder /app/start.sh /root/start.sh
COPY --from=builder /etc/nginx/nginx.conf.bak /etc/nginx/nginx.conf.bak
# Set proper permissions
RUN chmod +x /root/start.sh && \
chmod +x /home/hexo/hexo.git/hooks/post-receive && \
chown -R hexo:hexo /home/www/hexo && \
chown -R hexo:hexo /home/hexo && \
chmod -R 755 /home/www/hexo && \
chmod 700 /home/hexo/.ssh
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost/ || exit 1
VOLUME ["/home/www/hexo", "/home/hexo/.ssh", "/home/www/ssl", "/home/hexo/hexo.git", "/var/log/container", "/var/log/nginx"]
EXPOSE 22 80 443
CMD ["/root/start.sh"]