Aliyun OSS Nginx proxy module(阿里云OSS Nginx 签名代理模块)

本文涉及的产品
对象存储 OSS,20GB 3个月
日志服务 SLS,月写入数据量 50GB 1个月
文件存储 NAS,50GB 3个月
简介: OSS Nginx proxy module

1、此文章主要介绍内容

本文主要介绍如何利用Nginx lua 实现将阿里云OSS存储空间做到同本地磁盘一样使用。核心是利用Nginx lua 对OSS请求进行签名并利用内部跳转将所有访问本地Nginx的请求加上OSS 签名转发给OSS,实现本地Nginx无缝衔接阿里云OSS,存储空间无限扩展,存储成本无限下降,数据安全%99.99...... 。

2、本篇文章使用到的一些工具技术及如何学习和获取

1、lua

本文用到的都是一些基本的lua,基本上花半小时阅读下lua的语法就可以轻松理解本文内容

2、Nginx lua

主要是学习nginx lua 及环境部署,不过阅读本文还不需要亲自动手去学习及部署nginx lua 环境,读者可以从docker 官方镜像源pull openresty 镜像进行实验。本文已openresty/1.7.7.2 作为实验环境。

3、阿里云OSS

赶紧开通吧,用起来相当爽,一处存储全球无限制访问
https://www.aliyun.com/act/aliyun/ossdoc.html

4、参考博客

建议阅读我的另外一篇博客,对深入理解OSS 及互联网上提供的HTTP服务有更深刻的理解
https://yq.aliyun.com/articles/7511?spm=0.0.0.0.IWbHSR

3、利用Nginx lua 实现请求签名并转发至OSS

Lua 签名 code
注:此代码并非出自作者之手
oss_auth.lua


-- has been sorted in alphabetical order
local signed_subresources = {
   'acl',
   'append',
   'bucketInfo',
   'cname',
   'commitTransition',
   'comp',
   'cors',
   'delete',
   'lifecycle',
   'location',
   'logging',
   'mime',
   'notification',
   'objectInfo',
   'objectMeta',
   'partData',
   'partInfo',
   'partNumber',
   'policy',
   'position',
   'referer',
   'replication',
   'replicationLocation',
   'replicationProgress',
   'requestPayment',
   'response-cache-control',
   'response-content-disposition',
   'response-content-encoding',
   'response-content-language',
   'response-content-type',
   'response-expires',
   'restore',
   'security-token',
   'tagging',
   'torrent',
   'uploadId',
   'uploads',
   'versionId',
   'versioning',
   'versions',
   'website'
}
   
function string.startswith(s, start)
   return string.sub(s, 1, string.len(start)) == start
end

local function get_canon_sub_resource()
   local args = ngx.req.get_uri_args()
   -- lower keys
   local keys = {}
   for k, v in pairs(args) do
      keys[k:lower()] = v
   end
   -- make resource string
   local s = ''
   local sep = '?'
   for i, k in ipairs(signed_subresources) do
      v = keys[k]
      if v then
         -- sub table
         v = type(v) == 'table' and v[1] or v
         s = s .. string.format("%s%s=%s", sep, k, v)
         sep = '&'
      end
   end
   return s
end

local function get_canon_resource()
   resource = ''
   object = ngx.unescape_uri(ngx.var.uri)
   sub = get_canon_sub_resource()   
   return string.format("/%s%s%s", ngx.var.oss_bucket, object, sub)
end   

local function get_canon_headers()
   -- default: <lowerkey, value>
   local headers = ngx.req.get_headers()
   local keys = {}
   for k, v in pairs(headers) do
      if string.startswith(k, 'x-oss-') then
         -- client must assemble the same header keys
         if type(v) ~= 'string' then return nil end
         table.insert(keys, k)
      end
   end
   -- sorted in alphabetical order
   table.sort(keys)
   for i, key in ipairs(keys) do
      keys[i] = key .. ':' .. headers[key] .. '\n'
   end
   return table.concat(keys)
end

local function calc_sign(key, method, md5, type_, date, oss_headers, resource)
    -- string_to_sign:
    -- method + '\n' + content_md5 + '\n' + content_type + '\n'
    -- + date + '\n' + canonicalized_oss_headers + canonicalized_resource
    local sign_str = string.format('%s\n%s\n%s\n%s\n%s%s',
    method, md5, type_,
    date, oss_headers, resource)
    ngx.log(ngx.ERR, "SignStr:", sign_str, "\n")
    local sign_result = ngx.encode_base64(ngx.hmac_sha1(key, sign_str))
    return sign_result, sign_str
end   

local function oss_auth()
   -- ngx.log(ngx.INFO, 'auth')
   --local method = ngx.var.request_method
   local method = ngx.req.get_method()
   local content_md5 = ngx.var.http_content_md5 or ''
   local content_type = ngx.var.http_content_type or ''
   -- get date
   local date = ngx.var.http_x_oss_date or ngx.var.http_date or ''
   if date == '' then
      date = ngx.http_time(ngx.time())
      -- ngx.log(ngx.INFO, 'Date:', date)
      ngx.req.set_header('Date', date)
   end
   local resource = get_canon_resource()
   local canon_headers = get_canon_headers()
   local sign_result, sign_str = calc_sign(ngx.var.oss_auth_key, method, content_md5,
   content_type, date, canon_headers, resource)
   -- ngx.log(ngx.INFO, 'sign string:', sign_str)
   -- ngx.log(ngx.INFO, 'sign string len:', string.len(sign_str))
   local auth = string.format("OSS %s:%s", ngx.var.oss_auth_id, sign_result)
   ngx.req.set_header('Authorization', auth)
   ngx.exec("@oss")
end   

-- main
res = oss_auth()

if res then
   ngx.exit(res)
end

nginx.conf

  server {
        listen 8000;

        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_request_buffering off;

        location / {
            set $oss_bucket "your_oss_bucket";
            set $oss_auth_id "your_access_id";
            set $oss_auth_key "your_access_key";
            rewrite_by_lua_file "/path/oss_auth.lua";
        }

        # internal redirect
        location @oss {
            // endpoint eg: oss.aliyuncs.com
            proxy_pass http://your_oss_bucket.endpoint; 
        }
    }

4、如何使用上述代码

首先oss_auth.lua 无需做任何改动

nginx.conf 中需要将
your_oss_bucket 替换为阿里云OSS 的bucket名
your_access_id替换为AccessKeyId
your_access_key 替换为 AccessKeySecret

例如:

error_log  logs/error.log  debug;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    lua_package_path "/usr/servers/lualib/?.lua;";
    lua_package_cpath "/usr/servers/lualib/?.so;"; 
    server {
        listen       80;
        location / {
            set $oss_bucket "bucket-example";
            set $oss_auth_id "za2127hbbdsdjhkhskel0ytocbzr";
            set $oss_auth_key "gMOG3o+JHDSJHCNMcsaH+Q=";
            rewrite_by_lua_file conf/lua/oss_auth.lua;
        }

        location @oss {
            proxy_pass http://bucket-example.oss-cn-qingdao.aliyuncs.com;
        }
    }
}
相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
目录
相关文章
|
5月前
|
机器学习/深度学习 人工智能 专有云
人工智能平台PAI使用问题之怎么将DLC的数据写入到另一个阿里云主账号的OSS中
阿里云人工智能平台PAI是一个功能强大、易于使用的AI开发平台,旨在降低AI开发门槛,加速创新,助力企业和开发者高效构建、部署和管理人工智能应用。其中包含了一系列相互协同的产品与服务,共同构成一个完整的人工智能开发与应用生态系统。以下是对PAI产品使用合集的概述,涵盖数据处理、模型开发、训练加速、模型部署及管理等多个环节。
|
1月前
|
分布式计算 Java 开发工具
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
|
4月前
|
存储 机器学习/深度学习 弹性计算
阿里云EMR数据湖文件系统问题之OSS-HDFS全托管服务的问题如何解决
阿里云EMR数据湖文件系统问题之OSS-HDFS全托管服务的问题如何解决
|
5月前
|
消息中间件 分布式计算 DataWorks
DataWorks产品使用合集之如何使用Python和阿里云SDK读取OSS中的文件
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
5月前
|
存储 运维 安全
阿里云OSS的优势
【7月更文挑战第19天】阿里云OSS的优势
243 2
|
5月前
|
存储 API 开发工具
阿里云OSS
【7月更文挑战第19天】阿里云OSS
208 1
|
5月前
|
存储 弹性计算 对象存储
预留空间是什么?阿里云OSS对象存储预留空间说明
阿里云OSS预留空间是预付费存储产品,提供折扣价以锁定特定容量,适用于抵扣有地域属性的Bucket标准存储费用及ECS快照费。通过购买预留空间,如500GB通用预留+100GB标准-本地冗余存储包,用户可优化成本。
232 4
|
5月前
|
人工智能 对象存储
【阿里云AI助理】自家产品提供错误答案。阿里云OSS 资源包类型: 下行流量 地域: 中国内地通用 下行流量包规格: 300 GB 套餐: 下行流量包(中国内地) ,包1年。那么这个是每月300GB,1年是3600GB的流量;还是1年只有300GB的流量?
自家产品提供错误答案。阿里云OSS 资源包类型: 下行流量 地域: 中国内地通用 下行流量包规格: 300 GB 套餐: 下行流量包(中国内地) ,包1年。那么这个是每月300GB,1年是3600GB的流量;还是1年只有300GB的流量?
142 1
|
5月前
|
持续交付 开发工具 对象存储
阿里云云效产品使用合集之构建物如何上传到阿里云OSS
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
5月前
|
缓存 对象存储 数据安全/隐私保护
阿里云OSS, 跨域请求, No ‘Access-Control-Allow-Origin‘
阿里云OSS, 跨域请求, No ‘Access-Control-Allow-Origin‘
788 0

相关产品

  • 对象存储