Skip to content

Instantly share code, notes, and snippets.

@zekiunal
Last active June 5, 2024 12:14
Show Gist options
  • Save zekiunal/b6dca9a5c0f978d72d403d905ec96ede to your computer and use it in GitHub Desktop.
Save zekiunal/b6dca9a5c0f978d72d403d905ec96ede to your computer and use it in GitHub Desktop.

İçindekiler

Gereksinimler

  • Docker ve Docker Compose yüklü olmalıdır.
  • Let's Encrypt tarafından sağlanan domain sertifikaları (örneğin, fullchain.pem ve privkey.pem).

Kurulum

Adım 1: Let's Encrypt ile Domain Sertifikalarının Oluşturulması

Let's Encrypt ile domain sertifikalarını oluşturmak için certbot kullanabilirsiniz. Aşağıdaki komutlar, portus.mydomain.com ve registry.mydomain.com domainleri için sertifika oluşturur:

docker run -it --rm --name certbot -p 80:80 -v "/etc/letsencrypt:/etc/letsencrypt" -v "/var/lib/letsencrypt:/var/lib/letsencrypt" certbot/certbot certonly --test-cert --standalone -d portus.mydomain.com --email [email protected]  --agree-tos
docker run -it --rm --name certbot -p 80:80 -v "/etc/letsencrypt:/etc/letsencrypt" -v "/var/lib/letsencrypt:/var/lib/letsencrypt" certbot/certbot certonly --test-cert --standalone -d registry.mydomain.com --email [email protected]  --agree-tos

Sertifikalar başarıyla oluşturulduktan sonra, sertifika ve anahtar dosyaları şu dizinde bulunacaktır:

/etc/letsencrypt/live/portus.mydomain.com/
/etc/letsencrypt/live/registry.mydomain.com/

Adım 2: Portus Auth Service RSA Sertifikalarının Oluşturulması

RSA anahtar çifti ve sertifika oluşturmak için aşağıdaki komutları kullanın:

# Özel anahtarı oluşturma
openssl genrsa -out secrets/auth_service_private.key 2048

# Public key dosyasını oluşturma
openssl rsa -in secrets/auth_service_private.key -pubout -out secrets/auth_service_public.pem

# Public key dosyasını bir sertifika olarak kaydedin
openssl req -new -x509 -key secrets/auth_service_private.key -out secrets/auth_service_public.crt -days 365

Dosya yapınız şu şekilde olmalıdır:

secrets/
├── auth_service_private.key
├── auth_service_public.pem
└── auth_service_public.crt

Adım 3: Registry Init Dosyasının Oluşturulması

Docker Registry'nin başlatılması sırasında kullanılacak init script'i oluşturun:

registry/init:

#!/bin/sh

set -x

# Public key dosyasını CA sertifikaları dizinine kopyalama
cp /secrets/auth_service_public.crt /usr/local/share/ca-certificates/auth_service_public.crt

# CA sertifikalarını güncelleme
update-ca-certificates

# Docker Registry'yi başlatma
registry serve /etc/docker/registry/config.yml

Bu dosyanın çalıştırılabilir olduğundan emin olun:

chmod +x registry/init

Adım 4: Portus Nginx Konfigürasyonu

Nginx konfigürasyon dosyasını oluşturun:

nginx/conf.d/portus.conf:

upstream portus {
    least_conn;
    server portus:3000 max_fails=3 fail_timeout=15s;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name portus.mydomain.com;
    root /srv/Portus/public;

    # Added By AI
    http2 on;

    # SSL
    ssl_certificate /etc/letsencrypt/live/portus.mydomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/portus.mydomain.com/privkey.pem;

    # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
    ssl_protocols TLSv1.2;

    # Ciphers chosen for forward secrecy and compatibility.
    #
    # http://blog.ivanristic.com/2013/08/configuring-apache-nginx-and-openssl-for-forward-secrecy.html
    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:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;

    # Added By AI
    ssl_session_timeout 10m;

    # OCSP Stapling - Added By AI
    #ssl_stapling on;
    #ssl_stapling_verify on;
    #ssl_trusted_certificate /etc/letsencrypt/live/portus.mydomain.com/fullchain.pem;

    # HSTS - Added By AI
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # Don't allow the browser to render the page inside a frame or iframe
    # and avoid Clickjacking. More in the following link:
    #
    # https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options
    add_header X-Frame-Options DENY;

    # Disable content-type sniffing on some browsers.
    add_header X-Content-Type-Options nosniff;

    # This header enables the Cross-site scripting (XSS) filter built into
    # most recent web browsers. It's usually enabled by default anyway, so the
    # role of this header is to re-enable the filter for this particular
    # website if it was disabled by the user.
    add_header X-XSS-Protection "1; mode=block";

    # Add header for IE in compatibility mode.
    add_header X-UA-Compatible "IE=edge";

    # Portus needs to handle /v2/token for authentication
    location = /v2/token {
        proxy_pass                          https://portus;
        proxy_set_header Host               $http_host;   # required for docker client's sake
        proxy_set_header X-Real-IP          $remote_addr; # pass on real client's IP
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_read_timeout                  900;
        proxy_buffering                     on;
    }

    # Portus needs to handle /v2/webhooks/events for notifications
    location = /v2/webhooks/events {
        proxy_pass                          https://portus;
        proxy_set_header Host               $http_host;   # required for docker client's sake
        proxy_set_header X-Real-IP          $remote_addr; # pass on real client's IP
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_read_timeout                  900;
        proxy_buffering                     on;
    }

    # Assets are mapped inside of /srv/Portus/public from a shared volume.
    location ~ ^/(assets)/ {
        access_log                  off;
        gzip_static                 on;
        expires                     max;
        add_header  Cache-Control   public;
        add_header  Last-Modified   "";
        add_header  ETag            "";
        break;
    }

    # Portus handles everything else for the UI
    location / {
      try_files $uri/index.html $uri.html $uri @portus;
    }

    location @portus {
        proxy_pass                          https://portus;
        proxy_set_header Host               $http_host;   # required for docker client's sake
        proxy_set_header X-Real-IP          $remote_addr; # pass on real client's IP
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_read_timeout                  900;
        proxy_buffering on;
    }
}

Adım 5: Registry Nginx Konfigürasyonu

Nginx konfigürasyon dosyasını oluşturun:

nginx/conf.d/registry.conf:

# See https://distribution.github.io/distribution/recipes/nginx/

upstream registry {
  least_conn;
  server registry:5000 max_fails=3 fail_timeout=15s;
}

## Set a variable to help us decide if we need to add the
## 'Docker-Distribution-Api-Version' header.
## The registry always sets this header.
## In the case of nginx performing auth, the header is unset
## since nginx is auth-ing before proxying.
map $upstream_http_docker_distribution_api_version $docker_distribution_api_version {
  '' 'registry/2.0';
}

log_format registry '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  server_name registry.mydomain.com;

    # Added By AI
    http2 on;

    # SSL
    ssl_certificate /etc/letsencrypt/live/registry.mydomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/registry.mydomain.com/privkey.pem;

    # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
    ssl_protocols TLSv1.2 TLSv1.3;

    # Ciphers chosen for forward secrecy and compatibility.
    #
    # http://blog.ivanristic.com/2013/08/configuring-apache-nginx-and-openssl-for-forward-secrecy.html
    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:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;

    # Added By AI
    ssl_session_timeout 10m;

    # OCSP Stapling - Added By AI
    #ssl_stapling on;
    #ssl_stapling_verify on;
    #ssl_trusted_certificate /etc/letsencrypt/live/registry.mydomain.com/fullchain.pem;

    # HSTS - Added By AI
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # Don't allow the browser to render the page inside a frame or iframe
    # and avoid Clickjacking. More in the following link:
    #
    # https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options
    add_header X-Frame-Options DENY;

    # Disable content-type sniffing on some browsers.
    add_header X-Content-Type-Options nosniff;

    # This header enables the Cross-site scripting (XSS) filter built into
    # most recent web browsers. It's usually enabled by default anyway, so the
    # role of this header is to re-enable the filter for this particular
    # website if it was disabled by the user.
    add_header X-XSS-Protection "1; mode=block";

    # Add header for IE in compatibility mode.
    add_header X-UA-Compatible "IE=edge";

    # disable any limits to avoid HTTP 413 for large image uploads
    client_max_body_size 0;

    # required to avoid HTTP 411: see Issue #1486 (https://github.com/moby/moby/issues/1486)
    chunked_transfer_encoding on;

    location /v2/ {
        # Do not allow connections from docker 1.5 and earlier
        # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
        if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
           return 404;
        }

        ## If $docker_distribution_api_version is empty, the header is not added.
        ## See the map directive above where this variable is defined.
        add_header 'Docker-Distribution-Api-Version' $docker_distribution_api_version always;

        proxy_pass                          https://registry;
        proxy_set_header Host               $http_host;   # required for docker client's sake
        proxy_set_header X-Real-IP          $remote_addr; # pass on real client's IP
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_read_timeout                  900;
        proxy_buffering on;

        # These headers are required for Docker to trust the registry
        # certificate and enable client-side certificate validation
        #proxy_ssl_verify on;
        #proxy_ssl_trusted_certificate /etc/letsencrypt/live/registry.mydomain.com/fullchain.pem;
        #proxy_ssl_session_reuse off;

        access_log      /var/log/nginx/registry.access.log registry;
        error_log       /var/log/nginx/registry.error.log;
    }
}

Adım 6: Registry Config.yml

Docker Registry için konfigürasyon dosyasını oluşturun:

registry/config.yml:

version: 0.1
storage:
  filesystem:
    rootdirectory: /var/lib/registry
  delete:
    enabled: true
http:
  addr: 0.0.0.0:5000
  debug:
    addr: 0.0.0.0:5001
redis:
  addr: redis:6379
  pool:
    maxidle: 16
    maxactive: 64
  dialtimeout: 200ms
  readtimeout: 200ms
  writetimeout: 200ms
auth:
  token:
    realm: https://${PORTUS_FQDN}/v2/token
    service: ${REGISTRY_FQDN}
    issuer: ${PORTUS_FQDN}
    rootcertbundle: /secrets/auth_service_public.crt
notifications:
  endpoints:
    - name: portus
      url: https://${PORTUS_FQDN}/v2/webhooks/events
      timeout: 2000ms
      threshold: 5
      backoff: 1s

Adım 7: .env Dosyası

Ortam değişkenlerini tanımlamak için .env dosyasını oluşturun:

.env:

REGISTRY_FQDN=registry.mydomain.com
REGISTRY_SECRET=zyLUImiMWrKIeoyuYUBRl22b3UG3jeFIIZktYubTlITxciXcU9ed4jBUoDrq7zMkg9w7D8moWGPK2Xjgsfdsfd3HxE68d6dDC45HGyOB9rBdP4kAWoixCKbRyp8RvX63aWmHH9dq0RJblQEQOJQZEzqEjwxESlS0OqtUW7obe2McjXesTUYbWhiK1KonSI5vsNBrCcJ2byYBj8TtJRen7Xzmdfsfi3YBfSRFOGRa6g0nFLUgKZhXSuoWmn

DATABASE_NAME=portus
DATABASE_PASSWORD=example

PORTUS_PASSWORD=12345678
PORTUS_FQDN=portus.mydomain.com

Adım 8: Docker Compose Dosyasını Oluşturma

docker-compose.yml dosyasını aşağıdaki gibi oluşturun:

docker-compose.yml:

version: '3.8'

services:
  redis:
    image: redis:latest
    container_name: redis
    ports:
      - "6379:6379"

  registry:
    image: registry:2.8.3
    command: [ "/bin/sh", "/etc/docker/registry/init" ]
    environment:
      REGISTRY_HTTP_SECRET: ${REGISTRY_SECRET}
      REGISTRY_AUTH_TOKEN_REALM: https://${PORTUS_FQDN}/v2/token
      REGISTRY_AUTH_TOKEN_SERVICE: ${REGISTRY_FQDN}
      REGISTRY_AUTH_TOKEN_ISSUER: ${PORTUS_FQDN}
      REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE: /secrets/auth_service_public.crt

      # SSL
      REGISTRY_HTTP_TLS_CERTIFICATE: /etc/letsencrypt/live/registry.mydomain.com/fullchain.pem
      REGISTRY_HTTP_TLS_KEY: /etc/letsencrypt/live/registry.mydomain.com/privkey.pem

      # REDIS
      REGISTRY_REDIS_ADDR: redis:6379

      # Portus endpoint
      REGISTRY_NOTIFICATIONS_ENDPOINTS: >
        - name: portus
          url: https://${PORTUS_FQDN}/v2/webhooks/events
          timeout: 2000ms
          threshold: 5
          backoff: 1s
    volumes:
      - ./registry/config.yml:/etc/docker/registry/config.yml:ro
      - ./registry/init:/etc/docker/registry/init:ro
      - /etc/letsencrypt:/etc/letsencrypt:ro
      - ./secrets:/secrets:ro
    ports:
      - "5000:5000"
      - "5001:5001" # required to access debug service
    links:
      - redis:redis
      - portus:portus

  portus:
    image: opensuse/portus:2.4.3
    platform: linux/amd64
    environment:
      - PORTUS_MACHINE_FQDN_VALUE=${PORTUS_FQDN}
      - PORTUS_DB_HOST=db
      - PORTUS_DB_DATABASE=${DATABASE_NAME}
      - PORTUS_DB_PASSWORD=${DATABASE_PASSWORD}
      - PORTUS_DB_POOL=5
      - PORTUS_SECRET_KEY_BASE=${REGISTRY_SECRET}
      - PORTUS_KEY_PATH=/secrets/auth_service_private.key
      - PORTUS_PASSWORD=${PORTUS_PASSWORD}
      - PORTUS_PUMA_TLS_KEY=/etc/letsencrypt/live/portus.mydomain.com/privkey.pem
      - PORTUS_PUMA_TLS_CERT=/etc/letsencrypt/live/portus.mydomain.com/fullchain.pem
    ports:
      - "3000:3000"
    links:
      - db
    volumes:
      - /etc/letsencrypt:/etc/letsencrypt:ro
      - ./secrets:/secrets:ro
      - static:/srv/Portus/public

  background:
    image: opensuse/portus:2.4.3
    platform: linux/amd64
    depends_on:
      - portus
      - db
    environment:
      - PORTUS_MACHINE_FQDN_VALUE=${PORTUS_FQDN}
      - CCONFIG_PREFIX=PORTUS
      - PORTUS_DB_HOST=db
      - PORTUS_DB_DATABASE=${DATABASE_NAME}
      - PORTUS_DB_PASSWORD=${DATABASE_PASSWORD}
      - PORTUS_DB_POOL=5
      - PORTUS_SECRET_KEY_BASE=${REGISTRY_SECRET}
      - PORTUS_KEY_PATH=/secrets/auth_service_private.key
      - PORTUS_PASSWORD=${PORTUS_PASSWORD}
      - PORTUS_BACKGROUND=true
    links:
      - db
    volumes:
      - /etc/letsencrypt:/etc/letsencrypt:ro
      - ./secrets:/secrets:ro

  db:
    image: mariadb
    command: ["--character-set-server=utf8", "--collation-server=utf8_unicode_ci"]
    environment:
      - MARIADB_DATABASE=${DATABASE_NAME}
      - MARIADB_ROOT_PASSWORD=${DATABASE_PASSWORD}
      - MARIADB_CHARSET=utf8
      - MARIADB_COLLATION=utf8_unicode_ci
    ports:
      - "3306:3306"

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    links:
      - registry:registry
      - portus:portus
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - /etc/letsencrypt:/etc/letsencrypt
      - ./logs/nginx:/var/log/nginx
      - static:/srv/Portus/public:ro

volumes:
  static:
    driver: local

Adım 9: Projeyi Başlatma

docker-compose up

Yol Haritası

Production ortamında Docker Registry'yi kurarken aşağıdaki adımları takip etmek önemlidir:

  • SSL/TLS kullanarak güvenlik sağlama.
  • Kimlik doğrulama ve yetkilendirme yapılandırma.
  • Depolama sürücüsünü uygun şekilde yapılandırma.
  • Performansı artırmak için cache ve yük dengeleme kullanma.
  • Loglama ve izleme sistemleri kurma.
  • Düzenli yedekleme ve geri yükleme stratejileri oluşturma.
  • Yüksek erişilebilirlik sağlama.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment