env AWS_ACCESS_KEY_ID; env AWS_SECRET_ACCESS_KEY; env S3_BUCKET_NAME; env AWS_REGION; env RETURN_URL; worker_processes 1; events { worker_connections 1024; } http { lua_load_resty_core off; lua_package_path "/tmp/lua-resty-core/lib/?.lua;/tmp/lua-resty-http/lib/?.lua;/tmp/lua/?.lua;;"; lua_package_cpath '/usr/lib/x86_64-linux-gnu/lua/5.1/?.so;;'; lua_socket_buffer_size 128k; client_max_body_size 10m; client_body_buffer_size 10m; server { listen 80; location /healthcheck { add_header Content-Type text/plain; return 200 'Ok'; access_log off; } location ~ ^/upload { if ($request_method = 'OPTIONS') { # Tell client that this pre-flight info is valid for 20 days add_header 'Access-Control-Allow-Origin' "*" ; add_header 'Access-Control-Allow-Credentials' 'true' ; add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS' ; add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With'; add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain charset=UTF-8'; add_header 'Content-Length' 0; return 204; } if ($request_method != PUT) { return 404; } set_secure_random_alphanum $prefix 64; set_sha1 $prefixsha $prefix; set_by_lua $time "os.time()"; set_by_lua $timestamp "return os.date('%Y%m%dT%H%M%SZ', tonumber(ngx.var.time))"; set_by_lua $date "return os.date('%a, %d %b %Y %H:%M:%S GMT', tonumber(ngx.var.time))"; set_by_lua $day "return os.date('%Y%m%d', tonumber(ngx.var.time))"; set_sha1 $datesha $date; set $key $prefixsha$datesha; set_by_lua $bucket "return os.getenv('S3_BUCKET_NAME')"; set_by_lua $baseurl "return os.getenv('RETURN_URL')"; set_by_lua $region "return os.getenv('AWS_REGION')"; set $phost $bucket.s3-$region.amazonaws.com; set $ppath /$day/$key; set $url https://$phost$ppath; set $returnurl https://$baseurl$ppath; set $acl public-read; set $contentSha256 "UNSIGNED-PAYLOAD"; set $authorization ""; set $token ""; access_by_lua_block { local sha2 = require("sha2") local fetcher = require("fetcher") local sign = require("sign") local key, secret, token = fetcher.fetch() local headers = {["x-amz-acl"] = ngx.var.acl, ["x-amz-date"] = ngx.var.timestamp, ["x-amz-content-sha256"] = ngx.var.contentSha256, ["date"] = ngx.var.date, ["host"] = ngx.var.phost } if token then ngx.var.token = token headers["x-amz-security-token"] = token end ngx.var.authorization = sign.sign(key, secret, os.time(), ngx.var.ppath, headers, ngx.var.region) } proxy_set_header date $date; proxy_set_header host $phost; proxy_set_header x-amz-acl $acl; proxy_set_header x-amz-date $timestamp; proxy_set_header x-amz-security-token $token; proxy_set_header x-amz-content-sha256 $contentSha256; proxy_set_header Authorization $authorization; proxy_hide_header x-amz-id-2; proxy_hide_header x-amz-request-id; add_header X-File-URL $returnurl; resolver 8.8.8.8 valid=300s; resolver_timeout 10s; add_header 'Access-Control-Expose-Headers' 'X-File-Url'; add_header 'Access-Control-Allow-Origin' "*" ; add_header 'Access-Control-Allow-Credentials' 'true' ; add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS' ; add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With'; add_header 'Access-Control-Max-Age' 1728000; proxy_pass $url; } location ~ ^/put/(.+)$ { if ($request_method = 'OPTIONS') { # Tell client that this pre-flight info is valid for 20 days add_header 'Access-Control-Allow-Origin' "*" ; add_header 'Access-Control-Allow-Credentials' 'true' ; add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS' ; add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With'; add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain charset=UTF-8'; add_header 'Content-Length' 0; return 204; } if ($request_method != PUT) { return 404; } set_by_lua $time "os.time()"; set_by_lua $timestamp "return os.date('%Y%m%dT%H%M%SZ', tonumber(ngx.var.time))"; set_by_lua $date "return os.date('%a, %d %b %Y %H:%M:%S GMT', tonumber(ngx.var.time))"; set_by_lua $bucket "return os.getenv('S3_BUCKET_NAME')"; set_by_lua $baseurl "return os.getenv('RETURN_URL')"; set_by_lua $region "return os.getenv('AWS_REGION')"; set $phost $bucket.s3-$region.amazonaws.com; set $ppath /$1; set $url https://$phost$ppath; set $returnurl https://$baseurl$ppath; set $acl public-read; set $contentSha256 "UNSIGNED-PAYLOAD"; set $authorization ""; set $token ""; access_by_lua_block { local sha2 = require("sha2") local fetcher = require("fetcher") local sign = require("sign") local key, secret, token = fetcher.fetch() local headers = {["x-amz-acl"] = ngx.var.acl, ["x-amz-date"] = ngx.var.timestamp, ["x-amz-content-sha256"] = ngx.var.contentSha256, ["date"] = ngx.var.date, ["host"] = ngx.var.phost } if token then ngx.var.token = token headers["x-amz-security-token"] = token end ngx.var.authorization = sign.sign(key, secret, os.time(), ngx.var.ppath, headers, ngx.var.region) } proxy_set_header date $date; proxy_set_header host $phost; proxy_set_header x-amz-acl $acl; proxy_set_header x-amz-date $timestamp; proxy_set_header x-amz-security-token $token; proxy_set_header x-amz-content-sha256 $contentSha256; proxy_set_header Authorization $authorization; proxy_hide_header x-amz-id-2; proxy_hide_header x-amz-request-id; add_header X-File-URL $returnurl; resolver 8.8.8.8 valid=300s; resolver_timeout 10s; add_header 'Access-Control-Expose-Headers' 'X-File-Url'; add_header 'Access-Control-Allow-Origin' "*" ; add_header 'Access-Control-Allow-Credentials' 'true' ; add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS' ; add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With'; add_header 'Access-Control-Max-Age' 1728000; proxy_pass $url; } } }