Some checks are pending
CI/CD Pipeline (Fully Isolated DinD) / Run Tests (DinD) (push) Waiting to run
CI/CD Pipeline (Fully Isolated DinD) / Build and Push Docker Images (DinD) (push) Blocked by required conditions
CI/CD Pipeline (Fully Isolated DinD) / Deploy to Production (push) Blocked by required conditions
220 lines
7.2 KiB
Nginx Configuration File
220 lines
7.2 KiB
Nginx Configuration File
# Docker Registry v2 Nginx Configuration with Enhanced Security
|
|
# Port 443: Unauthenticated pulls (GET requests only)
|
|
# Port 4443: Authenticated operations (login, logout, push, delete, etc.)
|
|
|
|
events {
|
|
worker_connections 1024;
|
|
use epoll;
|
|
multi_accept on;
|
|
}
|
|
|
|
http {
|
|
# Rate limiting with different zones for different operations
|
|
limit_req_zone $binary_remote_addr zone=registry:10m rate=10r/s;
|
|
limit_req_zone $binary_remote_addr zone=push:10m rate=5r/s;
|
|
limit_req_zone $binary_remote_addr zone=login:10m rate=2r/s;
|
|
|
|
# Connection limiting
|
|
limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m;
|
|
|
|
# Upstream Docker Registry
|
|
upstream registry {
|
|
server localhost:5000;
|
|
keepalive 32;
|
|
# Health check
|
|
keepalive_requests 100;
|
|
keepalive_timeout 60s;
|
|
}
|
|
|
|
# HTTP server for unauthenticated pulls on port 443
|
|
server {
|
|
listen 443 ssl http2;
|
|
server_name _;
|
|
|
|
# Connection limits
|
|
limit_conn conn_limit_per_ip 10;
|
|
|
|
# SSL Configuration - TLS 1.2/1.3 only with modern ciphers
|
|
ssl_certificate /etc/registry/certs/registry.crt;
|
|
ssl_certificate_key /etc/registry/certs/private/registry.key;
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
|
|
ssl_prefer_server_ciphers off;
|
|
ssl_session_cache shared:SSL:10m;
|
|
ssl_session_timeout 10m;
|
|
ssl_session_tickets off;
|
|
ssl_stapling on;
|
|
ssl_stapling_verify on;
|
|
|
|
# Security headers with HSTS
|
|
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 Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
|
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none';" always;
|
|
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
|
|
|
|
# Client max body size for large image uploads
|
|
client_max_body_size 2G;
|
|
client_body_timeout 60s;
|
|
client_header_timeout 60s;
|
|
|
|
# Rate limiting for read operations
|
|
limit_req zone=registry burst=20 nodelay;
|
|
|
|
# Block all write operations explicitly
|
|
if ($request_method !~ ^(GET|HEAD)$) {
|
|
return 405 "Method Not Allowed";
|
|
}
|
|
|
|
# Block suspicious user agents
|
|
if ($http_user_agent ~* (bot|crawler|spider|scraper)) {
|
|
return 403 "Forbidden";
|
|
}
|
|
|
|
# Allow all GET requests to v2 API (Docker Registry itself will handle security)
|
|
location /v2/ {
|
|
proxy_pass http://registry;
|
|
proxy_set_header Host $http_host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_read_timeout 900;
|
|
proxy_connect_timeout 60;
|
|
proxy_send_timeout 60;
|
|
proxy_buffering off;
|
|
proxy_request_buffering off;
|
|
|
|
# Additional security headers for registry
|
|
proxy_hide_header X-Powered-By;
|
|
proxy_hide_header Server;
|
|
}
|
|
|
|
location /health {
|
|
access_log off;
|
|
return 200 "healthy\n";
|
|
add_header Content-Type text/plain;
|
|
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
|
}
|
|
|
|
# Block access to hidden files
|
|
location ~ /\. {
|
|
deny all;
|
|
access_log off;
|
|
log_not_found off;
|
|
}
|
|
|
|
# Block access to sensitive files
|
|
location ~* \.(htaccess|htpasswd|ini|log|sh|sql|conf)$ {
|
|
deny all;
|
|
access_log off;
|
|
log_not_found off;
|
|
}
|
|
|
|
location / {
|
|
return 404;
|
|
}
|
|
|
|
access_log /var/log/nginx/registry_access.log;
|
|
error_log /var/log/nginx/registry_error.log;
|
|
}
|
|
|
|
# HTTPS server for authenticated operations on port 4443
|
|
server {
|
|
listen 4443 ssl http2;
|
|
server_name _;
|
|
|
|
# Connection limits
|
|
limit_conn conn_limit_per_ip 5;
|
|
|
|
# SSL Configuration - TLS 1.2/1.3 only with modern ciphers
|
|
ssl_certificate /etc/registry/certs/registry.crt;
|
|
ssl_certificate_key /etc/registry/certs/private/registry.key;
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
|
|
ssl_prefer_server_ciphers off;
|
|
ssl_session_cache shared:SSL:10m;
|
|
ssl_session_timeout 10m;
|
|
ssl_session_tickets off;
|
|
ssl_stapling on;
|
|
ssl_stapling_verify on;
|
|
|
|
# Security headers with HSTS
|
|
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 Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
|
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none';" always;
|
|
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
|
|
|
|
# Client max body size for large image uploads
|
|
client_max_body_size 2G;
|
|
client_body_timeout 60s;
|
|
client_header_timeout 60s;
|
|
|
|
# Rate limiting for write operations
|
|
limit_req zone=push burst=10 nodelay;
|
|
|
|
# Rate limiting for login attempts
|
|
location ~ ^/v2/.*/blobs/uploads/ {
|
|
limit_req zone=login burst=3 nodelay;
|
|
auth_basic "Docker Registry v2";
|
|
auth_basic_user_file /etc/nginx/.htpasswd;
|
|
proxy_pass http://registry;
|
|
proxy_set_header Host $http_host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_read_timeout 900;
|
|
proxy_connect_timeout 60;
|
|
proxy_send_timeout 60;
|
|
proxy_buffering off;
|
|
proxy_request_buffering off;
|
|
proxy_hide_header X-Powered-By;
|
|
proxy_hide_header Server;
|
|
}
|
|
|
|
# Basic authentication for write operations
|
|
location ~ ^/v2/.*$ {
|
|
# Require auth for all v2 API operations
|
|
auth_basic "Docker Registry v2";
|
|
auth_basic_user_file /etc/nginx/.htpasswd;
|
|
|
|
proxy_pass http://registry;
|
|
proxy_set_header Host $http_host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_read_timeout 900;
|
|
proxy_connect_timeout 60;
|
|
proxy_send_timeout 60;
|
|
proxy_buffering off;
|
|
proxy_request_buffering off;
|
|
proxy_hide_header X-Powered-By;
|
|
proxy_hide_header Server;
|
|
}
|
|
|
|
# Block access to hidden files
|
|
location ~ /\. {
|
|
deny all;
|
|
access_log off;
|
|
log_not_found off;
|
|
}
|
|
|
|
# Block access to sensitive files
|
|
location ~* \.(htaccess|htpasswd|ini|log|sh|sql|conf)$ {
|
|
deny all;
|
|
access_log off;
|
|
log_not_found off;
|
|
}
|
|
|
|
location / {
|
|
return 404;
|
|
}
|
|
|
|
access_log /var/log/nginx/registry_auth_access.log;
|
|
error_log /var/log/nginx/registry_auth_error.log;
|
|
}
|
|
}
|