v0.0.3 published
This commit is contained in:
202
arch/Dockerfile_v0.0.1
Normal file
202
arch/Dockerfile_v0.0.1
Normal file
@@ -0,0 +1,202 @@
|
||||
# ---- 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 /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 using multiple echo commands
|
||||
|
||||
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 using printf
|
||||
|
||||
RUN printf 'user ${NGINX_USER:-hexo};\nworker_processes ${NGINX_WORKERS:-auto};\npid /var/run/nginx.pid;\n\nevents {\n worker_connections ${NGINX_CONNECTIONS:-1024};\n use epoll;\n multi_accept on;\n}\n\nhttp {\n include /etc/nginx/mime.types;\n default_type application/octet-stream;\n \n access_log /var/log/nginx/access.log;\n error_log /var/log/nginx/error.log;\n \n sendfile on;\n tcp_nopush on;\n tcp_nodelay on;\n keepalive_timeout 65;\n types_hash_max_size 2048;\n \n add_header X-Frame-Options DENY;\n add_header X-Content-Type-Options nosniff;\n add_header X-XSS-Protection "1; mode=block";\n \n gzip on;\n gzip_vary on;\n gzip_proxied any;\n gzip_comp_level 6;\n gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;\n\n server {\n listen ${HTTP_PORT:-80};\n server_name ${SERVER_NAME:-localhost};\n root ${WEB_ROOT:-/home/www/hexo};\n index index.html index.htm;\n \n server_tokens off;\n \n location / {\n try_files $uri $uri/ =404;\n }\n \n location ~* \\.(jpg|jpeg|png|gif|ico|css|js)$ {\n expires 1y;\n add_header Cache-Control "public, immutable";\n }\n }\n}' > /etc/container/templates/nginx.conf.template
|
||||
|
||||
|
||||
|
||||
# Create improved start script using printf for better formatting
|
||||
|
||||
RUN printf '#!/bin/bash\n\nRED="\\033[0;31m"\nGREEN="\\033[0;32m"\nYELLOW="\\033[1;33m"\nBLUE="\\033[0;34m"\nNC="\\033[0m"\n\nLOG_DIR="/var/log/container"\nLOG_FILE="$LOG_DIR/services.log"\nMAX_LOG_SIZE=10485760\n\n_log() {\n local level_color=$1\n local level_name=$2\n shift 2\n echo -e "${level_color}[${level_name}]${NC} $(date \047+%%Y-%%m-%%d %%H:%%M:%%S\047) - $@"\n}\nlog_info() { _log "$BLUE" "INFO" "$@"; }\nlog_success() { _log "$GREEN" "SUCCESS" "$@"; }\nlog_warning() { _log "$YELLOW" "WARNING" "$@"; }\nlog_error() { _log "$RED" "ERROR" "$@"; }\n\nsetup_logging() {\n mkdir -p "$LOG_DIR"\n touch "$LOG_FILE"\n log_info "Logging to console and $LOG_FILE"\n exec > >(tee -a "$LOG_FILE") 2> >(tee -a "$LOG_FILE" >&2)\n}\n\nrender_config() {\n log_info "Rendering configuration templates..."\n local rendered=0\n \n if envsubst < /etc/container/templates/sshd_config.template > /etc/ssh/sshd_config; then\n log_success "SSHD configuration rendered"; ((rendered++))\n else \n log_error "Failed to render SSHD configuration"; \n fi\n \n if envsubst < /etc/container/templates/nginx.conf.template > /etc/nginx/nginx.conf; then\n log_success "Nginx configuration rendered"; ((rendered++))\n else \n log_error "Failed to render Nginx configuration"; \n fi\n \n if [ "$rendered" -eq 2 ]; then \n log_success "All configuration files rendered"\n return 0\n else \n log_error "Failed to render some configuration files"\n return 1\n fi\n}\n\nstart_services() {\n log_info "Starting SSH service..."\n if [ ! -f "/etc/ssh/ssh_host_rsa_key" ]; then\n log_info "Generating SSH host keys..."\n ssh-keygen -A\n fi\n \n /usr/sbin/sshd -D &\n SSH_PID=$!\n \n log_info "Starting Nginx service..."\n nginx -g "daemon off;" &\n NGINX_PID=$!\n \n sleep 2\n \n if kill -0 $SSH_PID 2>/dev/null && kill -0 $NGINX_PID 2>/dev/null; then\n log_success "All services started successfully"\n return 0\n else\n log_error "Failed to start some services"\n return 1\n fi\n}\n\nmonitor_services() {\n log_info "Starting service monitoring..."\n while true; do\n sleep 30\n \n if ! kill -0 $SSH_PID 2>/dev/null; then\n log_error "SSH service stopped, attempting restart..."\n /usr/sbin/sshd -D &\n SSH_PID=$!\n fi\n \n if ! kill -0 $NGINX_PID 2>/dev/null; then\n log_error "Nginx service stopped, attempting restart..."\n nginx -g "daemon off;" &\n NGINX_PID=$!\n fi\n done\n}\n\ncleanup() {\n log_info "Received shutdown signal, gracefully stopping services..."\n \n if [ ! -z "$NGINX_PID" ] && kill -0 $NGINX_PID 2>/dev/null; then\n log_info "Stopping Nginx (PID:$NGINX_PID)"\n kill -TERM $NGINX_PID\n wait $NGINX_PID 2>/dev/null\n log_success "Nginx stopped"\n fi\n \n if [ ! -z "$SSH_PID" ] && kill -0 $SSH_PID 2>/dev/null; then\n log_info "Stopping SSH (PID:$SSH_PID)"\n kill -TERM $SSH_PID\n wait $SSH_PID 2>/dev/null\n log_success "SSH stopped"\n fi\n \n log_info "Container shutdown complete"\n exit 0\n}\n\ntrap cleanup SIGTERM SIGINT\n\nmain() {\n setup_logging\n log_info "===== Container Starting ====="\n log_info "Time: $(date)"\n log_info "Timezone: $TZ"\n log_info "User: $(whoami)"\n \n if ! render_config; then\n log_error "Configuration rendering failed"\n exit 1\n fi\n \n if ! /usr/sbin/sshd -t; then\n log_error "SSH configuration test failed"\n exit 1\n fi\n \n if ! nginx -t; then\n log_error "Nginx configuration test failed"\n exit 1\n fi\n \n if ! start_services; then\n exit 1\n fi\n \n log_success "===== All services started successfully ====="\n monitor_services\n}\n\nmain' > /app/start.sh && \
|
||||
|
||||
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 with secure permissions
|
||||
|
||||
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 for security
|
||||
|
||||
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"]
|
||||
565
arch/Dockerfile_v0.0.2
Normal file
565
arch/Dockerfile_v0.0.2
Normal file
@@ -0,0 +1,565 @@
|
||||
# Dockerfile v0.0.2 - Enhanced Hexo Deployment Container
|
||||
# Improvements:
|
||||
# - Enhanced readability with heredoc syntax for scripts
|
||||
# - Fixed PUID/PGID support for proper user/group mapping
|
||||
# - Intelligent log rotation with 10MB file size limit
|
||||
# - Optimized production image (removed vim, nodejs, npm)
|
||||
# - Enhanced security configurations (CSP headers, MaxAuthTries, ClientAlive)
|
||||
# - Dedicated health endpoint (/health)
|
||||
# - Improved post-receive hook with detailed logging
|
||||
# - Dynamic volume permission management
|
||||
|
||||
# ---- Stage 1: Builder/Base ----
|
||||
# This stage sets up the base environment, installs build tools, creates scripts and templates
|
||||
|
||||
FROM ubuntu:22.04 AS builder
|
||||
|
||||
ARG TZ=Asia/Shanghai
|
||||
ARG PUID=1000
|
||||
ARG PGID=1000
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV TZ=${TZ}
|
||||
|
||||
# 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 directories for artifacts
|
||||
RUN mkdir -p /etc/container/templates && \
|
||||
mkdir -p /app && \
|
||||
mkdir -p /home/hexo
|
||||
|
||||
# Configure git hook with improved logging using heredoc
|
||||
RUN git init --bare /home/hexo/hexo.git
|
||||
|
||||
# Create enhanced post-receive hook with detailed logging
|
||||
RUN cat << 'EOF' > /home/hexo/hexo.git/hooks/post-receive
|
||||
#!/bin/bash
|
||||
|
||||
# Enhanced post-receive hook with detailed logging
|
||||
LOG_FILE="/var/log/container/deployment.log"
|
||||
DEPLOY_TIME=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
log_deploy() {
|
||||
echo "[$DEPLOY_TIME] $*" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
log_deploy "===== Starting Git Deployment ====="
|
||||
log_deploy "Deploy initiated by: $(whoami)"
|
||||
log_deploy "Git repository: $PWD"
|
||||
log_deploy "Target directory: /home/www/hexo"
|
||||
|
||||
# Ensure target directory exists
|
||||
if [ ! -d "/home/www/hexo" ]; then
|
||||
log_deploy "Creating target directory /home/www/hexo"
|
||||
mkdir -p /home/www/hexo
|
||||
fi
|
||||
|
||||
# Checkout files
|
||||
log_deploy "Checking out files..."
|
||||
if git --work-tree=/home/www/hexo --git-dir=/home/hexo/hexo.git checkout -f; then
|
||||
log_deploy "Git checkout completed successfully"
|
||||
else
|
||||
log_deploy "ERROR: Git checkout failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set proper ownership and permissions
|
||||
log_deploy "Setting file ownership and permissions..."
|
||||
if chown -R hexo:hexo /home/www/hexo; then
|
||||
log_deploy "File ownership set successfully"
|
||||
else
|
||||
log_deploy "WARNING: Failed to set file ownership"
|
||||
fi
|
||||
|
||||
if chmod -R 755 /home/www/hexo; then
|
||||
log_deploy "File permissions set successfully"
|
||||
else
|
||||
log_deploy "WARNING: Failed to set file permissions"
|
||||
fi
|
||||
|
||||
# Count deployed files
|
||||
FILE_COUNT=$(find /home/www/hexo -type f | wc -l)
|
||||
TOTAL_SIZE=$(du -sh /home/www/hexo 2>/dev/null | cut -f1)
|
||||
|
||||
log_deploy "Deployment completed successfully"
|
||||
log_deploy "Files deployed: $FILE_COUNT"
|
||||
log_deploy "Total size: $TOTAL_SIZE"
|
||||
log_deploy "===== Git Deployment Finished ====="
|
||||
EOF
|
||||
|
||||
RUN chmod +x /home/hexo/hexo.git/hooks/post-receive
|
||||
|
||||
# Backup original nginx.conf
|
||||
RUN cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
|
||||
|
||||
# Create enhanced SSH Config Template with security improvements using heredoc
|
||||
RUN cat << 'EOF' > /etc/container/templates/sshd_config.template
|
||||
# Enhanced SSH Configuration with Security Hardening
|
||||
Port ${SSH_PORT:-22}
|
||||
ListenAddress 0.0.0.0
|
||||
ListenAddress ::
|
||||
|
||||
# Authentication settings
|
||||
PermitRootLogin ${PERMIT_ROOT_LOGIN:-no}
|
||||
PubkeyAuthentication yes
|
||||
AuthorizedKeysFile .ssh/authorized_keys
|
||||
PasswordAuthentication no
|
||||
ChallengeResponseAuthentication no
|
||||
UsePAM yes
|
||||
|
||||
# Security enhancements
|
||||
MaxAuthTries 3
|
||||
ClientAliveInterval 300
|
||||
ClientAliveCountMax 2
|
||||
LoginGraceTime 60
|
||||
MaxStartups 10:30:60
|
||||
|
||||
# Disable unnecessary features
|
||||
X11Forwarding no
|
||||
AllowTcpForwarding no
|
||||
GatewayPorts no
|
||||
PermitTunnel no
|
||||
PrintMotd no
|
||||
|
||||
# Environment and subsystem
|
||||
AcceptEnv LANG LC_*
|
||||
Subsystem sftp /usr/lib/openssh/sftp-server
|
||||
|
||||
# User restrictions
|
||||
AllowUsers hexo
|
||||
EOF
|
||||
|
||||
# Create enhanced Nginx Config Template with security headers and health endpoint using heredoc
|
||||
RUN cat << 'EOF' > /etc/container/templates/nginx.conf.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 optimizations
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
|
||||
# Enhanced security headers
|
||||
add_header X-Frame-Options DENY always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self';" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
|
||||
# Compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/xml
|
||||
text/javascript
|
||||
application/json
|
||||
application/javascript
|
||||
application/xml+rss
|
||||
application/atom+xml
|
||||
image/svg+xml;
|
||||
|
||||
server {
|
||||
listen ${HTTP_PORT:-80};
|
||||
server_name ${SERVER_NAME:-localhost};
|
||||
root ${WEB_ROOT:-/home/www/hexo};
|
||||
index index.html index.htm;
|
||||
|
||||
server_tokens off;
|
||||
|
||||
# Main site location
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# Dedicated health check endpoint
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "OK\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
|
||||
# Static assets with caching
|
||||
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|eot|svg)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
add_header Vary Accept-Encoding;
|
||||
}
|
||||
|
||||
# Security: deny access to hidden files
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create enhanced start script with heredoc for better readability and maintainability
|
||||
RUN cat << 'EOF' > /app/start.sh
|
||||
#!/bin/bash
|
||||
|
||||
# Enhanced startup script with improved logging, error handling, and dynamic permissions
|
||||
# Version: 0.0.2
|
||||
|
||||
# Color definitions for logging
|
||||
RED="\033[0;31m"
|
||||
GREEN="\033[0;32m"
|
||||
YELLOW="\033[1;33m"
|
||||
BLUE="\033[0;34m"
|
||||
NC="\033[0m"
|
||||
|
||||
# Configuration
|
||||
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 with rotation
|
||||
setup_logging() {
|
||||
mkdir -p "$LOG_DIR"
|
||||
touch "$LOG_FILE"
|
||||
|
||||
# Rotate log if it's too large
|
||||
if [ -f "$LOG_FILE" ] && [ $(stat -c%s "$LOG_FILE" 2>/dev/null || echo 0) -gt $MAX_LOG_SIZE ]; then
|
||||
log_info "Log file size exceeded ${MAX_LOG_SIZE} bytes, rotating..."
|
||||
mv "$LOG_FILE" "${LOG_FILE}.old"
|
||||
touch "$LOG_FILE"
|
||||
log_info "Log rotation completed"
|
||||
fi
|
||||
|
||||
log_info "Logging to console and $LOG_FILE"
|
||||
exec > >(tee -a "$LOG_FILE") 2> >(tee -a "$LOG_FILE" >&2)
|
||||
}
|
||||
|
||||
# Apply dynamic PUID/PGID if different from defaults
|
||||
apply_dynamic_permissions() {
|
||||
local current_uid=$(id -u hexo)
|
||||
local current_gid=$(id -g hexo)
|
||||
local target_uid=${PUID:-1000}
|
||||
local target_gid=${PGID:-1000}
|
||||
|
||||
if [ "$current_uid" != "$target_uid" ] || [ "$current_gid" != "$target_gid" ]; then
|
||||
log_info "Applying dynamic user/group mapping: $current_uid:$current_gid -> $target_uid:$target_gid"
|
||||
|
||||
# Update group if needed
|
||||
if [ "$current_gid" != "$target_gid" ]; then
|
||||
groupmod -g "$target_gid" hexo
|
||||
log_info "Updated hexo group ID to $target_gid"
|
||||
fi
|
||||
|
||||
# Update user if needed
|
||||
if [ "$current_uid" != "$target_uid" ]; then
|
||||
usermod -u "$target_uid" hexo
|
||||
log_info "Updated hexo user ID to $target_uid"
|
||||
fi
|
||||
|
||||
# Update ownership of important directories
|
||||
log_info "Updating ownership of critical directories..."
|
||||
chown -R hexo:hexo /home/hexo /home/www/hexo 2>/dev/null || true
|
||||
log_success "Dynamic permissions applied successfully"
|
||||
else
|
||||
log_info "User/group IDs already match target values ($target_uid:$target_gid)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Render configuration templates
|
||||
render_config() {
|
||||
log_info "Rendering configuration templates..."
|
||||
local rendered=0
|
||||
|
||||
# Render SSH configuration
|
||||
if envsubst < /etc/container/templates/sshd_config.template > /etc/ssh/sshd_config; then
|
||||
log_success "SSH configuration rendered"
|
||||
((rendered++))
|
||||
else
|
||||
log_error "Failed to render SSH configuration"
|
||||
fi
|
||||
|
||||
# Render Nginx configuration
|
||||
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 successfully"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to render some configuration files"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Start services
|
||||
start_services() {
|
||||
log_info "Starting services..."
|
||||
|
||||
# Generate SSH host keys if needed
|
||||
if [ ! -f "/etc/ssh/ssh_host_rsa_key" ]; then
|
||||
log_info "Generating SSH host keys..."
|
||||
ssh-keygen -A
|
||||
log_success "SSH host keys generated"
|
||||
fi
|
||||
|
||||
# Start SSH service
|
||||
log_info "Starting SSH service..."
|
||||
/usr/sbin/sshd -D &
|
||||
SSH_PID=$!
|
||||
|
||||
# Start Nginx service
|
||||
log_info "Starting Nginx service..."
|
||||
nginx -g "daemon off;" &
|
||||
NGINX_PID=$!
|
||||
|
||||
# Wait for services to start
|
||||
sleep 3
|
||||
|
||||
# Verify services are running
|
||||
if kill -0 $SSH_PID 2>/dev/null && kill -0 $NGINX_PID 2>/dev/null; then
|
||||
log_success "All services started successfully"
|
||||
log_info "SSH PID: $SSH_PID"
|
||||
log_info "Nginx PID: $NGINX_PID"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to start some services"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Monitor services and restart if needed
|
||||
monitor_services() {
|
||||
log_info "Starting service monitoring (30s intervals)..."
|
||||
|
||||
while true; do
|
||||
sleep 30
|
||||
|
||||
# Check SSH service
|
||||
if ! kill -0 $SSH_PID 2>/dev/null; then
|
||||
log_error "SSH service stopped unexpectedly, attempting restart..."
|
||||
/usr/sbin/sshd -D &
|
||||
SSH_PID=$!
|
||||
if kill -0 $SSH_PID 2>/dev/null; then
|
||||
log_success "SSH service restarted successfully (PID: $SSH_PID)"
|
||||
else
|
||||
log_error "Failed to restart SSH service"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check Nginx service
|
||||
if ! kill -0 $NGINX_PID 2>/dev/null; then
|
||||
log_error "Nginx service stopped unexpectedly, attempting restart..."
|
||||
nginx -g "daemon off;" &
|
||||
NGINX_PID=$!
|
||||
if kill -0 $NGINX_PID 2>/dev/null; then
|
||||
log_success "Nginx service restarted successfully (PID: $NGINX_PID)"
|
||||
else
|
||||
log_error "Failed to restart Nginx service"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Graceful shutdown
|
||||
cleanup() {
|
||||
log_info "Received shutdown signal, gracefully stopping services..."
|
||||
|
||||
# Stop Nginx
|
||||
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 gracefully"
|
||||
fi
|
||||
|
||||
# Stop SSH
|
||||
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 gracefully"
|
||||
fi
|
||||
|
||||
log_info "Container shutdown completed"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Main execution function
|
||||
main() {
|
||||
setup_logging
|
||||
|
||||
log_info "===== Hexo Container Starting (v0.0.2) ====="
|
||||
log_info "Timestamp: $(date)"
|
||||
log_info "Timezone: $TZ"
|
||||
log_info "Current user: $(whoami)"
|
||||
log_info "PUID: ${PUID:-1000}, PGID: ${PGID:-1000}"
|
||||
|
||||
# Apply dynamic permissions
|
||||
apply_dynamic_permissions
|
||||
|
||||
# Render configurations
|
||||
if ! render_config; then
|
||||
log_error "Configuration rendering failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test configurations
|
||||
log_info "Testing configurations..."
|
||||
if ! /usr/sbin/sshd -t; then
|
||||
log_error "SSH configuration test failed"
|
||||
exit 1
|
||||
fi
|
||||
log_success "SSH configuration test passed"
|
||||
|
||||
if ! nginx -t; then
|
||||
log_error "Nginx configuration test failed"
|
||||
exit 1
|
||||
fi
|
||||
log_success "Nginx configuration test passed"
|
||||
|
||||
# Start services
|
||||
if ! start_services; then
|
||||
log_error "Service startup failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "===== All services started successfully ====="
|
||||
log_info "Container ready for connections"
|
||||
log_info "SSH: Port ${SSH_PORT:-22}"
|
||||
log_info "HTTP: Port ${HTTP_PORT:-80}"
|
||||
log_info "Health check: http://localhost/health"
|
||||
|
||||
# Start monitoring
|
||||
monitor_services
|
||||
}
|
||||
|
||||
# Set up signal handlers
|
||||
trap cleanup SIGTERM SIGINT
|
||||
|
||||
# Start main execution
|
||||
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
|
||||
|
||||
ARG TZ=Asia/Shanghai
|
||||
ARG PUID=1000
|
||||
ARG PGID=1000
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV TZ=${TZ}
|
||||
ENV PUID=${PUID}
|
||||
ENV PGID=${PGID}
|
||||
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 (removed vim, nodejs, npm for minimal production image)
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
openssh-server \
|
||||
git \
|
||||
nginx-full \
|
||||
gettext-base \
|
||||
curl \
|
||||
ca-certificates && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create hexo user with proper PUID/PGID mapping
|
||||
RUN groupadd -g ${PGID} hexo && \
|
||||
useradd -u ${PUID} -g hexo -d /home/hexo -s /bin/bash hexo
|
||||
|
||||
# Create necessary directories with secure permissions
|
||||
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 for security
|
||||
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 && \
|
||||
chmod 755 /var/log/container && \
|
||||
chmod 755 /var/log/nginx
|
||||
|
||||
# Enhanced health check using the dedicated /health endpoint
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
|
||||
CMD curl -f http://localhost/health || exit 1
|
||||
|
||||
# Define volumes for persistent data
|
||||
VOLUME ["/home/www/hexo", "/home/hexo/.ssh", "/home/www/ssl", "/home/hexo/hexo.git", "/var/log/container", "/var/log/nginx"]
|
||||
|
||||
# Expose ports
|
||||
EXPOSE 22 80 443
|
||||
|
||||
# Set the startup command
|
||||
CMD ["/root/start.sh"]
|
||||
352
arch/origin/Dockerfile
Normal file
352
arch/origin/Dockerfile
Normal file
@@ -0,0 +1,352 @@
|
||||
# ---- 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 /root/hexo.git && \
|
||||
echo "#!/bin/bash" > /root/hexo.git/hooks/post-receive && \
|
||||
echo "git --work-tree=/home/www/hexo --git-dir=/root/hexo.git checkout -f" >> /root/hexo.git/hooks/post-receive && \
|
||||
echo "chown -R hexo:hexo /home/www/hexo" >> /root/hexo.git/hooks/post-receive && \
|
||||
chmod +x /root/hexo.git/hooks/post-receive
|
||||
|
||||
# Backup original nginx.conf
|
||||
RUN cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
|
||||
|
||||
# Create improved SSH Config Template
|
||||
RUN cat > /etc/container/templates/sshd_config.template << 'EOF'
|
||||
# SSH Configuration Template
|
||||
Port ${SSH_PORT:-22}
|
||||
ListenAddress 0.0.0.0
|
||||
ListenAddress ::
|
||||
PermitRootLogin ${PERMIT_ROOT_LOGIN:-no}
|
||||
PubkeyAuthentication yes
|
||||
AuthorizedKeysFile .ssh/authorized_keys
|
||||
PasswordAuthentication no
|
||||
ChallengeResponseAuthentication no
|
||||
UsePAM yes
|
||||
X11Forwarding no
|
||||
PrintMotd no
|
||||
AcceptEnv LANG LC_*
|
||||
Subsystem sftp /usr/lib/openssh/sftp-server
|
||||
EOF
|
||||
|
||||
# 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 /root/.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 && \
|
||||
mkdir -p /home/hexo/.ssh
|
||||
|
||||
# Copy artifacts from builder stage
|
||||
COPY --from=builder /root/hexo.git /root/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 /root/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 /root/.ssh && \
|
||||
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", "/root/.ssh", "/home/www/ssl", "/root/hexo.git", "/var/log/container", "/var/log/nginx"]
|
||||
|
||||
EXPOSE 22 80 443
|
||||
|
||||
CMD ["/root/start.sh"]
|
||||
0
arch/origin/Dockerfile.fixed
Normal file
0
arch/origin/Dockerfile.fixed
Normal file
349
arch/origin/Dockerfile.improved
Normal file
349
arch/origin/Dockerfile.improved
Normal file
@@ -0,0 +1,349 @@
|
||||
# ---- 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"]
|
||||
615
arch/origin/Dockerfile.optimized
Normal file
615
arch/origin/Dockerfile.optimized
Normal file
@@ -0,0 +1,615 @@
|
||||
# ========== Multi-Stage Dockerfile for Hexo Blog Service ==========
|
||||
# This Dockerfile creates a secure, production-ready container for running
|
||||
# a Hexo blog with Nginx web server and SSH Git deployment capabilities.
|
||||
# Features: Non-root execution, environment-based user ID mapping, comprehensive logging
|
||||
|
||||
# ---- Stage 1: Builder/Base ----
|
||||
# Sets up templates, configurations, and scripts
|
||||
FROM ubuntu:22.04 AS builder
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV TZ=Asia/Shanghai
|
||||
|
||||
# Install build dependencies and configure locale
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
locales \
|
||||
git \
|
||||
nginx-full \
|
||||
gettext-base && \
|
||||
# Configure Chinese 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 && \
|
||||
# Set timezone
|
||||
ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && \
|
||||
echo $TZ > /etc/timezone && \
|
||||
# Clean up
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create template directories
|
||||
RUN mkdir -p /etc/container/templates && \
|
||||
mkdir -p /app
|
||||
|
||||
# ========== IMPROVEMENT 1: Use Heredoc for Better Readability ==========
|
||||
# Create enhanced SSH configuration template with heredoc
|
||||
RUN cat << 'EOF' > /etc/container/templates/sshd_config.template
|
||||
# SSH Server Configuration Template
|
||||
# This template supports environment variable substitution
|
||||
|
||||
Port ${SSH_PORT:-22}
|
||||
ListenAddress 0.0.0.0
|
||||
ListenAddress ::
|
||||
|
||||
# Authentication settings
|
||||
PermitRootLogin ${PERMIT_ROOT_LOGIN:-no}
|
||||
PubkeyAuthentication yes
|
||||
AuthorizedKeysFile .ssh/authorized_keys
|
||||
PasswordAuthentication no
|
||||
ChallengeResponseAuthentication no
|
||||
UsePAM yes
|
||||
|
||||
# Security settings
|
||||
AllowUsers ${SSH_USER:-hexo}
|
||||
X11Forwarding no
|
||||
PrintMotd no
|
||||
MaxAuthTries ${MAX_AUTH_TRIES:-3}
|
||||
ClientAliveInterval ${CLIENT_ALIVE_INTERVAL:-300}
|
||||
ClientAliveCountMax ${CLIENT_ALIVE_COUNT_MAX:-3}
|
||||
|
||||
# Logging
|
||||
SyslogFacility AUTH
|
||||
LogLevel ${SSH_LOG_LEVEL:-INFO}
|
||||
|
||||
# Subsystems
|
||||
Subsystem sftp /usr/lib/openssh/sftp-server
|
||||
|
||||
# Environment
|
||||
AcceptEnv LANG LC_*
|
||||
EOF
|
||||
|
||||
# Create Nginx configuration template with heredoc
|
||||
RUN cat << 'EOF' > /etc/container/templates/nginx.conf.template
|
||||
# Nginx Configuration Template
|
||||
# Optimized for security and performance
|
||||
|
||||
user ${NGINX_USER:-hexo};
|
||||
worker_processes ${NGINX_WORKERS:-auto};
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
# Error logging
|
||||
error_log /var/log/nginx/error.log ${NGINX_LOG_LEVEL:-warn};
|
||||
|
||||
events {
|
||||
worker_connections ${NGINX_CONNECTIONS:-1024};
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
# Basic settings
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# Logging
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
# Performance settings
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
client_max_body_size ${MAX_UPLOAD_SIZE:-16m};
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options DENY 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 Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
|
||||
|
||||
# Compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_min_length 1000;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
application/json
|
||||
application/javascript
|
||||
text/xml
|
||||
application/xml
|
||||
application/xml+rss
|
||||
text/javascript
|
||||
application/atom+xml
|
||||
image/svg+xml;
|
||||
|
||||
# Rate limiting
|
||||
limit_req_zone $binary_remote_addr zone=general:10m rate=${RATE_LIMIT:-10r/s};
|
||||
|
||||
server {
|
||||
listen ${HTTP_PORT:-80};
|
||||
server_name ${SERVER_NAME:-localhost};
|
||||
root ${WEB_ROOT:-/home/www/hexo};
|
||||
index index.html index.htm;
|
||||
|
||||
# Security settings
|
||||
server_tokens off;
|
||||
|
||||
# Rate limiting
|
||||
limit_req zone=general burst=${RATE_BURST:-20} nodelay;
|
||||
|
||||
# Main location
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# Static assets with caching
|
||||
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|eot|svg)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
add_header Vary Accept-Encoding;
|
||||
}
|
||||
|
||||
# Security: Deny access to hidden files
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
}
|
||||
|
||||
# Security: Deny access to sensitive files
|
||||
location ~* \.(bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)$ {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# ========== IMPROVEMENT 2: Enhanced Start Script with Log Rotation ==========
|
||||
# Create comprehensive start script with heredoc for better maintainability
|
||||
RUN cat << 'EOF' > /app/start.sh
|
||||
#!/bin/bash
|
||||
|
||||
# Color codes for logging
|
||||
readonly RED='\033[0;31m'
|
||||
readonly GREEN='\033[0;32m'
|
||||
readonly YELLOW='\033[1;33m'
|
||||
readonly BLUE='\033[0;34m'
|
||||
readonly PURPLE='\033[0;35m'
|
||||
readonly NC='\033[0m'
|
||||
|
||||
# Logging configuration
|
||||
readonly LOG_DIR="/var/log/container"
|
||||
readonly LOG_FILE="$LOG_DIR/services.log"
|
||||
readonly MAX_LOG_SIZE=${MAX_LOG_SIZE:-10485760} # 10MB default
|
||||
readonly MAX_LOG_FILES=${MAX_LOG_FILES:-5}
|
||||
|
||||
# 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" "$@"; }
|
||||
log_debug() { _log "$PURPLE" "DEBUG" "$@"; }
|
||||
|
||||
# ========== LOG ROTATION IMPLEMENTATION ==========
|
||||
rotate_logs() {
|
||||
if [[ -f "$LOG_FILE" && $(stat -c%s "$LOG_FILE" 2>/dev/null || echo 0) -gt $MAX_LOG_SIZE ]]; then
|
||||
log_info "Rotating log file (size: $(du -h "$LOG_FILE" 2>/dev/null | cut -f1))"
|
||||
|
||||
# Rotate existing logs
|
||||
for i in $(seq $((MAX_LOG_FILES-1)) -1 1); do
|
||||
if [[ -f "${LOG_FILE}.$i" ]]; then
|
||||
mv "${LOG_FILE}.$i" "${LOG_FILE}.$((i+1))"
|
||||
fi
|
||||
done
|
||||
|
||||
# Move current log to .1
|
||||
mv "$LOG_FILE" "${LOG_FILE}.1"
|
||||
touch "$LOG_FILE"
|
||||
|
||||
log_success "Log rotation completed"
|
||||
fi
|
||||
}
|
||||
|
||||
setup_logging() {
|
||||
mkdir -p "$LOG_DIR"
|
||||
touch "$LOG_FILE"
|
||||
|
||||
# Rotate logs if needed
|
||||
rotate_logs
|
||||
|
||||
log_info "Logging to console and $LOG_FILE"
|
||||
log_info "Log rotation: enabled (max size: ${MAX_LOG_SIZE} bytes, max files: ${MAX_LOG_FILES})"
|
||||
|
||||
# Redirect all output to log file while keeping console output
|
||||
exec > >(tee -a "$LOG_FILE") 2> >(tee -a "$LOG_FILE" >&2)
|
||||
}
|
||||
|
||||
# ========== USER MANAGEMENT WITH PUID/PGID SUPPORT ==========
|
||||
setup_user() {
|
||||
local target_uid=${PUID:-1000}
|
||||
local target_gid=${PGID:-1000}
|
||||
|
||||
log_info "Setting up user with UID:$target_uid, GID:$target_gid"
|
||||
|
||||
# Create group with specified GID
|
||||
if ! getent group hexo >/dev/null 2>&1; then
|
||||
if getent group "$target_gid" >/dev/null 2>&1; then
|
||||
log_warning "GID $target_gid already exists, using existing group"
|
||||
existing_group=$(getent group "$target_gid" | cut -d: -f1)
|
||||
log_info "Using existing group: $existing_group"
|
||||
else
|
||||
groupadd -g "$target_gid" hexo
|
||||
log_success "Created group 'hexo' with GID $target_gid"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create user with specified UID
|
||||
if ! getent passwd hexo >/dev/null 2>&1; then
|
||||
if getent passwd "$target_uid" >/dev/null 2>&1; then
|
||||
log_error "UID $target_uid already exists"
|
||||
return 1
|
||||
else
|
||||
useradd -u "$target_uid" -g "$target_gid" -d /home/hexo -s /bin/bash hexo
|
||||
log_success "Created user 'hexo' with UID $target_uid"
|
||||
fi
|
||||
else
|
||||
# User exists, check if UID needs updating
|
||||
current_uid=$(id -u hexo)
|
||||
if [[ "$current_uid" != "$target_uid" ]]; then
|
||||
log_info "Updating hexo user UID from $current_uid to $target_uid"
|
||||
usermod -u "$target_uid" hexo
|
||||
fi
|
||||
fi
|
||||
|
||||
# Ensure home directory exists and has correct ownership
|
||||
mkdir -p /home/hexo/.ssh
|
||||
mkdir -p /home/www/hexo
|
||||
chown -R hexo:hexo /home/hexo /home/www/hexo
|
||||
chmod 700 /home/hexo/.ssh
|
||||
|
||||
log_success "User setup completed"
|
||||
}
|
||||
|
||||
render_config() {
|
||||
log_info "Rendering configuration templates..."
|
||||
local rendered=0
|
||||
|
||||
# Render SSH configuration
|
||||
if envsubst < /etc/container/templates/sshd_config.template > /etc/ssh/sshd_config; then
|
||||
log_success "SSH configuration rendered"
|
||||
((rendered++))
|
||||
else
|
||||
log_error "Failed to render SSH configuration"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Render Nginx configuration
|
||||
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"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_success "All $rendered configuration files rendered successfully"
|
||||
return 0
|
||||
}
|
||||
|
||||
validate_configs() {
|
||||
log_info "Validating configurations..."
|
||||
|
||||
# Validate SSH configuration
|
||||
if /usr/sbin/sshd -t; then
|
||||
log_success "SSH configuration is valid"
|
||||
else
|
||||
log_error "SSH configuration validation failed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Validate Nginx configuration
|
||||
if nginx -t; then
|
||||
log_success "Nginx configuration is valid"
|
||||
else
|
||||
log_error "Nginx configuration validation failed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
start_services() {
|
||||
log_info "Starting services..."
|
||||
|
||||
# Generate SSH host keys if they don't exist
|
||||
if [[ ! -f "/etc/ssh/ssh_host_rsa_key" ]]; then
|
||||
log_info "Generating SSH host keys..."
|
||||
ssh-keygen -A
|
||||
log_success "SSH host keys generated"
|
||||
fi
|
||||
|
||||
# Start SSH service
|
||||
log_info "Starting SSH service..."
|
||||
/usr/sbin/sshd -D &
|
||||
SSH_PID=$!
|
||||
|
||||
# Start Nginx service
|
||||
log_info "Starting Nginx service..."
|
||||
nginx -g "daemon off;" &
|
||||
NGINX_PID=$!
|
||||
|
||||
# Wait for services to start
|
||||
sleep 3
|
||||
|
||||
# Verify services are running
|
||||
local services_ok=true
|
||||
if ! kill -0 $SSH_PID 2>/dev/null; then
|
||||
log_error "SSH service failed to start"
|
||||
services_ok=false
|
||||
else
|
||||
log_success "SSH service started (PID:$SSH_PID)"
|
||||
fi
|
||||
|
||||
if ! kill -0 $NGINX_PID 2>/dev/null; then
|
||||
log_error "Nginx service failed to start"
|
||||
services_ok=false
|
||||
else
|
||||
log_success "Nginx service started (PID:$NGINX_PID)"
|
||||
fi
|
||||
|
||||
if $services_ok; then
|
||||
log_success "All services started successfully"
|
||||
return 0
|
||||
else
|
||||
log_error "Some services failed to start"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
monitor_services() {
|
||||
log_info "Starting service monitoring and log rotation..."
|
||||
|
||||
while true; do
|
||||
sleep 30
|
||||
|
||||
# Rotate logs if needed
|
||||
rotate_logs
|
||||
|
||||
# Monitor SSH service
|
||||
if ! kill -0 $SSH_PID 2>/dev/null; then
|
||||
log_warning "SSH service stopped, attempting restart..."
|
||||
/usr/sbin/sshd -D &
|
||||
SSH_PID=$!
|
||||
if kill -0 $SSH_PID 2>/dev/null; then
|
||||
log_success "SSH service restarted (PID:$SSH_PID)"
|
||||
else
|
||||
log_error "Failed to restart SSH service"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Monitor Nginx service
|
||||
if ! kill -0 $NGINX_PID 2>/dev/null; then
|
||||
log_warning "Nginx service stopped, attempting restart..."
|
||||
nginx -g "daemon off;" &
|
||||
NGINX_PID=$!
|
||||
if kill -0 $NGINX_PID 2>/dev/null; then
|
||||
log_success "Nginx service restarted (PID:$NGINX_PID)"
|
||||
else
|
||||
log_error "Failed to restart Nginx service"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
log_info "Received shutdown signal, gracefully stopping services..."
|
||||
|
||||
# Stop Nginx
|
||||
if [[ -n "$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 gracefully"
|
||||
fi
|
||||
|
||||
# Stop SSH
|
||||
if [[ -n "$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 gracefully"
|
||||
fi
|
||||
|
||||
log_info "Container shutdown complete"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Signal handlers
|
||||
trap cleanup SIGTERM SIGINT
|
||||
|
||||
# Main execution function
|
||||
main() {
|
||||
setup_logging
|
||||
|
||||
log_info "========== Container Starting =========="
|
||||
log_info "Timestamp: $(date)"
|
||||
log_info "Timezone: ${TZ:-UTC}"
|
||||
log_info "PUID: ${PUID:-1000}, PGID: ${PGID:-1000}"
|
||||
log_info "Current user: $(whoami)"
|
||||
|
||||
# Setup user with PUID/PGID support
|
||||
if ! setup_user; then
|
||||
log_error "User setup failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Render configuration templates
|
||||
if ! render_config; then
|
||||
log_error "Configuration rendering failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate configurations
|
||||
if ! validate_configs; then
|
||||
log_error "Configuration validation failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Start services
|
||||
if ! start_services; then
|
||||
log_error "Service startup failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "========== All services started successfully =========="
|
||||
log_info "Container is ready to serve requests"
|
||||
|
||||
# Start monitoring loop
|
||||
monitor_services
|
||||
}
|
||||
|
||||
# Execute main function
|
||||
main "$@"
|
||||
EOF
|
||||
|
||||
chmod +x /app/start.sh
|
||||
|
||||
# Create Git repository with enhanced security
|
||||
RUN git init --bare /home/hexo/hexo.git
|
||||
|
||||
# ========== IMPROVEMENT 3: Enhanced Post-Receive Hook Security ==========
|
||||
RUN cat << 'EOF' > /home/hexo/hexo.git/hooks/post-receive
|
||||
#!/bin/bash
|
||||
|
||||
# Enhanced Git post-receive hook with security checks
|
||||
# This hook deploys the website content after a git push
|
||||
|
||||
LOG_FILE="/var/log/container/git-deploy.log"
|
||||
WORK_TREE="/home/www/hexo"
|
||||
GIT_DIR="/home/hexo/hexo.git"
|
||||
|
||||
# Logging function
|
||||
log() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Security: Validate that we're running as the correct user
|
||||
if [[ "$(whoami)" != "hexo" ]]; then
|
||||
log "ERROR: Post-receive hook must run as 'hexo' user, currently: $(whoami)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Security: Validate paths
|
||||
if [[ ! -d "$WORK_TREE" ]]; then
|
||||
log "ERROR: Work tree directory does not exist: $WORK_TREE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d "$GIT_DIR" ]]; then
|
||||
log "ERROR: Git directory does not exist: $GIT_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Starting deployment..."
|
||||
log "Work tree: $WORK_TREE"
|
||||
log "Git directory: $GIT_DIR"
|
||||
|
||||
# Perform the checkout
|
||||
if git --work-tree="$WORK_TREE" --git-dir="$GIT_DIR" checkout -f; then
|
||||
log "SUCCESS: Code deployed successfully"
|
||||
|
||||
# Ensure correct permissions
|
||||
if chown -R hexo:hexo "$WORK_TREE"; then
|
||||
log "SUCCESS: Permissions updated"
|
||||
else
|
||||
log "WARNING: Failed to update permissions"
|
||||
fi
|
||||
|
||||
# Optional: Reload Nginx if configuration changed
|
||||
if [[ -f "$WORK_TREE/nginx.conf" ]]; then
|
||||
log "INFO: Custom Nginx configuration detected, consider reloading"
|
||||
fi
|
||||
|
||||
log "Deployment completed successfully"
|
||||
else
|
||||
log "ERROR: Deployment failed"
|
||||
exit 1
|
||||
fi
|
||||
EOF
|
||||
|
||||
chmod +x /home/hexo/hexo.git/hooks/post-receive
|
||||
|
||||
# ---- Stage 2: Production ----
|
||||
# ========== IMPROVEMENT 4: Remove Unnecessary Packages ==========
|
||||
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 configuration
|
||||
COPY --from=builder /etc/localtime /etc/localtime
|
||||
COPY --from=builder /etc/timezone /etc/timezone
|
||||
|
||||
# Install ONLY runtime dependencies (removed vim, nodejs, npm)
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
openssh-server \
|
||||
git \
|
||||
nginx-light \
|
||||
gettext-base \
|
||||
curl \
|
||||
ca-certificates \
|
||||
locales && \
|
||||
# Configure locale
|
||||
locale-gen zh_CN.UTF-8 && \
|
||||
update-locale LANG=zh_CN.UTF-8 && \
|
||||
# Create necessary directories
|
||||
mkdir -p /var/run/sshd && \
|
||||
mkdir -p /var/log/container && \
|
||||
mkdir -p /var/log/nginx && \
|
||||
mkdir -p /home/hexo/.ssh && \
|
||||
mkdir -p /home/www/hexo && \
|
||||
mkdir -p /home/www/ssl && \
|
||||
# Clean up
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
rm -rf /tmp/* && \
|
||||
rm -rf /var/tmp/*
|
||||
|
||||
# Copy artifacts from builder stage
|
||||
COPY --from=builder /etc/container/templates/ /etc/container/templates/
|
||||
COPY --from=builder /app/start.sh /app/start.sh
|
||||
COPY --from=builder /home/hexo/hexo.git/ /home/hexo/hexo.git/
|
||||
|
||||
# Set executable permissions
|
||||
RUN chmod +x /app/start.sh && \
|
||||
chmod +x /home/hexo/hexo.git/hooks/post-receive
|
||||
|
||||
# Health check with better error handling
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
||||
CMD curl -f -s -o /dev/null http://localhost:${HTTP_PORT:-80}/ || exit 1
|
||||
|
||||
# Document exposed ports
|
||||
EXPOSE 22 80 443
|
||||
|
||||
# Define volumes for persistent data
|
||||
VOLUME ["/home/www/hexo", "/home/hexo/.ssh", "/home/www/ssl", "/home/hexo/hexo.git", "/var/log/container", "/var/log/nginx"]
|
||||
|
||||
# Use the enhanced start script
|
||||
CMD ["/app/start.sh"]
|
||||
334
arch/origin/Dockerfile.secure
Normal file
334
arch/origin/Dockerfile.secure
Normal file
@@ -0,0 +1,334 @@
|
||||
# ---- 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 /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 cat > /etc/container/templates/sshd_config.template << 'EOF'
|
||||
Port ${SSH_PORT:-22}
|
||||
ListenAddress 0.0.0.0
|
||||
ListenAddress ::
|
||||
PermitRootLogin ${PERMIT_ROOT_LOGIN:-no}
|
||||
PubkeyAuthentication yes
|
||||
AuthorizedKeysFile .ssh/authorized_keys
|
||||
PasswordAuthentication no
|
||||
ChallengeResponseAuthentication no
|
||||
UsePAM yes
|
||||
X11Forwarding no
|
||||
PrintMotd no
|
||||
AcceptEnv LANG LC_*
|
||||
Subsystem sftp /usr/lib/openssh/sftp-server
|
||||
AllowUsers hexo
|
||||
EOF
|
||||
|
||||
# Create Nginx Config Template with security headers
|
||||
RUN cat > /etc/container/templates/nginx.conf.template << 'EOF'
|
||||
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;
|
||||
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
|
||||
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;
|
||||
|
||||
server_tokens off;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
LOG_DIR="/var/log/container"
|
||||
LOG_FILE="$LOG_DIR/services.log"
|
||||
MAX_LOG_SIZE=10485760
|
||||
|
||||
_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() {
|
||||
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_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() {
|
||||
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() {
|
||||
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() {
|
||||
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() {
|
||||
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 with secure permissions
|
||||
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 for security
|
||||
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"]
|
||||
30
arch/origin/Dockerfile.simple
Normal file
30
arch/origin/Dockerfile.simple
Normal file
@@ -0,0 +1,30 @@
|
||||
# Dockerfile ÓÅ»¯°æ±¾²âÊÔ
|
||||
FROM ubuntu:22.04 AS builder
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update && apt-get install -y nginx-light curl && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN mkdir -p /app
|
||||
|
||||
RUN echo '#!/bin/bash' > /app/start.sh && \
|
||||
echo 'echo "Starting optimized container..."' >> /app/start.sh && \
|
||||
echo 'nginx -g "daemon off;"' >> /app/start.sh && \
|
||||
chmod +x /app/start.sh
|
||||
|
||||
FROM ubuntu:22.04
|
||||
|
||||
RUN apt-get update && apt-get install -y nginx-light curl && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
mkdir -p /var/www/html
|
||||
|
||||
COPY --from=builder /app/start.sh /app/start.sh
|
||||
|
||||
RUN echo '<h1>Hexo Blog - Optimized Version</h1><p> Heredoc implementation</p><p> PUID/PGID support</p><p> Log rotation</p><p> Package optimization</p><p> Enhanced security</p>' > /var/www/html/index.html
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=10s CMD curl -f http://localhost/ || exit 1
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["/app/start.sh"]
|
||||
98
arch/origin/Dockerfile.working
Normal file
98
arch/origin/Dockerfile.working
Normal file
@@ -0,0 +1,98 @@
|
||||
FROM ubuntu:22.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV TZ=Asia/Shanghai
|
||||
ENV LANG=zh_CN.UTF-8
|
||||
|
||||
# Set timezone and locale
|
||||
RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && \
|
||||
echo $TZ > /etc/timezone
|
||||
|
||||
# Install packages
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
openssh-server \
|
||||
git \
|
||||
nginx-full \
|
||||
gettext-base \
|
||||
curl \
|
||||
locales && \
|
||||
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 hexo user for security
|
||||
RUN groupadd -r hexo && \
|
||||
useradd -r -g hexo -d /home/hexo -s /bin/bash hexo
|
||||
|
||||
# Create 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 && \
|
||||
mkdir -p /etc/container/templates
|
||||
|
||||
# Setup Git repository for deployment
|
||||
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
|
||||
|
||||
# Create SSH config template
|
||||
RUN echo 'Port 22' > /etc/container/templates/sshd_config.template && \
|
||||
echo 'PermitRootLogin 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 'AllowUsers hexo' >> /etc/container/templates/sshd_config.template
|
||||
|
||||
# Create Nginx config template
|
||||
RUN echo 'user hexo;' > /etc/container/templates/nginx.conf.template && \
|
||||
echo 'worker_processes auto;' >> /etc/container/templates/nginx.conf.template && \
|
||||
echo 'events { worker_connections 1024; }' >> /etc/container/templates/nginx.conf.template && \
|
||||
echo 'http {' >> /etc/container/templates/nginx.conf.template && \
|
||||
echo ' include /etc/nginx/mime.types;' >> /etc/container/templates/nginx.conf.template && \
|
||||
echo ' server_tokens off;' >> /etc/container/templates/nginx.conf.template && \
|
||||
echo ' add_header X-Frame-Options DENY;' >> /etc/container/templates/nginx.conf.template && \
|
||||
echo ' server {' >> /etc/container/templates/nginx.conf.template && \
|
||||
echo ' listen 80;' >> /etc/container/templates/nginx.conf.template && \
|
||||
echo ' root /home/www/hexo;' >> /etc/container/templates/nginx.conf.template && \
|
||||
echo ' index index.html;' >> /etc/container/templates/nginx.conf.template && \
|
||||
echo ' location / { try_files $uri $uri/ =404; }' >> /etc/container/templates/nginx.conf.template && \
|
||||
echo ' }' >> /etc/container/templates/nginx.conf.template && \
|
||||
echo '}' >> /etc/container/templates/nginx.conf.template
|
||||
|
||||
# Create startup script
|
||||
RUN echo '#!/bin/bash' > /root/start.sh && \
|
||||
echo 'set -e' >> /root/start.sh && \
|
||||
echo 'echo "Starting container..."' >> /root/start.sh && \
|
||||
echo 'cp /etc/container/templates/sshd_config.template /etc/ssh/sshd_config' >> /root/start.sh && \
|
||||
echo 'cp /etc/container/templates/nginx.conf.template /etc/nginx/nginx.conf' >> /root/start.sh && \
|
||||
echo 'if [ ! -f "/etc/ssh/ssh_host_rsa_key" ]; then ssh-keygen -A; fi' >> /root/start.sh && \
|
||||
echo '/usr/sbin/sshd -D &' >> /root/start.sh && \
|
||||
echo 'nginx -g "daemon off;" &' >> /root/start.sh && \
|
||||
echo 'wait' >> /root/start.sh && \
|
||||
chmod +x /root/start.sh
|
||||
|
||||
# Set proper permissions
|
||||
RUN chown -R hexo:hexo /home/hexo && \
|
||||
chown -R hexo:hexo /home/www/hexo && \
|
||||
chmod 700 /home/hexo/.ssh && \
|
||||
chmod -R 755 /home/www/hexo
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost/ || exit 1
|
||||
|
||||
# Volumes
|
||||
VOLUME ["/home/www/hexo", "/home/hexo/.ssh", "/home/www/ssl", "/home/hexo/hexo.git"]
|
||||
|
||||
# Expose ports
|
||||
EXPOSE 22 80 443
|
||||
|
||||
# Start services
|
||||
CMD ["/root/start.sh"]
|
||||
12
arch/origin/hexo_image.txt
Normal file
12
arch/origin/hexo_image.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
apt update && apt upgrade -y
|
||||
apt install -y systemctl
|
||||
apt install -y git vim gcc g++ nodejs npm nginx libnginx-mod-http-geoip2 ssh
|
||||
|
||||
/etc/nginx/
|
||||
/home/www/hexo/
|
||||
/home/ssl/
|
||||
|
||||
|
||||
/home/hexo.git/
|
||||
|
||||
/root/.ssh
|
||||
Reference in New Issue
Block a user