把一个 OpenResty 站点变成 Docker Hub 镜像

TL;DR

将下面的代码粘贴到 OpenResty 站点配置 (server { } 块)内即可。

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains"; 
    client_max_body_size 0;
    chunked_transfer_encoding on;
    resolver 8.8.8.8 1.1.1.1 valid=300s;
    
    
    location /token {
        proxy_pass https://auth.docker.io;
        proxy_set_header Host auth.docker.io;
        proxy_ssl_server_name on;
    }

    location /v2/ {
        proxy_pass https://registry-1.docker.io;
        proxy_set_header Host registry-1.docker.io;
        proxy_ssl_server_name on;
        proxy_set_header Authorization $http_authorization;

        proxy_hide_header WWW-Authenticate;
        add_header WWW-Authenticate 'Bearer realm="https://$http_host/token",service="registry.docker.io"' always;

        proxy_redirect ~^https://([^/]+)/(.*)$ /blob/$1/$2;

        proxy_buffering off;
        proxy_read_timeout 900;
    }

    location ~ ^/blob/(?<blob_host>[^/]+)/(?<blob_path>.*)$ {
        access_by_lua_block {
            local host = ngx.var.blob_host

            local allowed = host:match("%.docker%.io$")
                or host:match("%.docker%.com$")
                or host:match("%.cloudflare%.docker%.com$")
                or host:match("%.amazonaws%.com$")
                or host == "docker.io"

            if not allowed then
                ngx.log(ngx.WARN, "rejected proxy target: ", host)
                return ngx.exit(403)
            end
        }

        proxy_pass https://$blob_host/$blob_path$is_args$args;
        proxy_set_header Host $blob_host;
        proxy_ssl_server_name on;
        proxy_ssl_name $blob_host;

        proxy_buffering off;
        proxy_read_timeout 900;
    }

补充说明

缓存问题

这个代码只是作为反向代理,使得 Docker 可以透过它去拉取镜像,并不会真的将镜像存储于你的服务器,所以每次请求的时候都会真的走一遍完整的流量,通过 CloudFlare + 缓存控制可缓解该问题。