DeOldify API安全接入指南:Nginx反向代理+Token鉴权配置方案

1. 为什么需要API安全防护?

如果你已经部署了DeOldify图像上色服务,可能会发现一个问题:你的API接口是直接暴露在公网上的。这意味着任何人都可以访问你的服务,不仅可能导致:

  • 服务被滥用:大量请求消耗你的计算资源
  • 数据泄露风险:上传的图片可能包含敏感信息
  • 费用失控:如果按使用量计费,可能产生意外费用
  • 服务不稳定:恶意请求可能导致服务崩溃

想象一下,你开了一家自助餐厅,所有人都可以免费进来吃饭,而且没有人数限制。很快,餐厅就会被挤爆,食材被消耗殆尽,正常顾客反而吃不上饭。API服务也是同样的道理。

今天,我就来分享一套完整的API安全接入方案,用Nginx反向代理加上Token鉴权,给你的DeOldify服务加上一道安全门。

2. 整体架构设计

在开始配置之前,我们先看看整个安全架构是什么样的:

┌─────────────────────────────────────────────────────────────┐
│                   外部用户访问                                │
│                                                             │
│  https://api.yourdomain.com/colorize?token=your_token      │
│                                                             │
└──────────────────────────┬──────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                    Nginx反向代理服务器                        │
│                                                             │
│  1. 验证Token有效性                                        │
│  2. 限制请求频率                                           │
│  3. 记录访问日志                                           │
│  4. 转发合法请求到后端服务                                  │
│                                                             │
└──────────────────────────┬──────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                   DeOldify服务 (7860端口)                    │
│                                                             │
│  只接收来自Nginx的请求                                      │
│  不直接暴露给公网                                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

这个架构有几个关键好处:

  1. 安全性:API不再直接暴露,所有请求都经过Nginx过滤
  2. 可控性:可以精确控制谁可以访问、访问频率是多少
  3. 可扩展性:未来可以轻松添加更多安全策略
  4. 监控性:所有访问都有日志记录,便于分析和审计

3. Nginx反向代理配置

3.1 安装Nginx

如果你还没有安装Nginx,先来安装一下:

# Ubuntu/Debian系统
sudo apt update
sudo apt install nginx -y

# CentOS/RHEL系统
sudo yum install epel-release -y
sudo yum install nginx -y

# 启动Nginx
sudo systemctl start nginx
sudo systemctl enable nginx

# 检查状态
sudo systemctl status nginx

3.2 基础反向代理配置

我们先创建一个基础的Nginx配置文件,把请求转发到DeOldify服务:

# 创建配置文件
sudo nano /etc/nginx/sites-available/deoldify-api

把下面的配置内容复制进去:

server {
    listen 80;
    server_name api.yourdomain.com;  # 改成你的域名或IP
    
    # 访问日志
    access_log /var/log/nginx/deoldify_access.log;
    error_log /var/log/nginx/deoldify_error.log;
    
    # 限制请求体大小(50MB)
    client_max_body_size 50M;
    
    # 超时设置
    proxy_connect_timeout 300s;
    proxy_send_timeout 300s;
    proxy_read_timeout 300s;
    
    # 健康检查接口(公开访问)
    location /health {
        proxy_pass http://localhost:7860/health;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        # 添加CORS头
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
        add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
        
        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
            add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
            add_header Access-Control-Max-Age 1728000;
            add_header Content-Type 'text/plain; charset=utf-8';
            add_header Content-Length 0;
            return 204;
        }
    }
    
    # 图片上色接口(需要Token验证)
    location /colorize {
        # 这里先配置转发,后面会加上Token验证
        proxy_pass http://localhost:7860/colorize;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        # 添加CORS头
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
        add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
        
        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
            add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
            add_header Access-Control-Max-Age 1728000;
            add_header Content-Type 'text/plain; charset=utf-8';
            add_header Content-Length 0;
            return 204;
        }
    }
    
    # URL上色接口(需要Token验证)
    location /colorize_url {
        proxy_pass http://localhost:7860/colorize_url;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        # 添加CORS头
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
        add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
        
        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
            add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
            add_header Access-Control-Max-Age 1728000;
            add_header Content-Type 'text/plain; charset=utf-8';
            add_header Content-Length 0;
            return 204;
        }
    }
    
    # 默认返回404
    location / {
        return 404;
    }
}

保存文件后,启用这个配置:

# 创建符号链接
sudo ln -s /etc/nginx/sites-available/deoldify-api /etc/nginx/sites-enabled/

# 测试配置是否正确
sudo nginx -t

# 重新加载Nginx配置
sudo systemctl reload nginx

现在,你的DeOldify服务已经通过Nginx代理了。可以通过以下方式访问:

# 健康检查(公开)
curl http://api.yourdomain.com/health

# 图片上色(目前还不需要Token)
curl -X POST http://api.yourdomain.com/colorize \
  -F "image=@/path/to/image.jpg"

4. Token鉴权系统实现

4.1 为什么选择Token鉴权?

Token鉴权有几个明显的优势:

  1. 简单易用:客户端只需要在请求中带上Token
  2. 无状态:服务器不需要保存会话信息
  3. 灵活控制:可以为不同用户生成不同Token,设置不同权限
  4. 易于撤销:只需要删除或禁用Token即可

4.2 创建Token管理脚本

我们来创建一个简单的Token管理系统:

# 创建Token管理目录
sudo mkdir -p /etc/deoldify-auth
sudo nano /etc/deoldify-auth/token_manager.sh

把下面的脚本内容复制进去:

#!/bin/bash

# Token管理脚本
# 用法: 
#  生成Token: ./token_manager.sh generate [用户名] [有效期天数]
#  验证Token: ./token_manager.sh verify [Token]
#  列出Token: ./token_manager.sh list
#  禁用Token: ./token_manager.sh disable [Token]
#  启用Token: ./token_manager.sh enable [Token]

TOKEN_DB="/etc/deoldify-auth/tokens.db"
LOG_FILE="/var/log/deoldify-auth.log"

# 初始化数据库
init_db() {
    if [ ! -f "$TOKEN_DB" ]; then
        echo "[]" > "$TOKEN_DB"
        chmod 600 "$TOKEN_DB"
        log "初始化Token数据库"
    fi
}

# 日志函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

# 生成随机Token
generate_token() {
    cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
}

# 生成新Token
generate() {
    local username="$1"
    local expire_days="${2:-30}"
    
    if [ -z "$username" ]; then
        echo "错误: 需要提供用户名"
        echo "用法: $0 generate [用户名] [有效期天数]"
        exit 1
    fi
    
    init_db
    
    local token=$(generate_token)
    local created=$(date +%s)
    local expire_seconds=$((expire_days * 24 * 60 * 60))
    local expire=$((created + expire_seconds))
    
    # 读取现有Token
    local tokens=$(cat "$TOKEN_DB")
    
    # 添加新Token
    local new_token=$(jq -n \
        --arg token "$token" \
        --arg username "$username" \
        --arg created "$created" \
        --arg expire "$expire" \
        --arg enabled "true" \
        '{
            token: $token,
            username: $username,
            created: $created|tonumber,
            expire: $expire|tonumber,
            enabled: $enabled,
            last_used: null,
            usage_count: 0
        }')
    
    # 更新数据库
    echo "$tokens" | jq ". += [$new_token]" > "$TOKEN_DB".tmp && mv "$TOKEN_DB".tmp "$TOKEN_DB"
    
    echo "Token生成成功:"
    echo "================"
    echo "用户名: $username"
    echo "Token: $token"
    echo "有效期: $expire_days 天"
    echo "创建时间: $(date -d @$created)"
    echo "过期时间: $(date -d @$expire)"
    echo "================"
    echo "重要: 请妥善保存此Token,它只会显示一次!"
    
    log "为用户 $username 生成Token,有效期 $expire_days 天"
}

# 验证Token
verify() {
    local token="$1"
    
    if [ -z "$token" ]; then
        echo "错误: 需要提供Token"
        echo "用法: $0 verify [Token]"
        exit 1
    fi
    
    init_db
    
    local tokens=$(cat "$TOKEN_DB")
    local now=$(date +%s)
    
    # 查找Token
    local token_info=$(echo "$tokens" | jq -r ".[] | select(.token == \"$token\")")
    
    if [ -z "$token_info" ]; then
        echo "验证失败: Token不存在"
        return 1
    fi
    
    local enabled=$(echo "$token_info" | jq -r '.enabled')
    local expire=$(echo "$token_info" | jq -r '.expire')
    local username=$(echo "$token_info" | jq -r '.username')
    
    if [ "$enabled" != "true" ]; then
        echo "验证失败: Token已被禁用"
        return 1
    fi
    
    if [ "$now" -gt "$expire" ]; then
        echo "验证失败: Token已过期"
        return 1
    fi
    
    # 更新使用信息
    local usage_count=$(echo "$token_info" | jq -r '.usage_count + 1')
    local updated_tokens=$(echo "$tokens" | jq \
        "map(if .token == \"$token\" then .last_used = $now | .usage_count = $usage_count else . end)")
    
    echo "$updated_tokens" > "$TOKEN_DB".tmp && mv "$TOKEN_DB".tmp "$TOKEN_DB"
    
    echo "验证成功:"
    echo "用户名: $username"
    echo "创建时间: $(date -d @$(echo "$token_info" | jq -r '.created'))"
    echo "过期时间: $(date -d @$expire)"
    echo "使用次数: $usage_count"
    echo "最后使用: $(date)"
    
    log "Token验证成功: $username"
    return 0
}

# 列出所有Token
list() {
    init_db
    
    local tokens=$(cat "$TOKEN_DB")
    local now=$(date +%s)
    
    echo "Token列表:"
    echo "================"
    
    echo "$tokens" | jq -r '.[] | 
        "用户名: \(.username)
        Token: \(.token)
        状态: \(if .enabled == "true" then "启用" else "禁用" end)
        创建时间: \(.created | tonumber | strftime("%Y-%m-%d %H:%M:%S"))
        过期时间: \(.expire | tonumber | strftime("%Y-%m-%d %H:%M:%S"))
        使用次数: \(.usage_count)
        最后使用: \(if .last_used then (.last_used | tonumber | strftime("%Y-%m-%d %H:%M:%S")) else "从未使用" end)
        ---------------"'
}

# 禁用Token
disable() {
    local token="$1"
    
    if [ -z "$token" ]; then
        echo "错误: 需要提供Token"
        echo "用法: $0 disable [Token]"
        exit 1
    fi
    
    init_db
    
    local tokens=$(cat "$TOKEN_DB")
    local updated_tokens=$(echo "$tokens" | jq \
        "map(if .token == \"$token\" then .enabled = \"false\" else . end)")
    
    echo "$updated_tokens" > "$TOKEN_DB".tmp && mv "$TOKEN_DB".tmp "$TOKEN_DB"
    
    echo "Token已禁用"
    log "禁用Token: $token"
}

# 启用Token
enable() {
    local token="$1"
    
    if [ -z "$token" ]; then
        echo "错误: 需要提供Token"
        echo "用法: $0 enable [Token]"
        exit 1
    fi
    
    init_db
    
    local tokens=$(cat "$TOKEN_DB")
    local updated_tokens=$(echo "$tokens" | jq \
        "map(if .token == \"$token\" then .enabled = \"true\" else . end)")
    
    echo "$updated_tokens" > "$TOKEN_DB".tmp && mv "$TOKEN_DB".tmp "$TOKEN_DB"
    
    echo "Token已启用"
    log "启用Token: $token"
}

# 主函数
main() {
    local action="$1"
    
    case "$action" in
        "generate")
            generate "$2" "$3"
            ;;
        "verify")
            verify "$2"
            ;;
        "list")
            list
            ;;
        "disable")
            disable "$2"
            ;;
        "enable")
            enable "$2"
            ;;
        *)
            echo "用法: $0 {generate|verify|list|disable|enable}"
            echo ""
            echo "命令说明:"
            echo "  generate [用户名] [有效期天数]  生成新Token"
            echo "  verify [Token]                  验证Token"
            echo "  list                            列出所有Token"
            echo "  disable [Token]                 禁用Token"
            echo "  enable [Token]                  启用Token"
            exit 1
            ;;
    esac
}

# 安装依赖
if ! command -v jq &> /dev/null; then
    echo "正在安装jq..."
    if command -v apt &> /dev/null; then
        sudo apt install -y jq
    elif command -v yum &> /dev/null; then
        sudo yum install -y jq
    else
        echo "错误: 无法安装jq,请手动安装"
        exit 1
    fi
fi

main "$@"

给脚本添加执行权限:

sudo chmod +x /etc/deoldify-auth/token_manager.sh

4.3 使用Token管理脚本

现在我们可以使用这个脚本来管理Token了:

# 生成一个新Token(有效期30天)
sudo /etc/deoldify-auth/token_manager.sh generate "user1" 30

# 输出示例:
# Token生成成功:
# ================
# 用户名: user1
# Token: aBcDeFgHiJkLmNoPqRsTuVwXyZ123456
# 有效期: 30 天
# 创建时间: 2024年 01月 15日 星期一 10:30:00 CST
# 过期时间: 2024年 02月 14日 星期一 10:30:00 CST
# ================
# 重要: 请妥善保存此Token,它只会显示一次!

# 验证Token
sudo /etc/deoldify-auth/token_manager.sh verify "aBcDeFgHiJkLmNoPqRsTuVwXyZ123456"

# 列出所有Token
sudo /etc/deoldify-auth/token_manager.sh list

# 禁用Token
sudo /etc/deoldify-auth/token_manager.sh disable "aBcDeFgHiJkLmNoPqRsTuVwXyZ123456"

# 启用Token
sudo /etc/deoldify-auth/token_manager.sh enable "aBcDeFgHiJkLmNoPqRsTuVwXyZ123456"

5. Nginx集成Token验证

5.1 创建Token验证脚本

我们需要创建一个Nginx可以调用的Token验证脚本:

sudo nano /etc/deoldify-auth/validate_token.py

把下面的Python脚本复制进去:

#!/usr/bin/env python3
"""
Token验证脚本 - 供Nginx auth_request模块调用
"""

import json
import sys
import os
import time
from http.server import BaseHTTPRequestHandler, HTTPServer
import urllib.parse

TOKEN_DB = "/etc/deoldify-auth/tokens.db"

def load_tokens():
    """加载Token数据库"""
    try:
        with open(TOKEN_DB, 'r') as f:
            return json.load(f)
    except (FileNotFoundError, json.JSONDecodeError):
        return []

def validate_token(token):
    """验证Token有效性"""
    if not token:
        return False, "未提供Token"
    
    tokens = load_tokens()
    now = int(time.time())
    
    for t in tokens:
        if t.get('token') == token:
            # 检查是否启用
            if t.get('enabled') != 'true':
                return False, "Token已被禁用"
            
            # 检查是否过期
            expire_time = t.get('expire', 0)
            if now > expire_time:
                return False, "Token已过期"
            
            # 更新使用信息
            t['last_used'] = now
            t['usage_count'] = t.get('usage_count', 0) + 1
            
            # 保存更新
            try:
                with open(TOKEN_DB, 'w') as f:
                    json.dump(tokens, f, indent=2)
            except:
                pass  # 即使保存失败也允许访问
            
            return True, t.get('username', 'unknown')
    
    return False, "无效的Token"

class TokenValidatorHandler(BaseHTTPRequestHandler):
    """HTTP请求处理器"""
    
    def do_GET(self):
        """处理GET请求"""
        # 解析查询参数
        query = urllib.parse.urlparse(self.path).query
        params = urllib.parse.parse_qs(query)
        
        # 获取Token
        token = params.get('token', [''])[0]
        if not token:
            # 尝试从Authorization头获取
            auth_header = self.headers.get('Authorization', '')
            if auth_header.startswith('Bearer '):
                token = auth_header[7:]
        
        # 验证Token
        is_valid, message = validate_token(token)
        
        if is_valid:
            self.send_response(200)
            self.send_header('Content-type', 'application/json')
            self.send_header('X-Username', message)  # 传递用户名
            self.end_headers()
            response = {'valid': True, 'username': message}
        else:
            self.send_response(401)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            response = {'valid': False, 'error': message}
        
        self.wfile.write(json.dumps(response).encode())
    
    def log_message(self, format, *args):
        """禁用默认日志"""
        pass

def run_server(port=9090):
    """启动验证服务器"""
    server_address = ('', port)
    httpd = HTTPServer(server_address, TokenValidatorHandler)
    
    print(f"Token验证服务器启动在端口 {port}")
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        print("\n服务器关闭")
        httpd.server_close()

if __name__ == '__main__':
    # 如果作为独立脚本运行,启动HTTP服务器
    if len(sys.argv) > 1 and sys.argv[1] == 'validate':
        # 命令行验证模式
        token = sys.argv[2] if len(sys.argv) > 2 else ''
        is_valid, message = validate_token(token)
        if is_valid:
            print(f"有效Token - 用户: {message}")
            sys.exit(0)
        else:
            print(f"无效Token: {message}")
            sys.exit(1)
    else:
        # 服务器模式
        run_server()

给脚本添加执行权限:

sudo chmod +x /etc/deoldify-auth/validate_token.py

5.2 配置系统服务

创建一个systemd服务来运行Token验证服务器:

sudo nano /etc/systemd/system/deoldify-auth.service

添加以下内容:

[Unit]
Description=DeOldify Token Validation Service
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/etc/deoldify-auth
ExecStart=/usr/bin/python3 /etc/deoldify-auth/validate_token.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

启动服务:

# 重新加载systemd配置
sudo systemctl daemon-reload

# 启动服务
sudo systemctl start deoldify-auth

# 设置开机自启
sudo systemctl enable deoldify-auth

# 检查状态
sudo systemctl status deoldify-auth

5.3 更新Nginx配置集成Token验证

现在更新Nginx配置,集成Token验证:

sudo nano /etc/nginx/sites-available/deoldify-api

更新配置,在需要验证的location块中添加auth_request:

server {
    listen 80;
    server_name api.yourdomain.com;
    
    access_log /var/log/nginx/deoldify_access.log;
    error_log /var/log/nginx/deoldify_error.log;
    
    client_max_body_size 50M;
    proxy_connect_timeout 300s;
    proxy_send_timeout 300s;
    proxy_read_timeout 300s;
    
    # Token验证服务地址
    auth_request /validate;
    
    # Token验证接口(内部使用)
    location = /validate {
        internal;
        proxy_pass http://localhost:9090;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-URI $request_uri;
        
        # 传递Token参数
        if ($arg_token) {
            proxy_set_header Authorization "Bearer $arg_token";
        }
    }
    
    # 验证失败时的错误页面
    error_page 401 = @error401;
    location @error401 {
        return 401 '{"error": "Unauthorized", "message": "无效或过期的Token"}';
        add_header Content-Type application/json;
    }
    
    # 健康检查接口(公开访问)
    location /health {
        # 不需要Token验证
        auth_request off;
        
        proxy_pass http://localhost:7860/health;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
        add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
        
        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
            add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
            add_header Access-Control-Max-Age 1728000;
            add_header Content-Type 'text/plain; charset=utf-8';
            add_header Content-Length 0;
            return 204;
        }
    }
    
    # 图片上色接口(需要Token验证)
    location /colorize {
        # 需要Token验证
        auth_request on;
        
        # 传递用户名到后端
        auth_request_set $username $upstream_http_x_username;
        proxy_set_header X-Username $username;
        
        proxy_pass http://localhost:7860/colorize;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
        add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
        
        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
            add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
            add_header Access-Control-Max-Age 1728000;
            add_header Content-Type 'text/plain; charset=utf-8';
            add_header Content-Length 0;
            return 204;
        }
    }
    
    # URL上色接口(需要Token验证)
    location /colorize_url {
        auth_request on;
        
        auth_request_set $username $upstream_http_x_username;
        proxy_set_header X-Username $username;
        
        proxy_pass http://localhost:7860/colorize_url;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
        add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
        
        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
            add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
            add_header Access-Control-Max-Age 1728000;
            add_header Content-Type 'text/plain; charset=utf-8';
            add_header Content-Length 0;
            return 204;
        }
    }
    
    # 默认返回404
    location / {
        return 404;
    }
}

重新加载Nginx配置:

# 测试配置
sudo nginx -t

# 重新加载
sudo systemctl reload nginx

6. 添加限流和防护

6.1 配置请求限流

为了防止API被滥用,我们需要添加限流配置:

sudo nano /etc/nginx/conf.d/rate_limit.conf

添加以下限流配置:

# 定义限流区域
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=auth_limit:10m rate=5r/s;

# 限制连接数
limit_conn_zone $binary_remote_addr zone=addr:10m;

然后更新DeOldify API配置:

sudo nano /etc/nginx/sites-available/deoldify-api

在server块中添加限流配置:

server {
    listen 80;
    server_name api.yourdomain.com;
    
    # 全局连接限制
    limit_conn addr 10;
    
    # ... 其他配置保持不变 ...
    
    # Token验证接口(更严格的限流)
    location = /validate {
        limit_req zone=auth_limit burst=5 nodelay;
        limit_conn addr 5;
        
        internal;
        proxy_pass http://localhost:9090;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-URI $request_uri;
        
        if ($arg_token) {
            proxy_set_header Authorization "Bearer $arg_token";
        }
    }
    
    # API接口(标准限流)
    location ~ ^/(colorize|colorize_url) {
        limit_req zone=api_limit burst=20 nodelay;
        limit_conn addr 5;
        
        # ... 原有配置保持不变 ...
    }
}

6.2 添加WAF防护

安装和配置ModSecurity来提供Web应用防火墙功能:

# 安装ModSecurity
sudo apt install libapache2-mod-security2 -y

# 下载OWASP核心规则集
sudo apt install git -y
cd /tmp
git clone https://github.com/coreruleset/coreruleset.git
sudo cp -r coreruleset /etc/modsecurity/
sudo cp /etc/modsecurity/coreruleset/crs-setup.conf.example /etc/modsecurity/coreruleset/crs-setup.conf

# 配置ModSecurity
sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
sudo nano /etc/modsecurity/modsecurity.conf

修改以下配置:

SecRuleEngine On
SecRequestBodyAccess On
SecResponseBodyAccess On
SecDataDir /tmp/

安装Nginx的ModSecurity模块:

# 对于Ubuntu/Debian
sudo apt install libnginx-mod-http-modsecurity -y

# 配置Nginx使用ModSecurity
sudo nano /etc/nginx/modsecurity.conf

添加:

modsecurity on;
modsecurity_rules_file /etc/modsecurity/modsecurity.conf;
modsecurity_rules_file /etc/modsecurity/coreruleset/crs-setup.conf;
modsecurity_rules_file /etc/modsecurity/coreruleset/rules/*.conf;

在Nginx站点配置中启用:

server {
    listen 80;
    server_name api.yourdomain.com;
    
    # 启用ModSecurity
    modsecurity on;
    modsecurity_rules_file /etc/nginx/modsecurity.conf;
    
    # ... 其他配置保持不变 ...
}

7. 客户端使用示例

7.1 Python客户端示例

更新之前的Python代码,添加Token支持:

import requests
import base64
from PIL import Image
from io import BytesIO

class DeOldifyClient:
    """DeOldify API客户端"""
    
    def __init__(self, base_url, api_token):
        """
        初始化客户端
        
        Args:
            base_url: API基础地址,如 "http://api.yourdomain.com"
            api_token: API访问Token
        """
        self.base_url = base_url.rstrip('/')
        self.api_token = api_token
        self.session = requests.Session()
        
        # 设置默认headers
        self.session.headers.update({
            'Authorization': f'Bearer {api_token}'
        })
    
    def health_check(self):
        """健康检查"""
        try:
            response = self.session.get(f"{self.base_url}/health")
            return response.json()
        except Exception as e:
            return {'error': str(e)}
    
    def colorize_image(self, image_path, output_path=None):
        """
        给图片上色
        
        Args:
            image_path: 图片文件路径
            output_path: 输出文件路径,如果为None则自动生成
            
        Returns:
            上色后的图片路径
        """
        try:
            # 读取图片
            with open(image_path, 'rb') as f:
                files = {'image': f}
                
                # 使用Token参数
                params = {'token': self.api_token}
                response = self.session.post(
                    f"{self.base_url}/colorize",
                    files=files,
                    params=params
                )
            
            # 检查响应
            if response.status_code == 401:
                raise Exception("Token无效或已过期")
            elif response.status_code != 200:
                raise Exception(f"API请求失败: {response.status_code}")
            
            # 解析结果
            result = response.json()
            
            if result.get('success'):
                # 解码base64图片数据
                img_data = base64.b64decode(result['output_img_base64'])
                img = Image.open(BytesIO(img_data))
                
                # 保存图片
                if output_path is None:
                    # 自动生成输出路径
                    import os
                    name, ext = os.path.splitext(image_path)
                    output_path = f"{name}_colored{ext}"
                
                img.save(output_path)
                print(f"✓ 上色完成: {output_path}")
                return output_path
            else:
                raise Exception(f"上色失败: {result}")
                
        except Exception as e:
            print(f"✗ 错误: {e}")
            return None
    
    def colorize_from_url(self, image_url, output_path):
        """
        从URL上色图片
        
        Args:
            image_url: 图片URL地址
            output_path: 输出文件路径
            
        Returns:
            bool: 是否成功
        """
        try:
            # 准备请求数据
            data = {"url": image_url}
            
            # 使用Token参数
            params = {'token': self.api_token}
            response = self.session.post(
                f"{self.base_url}/colorize_url",
                json=data,
                params=params
            )
            
            # 检查响应
            if response.status_code == 401:
                raise Exception("Token无效或已过期")
            elif response.status_code != 200:
                raise Exception(f"API请求失败: {response.status_code}")
            
            # 解析结果
            result = response.json()
            
            if result.get('success'):
                # 解码并保存
                img_data = base64.b64decode(result['output_img_base64'])
                img = Image.open(BytesIO(img_data))
                img.save(output_path)
                print(f"✓ 上色完成: {output_path}")
                return True
            else:
                raise Exception(f"上色失败: {result}")
                
        except Exception as e:
            print(f"✗ 错误: {e}")
            return False
    
    def batch_colorize(self, input_folder, output_folder):
        """
        批量处理文件夹中的图片
        
        Args:
            input_folder: 输入文件夹路径
            output_folder: 输出文件夹路径
            
        Returns:
            dict: 处理结果统计
        """
        import os
        
        # 创建输出文件夹
        os.makedirs(output_folder, exist_ok=True)
        
        # 支持的图片格式
        valid_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp']
        
        results = {
            'total': 0,
            'success': 0,
            'failed': 0,
            'errors': []
        }
        
        # 遍历输入文件夹
        for filename in os.listdir(input_folder):
            # 检查文件扩展名
            ext = os.path.splitext(filename)[1].lower()
            if ext not in valid_extensions:
                continue
            
            input_path = os.path.join(input_folder, filename)
            output_path = os.path.join(output_folder, f"colored_{filename}")
            
            results['total'] += 1
            print(f"正在处理 ({results['total']}): {filename}")
            
            try:
                success = self.colorize_image(input_path, output_path)
                if success:
                    results['success'] += 1
                else:
                    results['failed'] += 1
                    results['errors'].append(f"{filename}: 上色失败")
            except Exception as e:
                results['failed'] += 1
                results['errors'].append(f"{filename}: {str(e)}")
        
        # 打印统计信息
        print(f"\n处理完成:")
        print(f"  总计: {results['total']}")
        print(f"  成功: {results['success']}")
        print(f"  失败: {results['failed']}")
        
        if results['errors']:
            print(f"\n错误列表:")
            for error in results['errors']:
                print(f"  - {error}")
        
        return results

# 使用示例
if __name__ == "__main__":
    # 配置信息
    API_URL = "http://api.yourdomain.com"  # 你的API地址
    API_TOKEN = "your_token_here"  # 你的Token
    
    # 创建客户端
    client = DeOldifyClient(API_URL, API_TOKEN)
    
    # 测试连接
    print("测试API连接...")
    health = client.health_check()
    print(f"服务状态: {health}")
    
    # 单张图片上色
    print("\n处理单张图片...")
    result = client.colorize_image("old_photo.jpg", "old_photo_colored.jpg")
    
    # 批量处理
    print("\n批量处理图片...")
    stats = client.batch_colorize("./input_photos", "./output_photos")
    
    # 从URL处理
    print("\n从URL处理图片...")
    client.colorize_from_url(
        "https://example.com/old_photo.jpg",
        "downloaded_colored.jpg"
    )

7.2 命令行使用示例

# 使用curl调用API(通过查询参数传递Token)
curl -X POST "http://api.yourdomain.com/colorize?token=your_token_here" \
  -F "image=@/path/to/image.jpg"

# 或者通过Authorization头传递Token
curl -X POST http://api.yourdomain.com/colorize \
  -H "Authorization: Bearer your_token_here" \
  -F "image=@/path/to/image.jpg"

# 从URL上色
curl -X POST "http://api.yourdomain.com/colorize_url?token=your_token_here" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/image.jpg"}'

7.3 JavaScript/Node.js客户端示例

// Node.js客户端示例
const axios = require('axios');
const fs = require('fs');
const FormData = require('form-data');

class DeOldifyClient {
    constructor(baseUrl, apiToken) {
        this.baseUrl = baseUrl;
        this.apiToken = apiToken;
        this.client = axios.create({
            baseURL: baseUrl,
            headers: {
                'Authorization': `Bearer ${apiToken}`
            }
        });
    }

    // 健康检查
    async healthCheck() {
        try {
            const response = await this.client.get('/health');
            return response.data;
        } catch (error) {
            return { error: error.message };
        }
    }

    // 图片上色
    async colorizeImage(imagePath, outputPath) {
        try {
            const formData = new FormData();
            formData.append('image', fs.createReadStream(imagePath));

            const response = await this.client.post('/colorize', formData, {
                headers: formData.getHeaders(),
                params: { token: this.apiToken }
            });

            if (response.data.success) {
                // 解码base64图片
                const imageBuffer = Buffer.from(response.data.output_img_base64, 'base64');
                fs.writeFileSync(outputPath, imageBuffer);
                console.log(`✓ 上色完成: ${outputPath}`);
                return outputPath;
            } else {
                throw new Error('上色失败');
            }
        } catch (error) {
            if (error.response && error.response.status === 401) {
                throw new Error('Token无效或已过期');
            }
            throw error;
        }
    }

    // 从URL上色
    async colorizeFromUrl(imageUrl, outputPath) {
        try {
            const response = await this.client.post('/colorize_url', {
                url: imageUrl
            }, {
                params: { token: this.apiToken }
            });

            if (response.data.success) {
                const imageBuffer = Buffer.from(response.data.output_img_base64, 'base64');
                fs.writeFileSync(outputPath, imageBuffer);
                console.log(`✓ 上色完成: ${outputPath}`);
                return true;
            } else {
                throw new Error('上色失败');
            }
        } catch (error) {
            if (error.response && error.response.status === 401) {
                throw new Error('Token无效或已过期');
            }
            throw error;
        }
    }
}

// 使用示例
async function main() {
    const client = new DeOldifyClient(
        'http://api.yourdomain.com',
        'your_token_here'
    );

    // 测试连接
    console.log('测试API连接...');
    const health = await client.healthCheck();
    console.log('服务状态:', health);

    // 处理图片
    console.log('\n处理图片...');
    try {
        await client.colorizeImage('old_photo.jpg', 'old_photo_colored.jpg');
    } catch (error) {
        console.error('错误:', error.message);
    }
}

main();

8. 监控和日志分析

8.1 配置Nginx日志格式

为了更好地监控API使用情况,我们可以自定义Nginx日志格式:

sudo nano /etc/nginx/nginx.conf

在http块中添加:

http {
    # ... 其他配置 ...
    
    # 自定义日志格式
    log_format deoldify_json '{"time": "$time_iso8601", '
                           '"remote_addr": "$remote_addr", '
                           '"remote_user": "$remote_user", '
                           '"request": "$request", '
                           '"status": "$status", '
                           '"body_bytes_sent": "$body_bytes_sent", '
                           '"request_time": "$request_time", '
                           '"http_referer": "$http_referer", '
                           '"http_user_agent": "$http_user_agent", '
                           '"http_x_forwarded_for": "$http_x_forwarded_for", '
                           '"token": "$arg_token", '
                           '"username": "$upstream_http_x_username"}';
    
    # ... 其他配置 ...
}

更新站点配置使用JSON日志:

server {
    listen 80;
    server_name api.yourdomain.com;
    
    # 使用JSON格式日志
    access_log /var/log/nginx/deoldify_access.log deoldify_json;
    error_log /var/log/nginx/deoldify_error.log;
    
    # ... 其他配置 ...
}

8.2 创建监控脚本

创建一个监控脚本,定期检查服务状态和使用情况:

sudo nano /etc/deoldify-auth/monitor.sh
#!/bin/bash

# DeOldify API监控脚本

LOG_FILE="/var/log/deoldify-monitor.log"
API_URL="http://localhost:7860"
NGINX_ACCESS_LOG="/var/log/nginx/deoldify_access.log"
TOKEN_DB="/etc/deoldify-auth/tokens.db"

# 日志函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

# 检查服务健康状态
check_health() {
    local response=$(curl -s "$API_URL/health" 2>/dev/null || echo '{"status":"unreachable"}')
    local status=$(echo "$response" | jq -r '.status' 2>/dev/null || echo "error")
    
    if [ "$status" = "healthy" ]; then
        echo "✓ 服务健康"
        log "服务健康检查: 正常"
        return 0
    else
        echo "✗ 服务异常: $response"
        log "服务健康检查: 异常 - $response"
        return 1
    fi
}

# 分析访问日志
analyze_logs() {
    local today=$(date +%Y-%m-%d)
    local log_file="$NGINX_ACCESS_LOG"
    
    if [ ! -f "$log_file" ]; then
        echo "日志文件不存在: $log_file"
        return
    fi
    
    # 统计今日请求
    local today_requests=$(grep "$today" "$log_file" 2>/dev/null | wc -l)
    local today_success=$(grep "$today" "$log_file" 2>/dev/null | grep '"status":"200"' | wc -l)
    local today_errors=$(grep "$today" "$log_file" 2>/dev/null | grep -v '"status":"200"' | wc -l)
    
    # 统计Token使用情况
    if [ -f "$TOKEN_DB" ]; then
        local total_tokens=$(jq 'length' "$TOKEN_DB" 2>/dev/null || echo "0")
        local active_tokens=$(jq '[.[] | select(.enabled == "true")] | length' "$TOKEN_DB" 2>/dev/null || echo "0")
    else
        local total_tokens="0"
        local active_tokens="0"
    fi
    
    echo "📊 今日统计 ($today):"
    echo "  总请求数: $today_requests"
    echo "  成功请求: $today_success"
    echo "  失败请求: $today_errors"
    echo "  Token总数: $total_tokens"
    echo "  活跃Token: $active_tokens"
    
    log "日志分析: 请求数=$today_requests, 成功=$today_success, 失败=$today_errors"
}

# 检查系统资源
check_resources() {
    local cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
    local mem_usage=$(free -m | awk 'NR==2{printf "%.2f", $3*100/$2}')
    local disk_usage=$(df -h / | awk 'NR==2{print $5}' | cut -d'%' -f1)
    
    echo "🖥️  系统资源:"
    echo "  CPU使用率: ${cpu_usage}%"
    echo "  内存使用率: ${mem_usage}%"
    echo "  磁盘使用率: ${disk_usage}%"
    
    # 检查Nginx状态
    local nginx_status=$(systemctl is-active nginx)
    local auth_status=$(systemctl is-active deoldify-auth)
    
    echo "🔧 服务状态:"
    echo "  Nginx: $nginx_status"
    echo "  Token验证服务: $auth_status"
    
    log "资源检查: CPU=${cpu_usage}%, 内存=${mem_usage}%, 磁盘=${disk_usage}%"
}

# 生成使用报告
generate_report() {
    local report_file="/tmp/deoldify-report-$(date +%Y%m%d).txt"
    
    {
        echo "DeOldify API 使用报告"
        echo "生成时间: $(date)"
        echo "========================================"
        echo ""
        
        echo "1. 服务健康状态:"
        check_health
        echo ""
        
        echo "2. 访问统计:"
        analyze_logs
        echo ""
        
        echo "3. 系统资源:"
        check_resources
        echo ""
        
        echo "4. Token使用情况:"
        if [ -f "$TOKEN_DB" ]; then
            jq -r '.[] | "\(.username): 使用次数=\(.usage_count), 最后使用=\(if .last_used then (.last_used | tonumber | strftime("%Y-%m-%d %H:%M:%S")) else "从未使用" end), 状态=\(if .enabled == "true" then "启用" else "禁用" end)"' "$TOKEN_DB" 2>/dev/null || echo "无法读取Token数据库"
        else
            echo "Token数据库不存在"
        fi
        
    } > "$report_file"
    
    echo "报告已生成: $report_file"
    log "生成使用报告: $report_file"
}

# 发送警报(如果需要)
send_alert() {
    local message="$1"
    
    # 这里可以集成邮件、Slack、钉钉等通知方式
    # 示例:发送到syslog
    logger -t deoldify-monitor "$message"
    
    echo "⚠️  警报: $message"
    log "发送警报: $message"
}

# 主函数
main() {
    echo "开始监控检查..."
    log "开始监控检查"
    
    # 检查服务健康
    if ! check_health; then
        send_alert "DeOldify服务异常"
    fi
    
    # 检查系统资源
    check_resources
    
    # 分析日志
    analyze_logs
    
    # 生成报告(每天一次)
    local current_hour=$(date +%H)
    if [ "$current_hour" = "00" ]; then
        generate_report
    fi
    
    echo "监控检查完成"
    log "监控检查完成"
}

# 安装依赖
if ! command -v jq &> /dev/null; then
    echo "正在安装jq..."
    sudo apt install -y jq
fi

# 运行主函数
main

给脚本添加执行权限:

sudo chmod +x /etc/deoldify-auth/monitor.sh

8.3 设置定时监控

创建cron任务定期运行监控:

# 编辑crontab
sudo crontab -e

添加以下行:

# 每分钟检查一次服务健康
* * * * * /etc/deoldify-auth/monitor.sh >> /var/log/deoldify-cron.log 2>&1

# 每天凌晨1点生成详细报告
0 1 * * * /etc/deoldify-auth/monitor.sh --report >> /var/log/deoldify-daily.log 2>&1

# 每周一凌晨2点清理旧日志
0 2 * * 1 find /var/log/nginx/deoldify_* -mtime +30 -delete

9. 高级安全配置

9.1 配置HTTPS

为了更安全,我们应该启用HTTPS:

# 安装Certbot(Let's Encrypt)
sudo apt install certbot python3-certbot-nginx -y

# 获取SSL证书
sudo certbot --nginx -d api.yourdomain.com

# 自动续期测试
sudo certbot renew --dry-run

Nginx会自动更新配置,启用HTTPS。

9.2 配置防火墙

# 安装ufw(如果未安装)
sudo apt install ufw -y

# 启用防火墙
sudo ufw enable

# 允许SSH
sudo ufw allow ssh

# 允许HTTP和HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# 拒绝其他所有入站连接
sudo ufw default deny incoming

# 允许所有出站连接
sudo ufw default allow outgoing

# 查看规则
sudo ufw status verbose

9.3 配置Fail2ban防止暴力破解

# 安装Fail2ban
sudo apt install fail2ban -y

# 创建DeOldify专用的jail配置
sudo nano /etc/fail2ban/jail.local

添加:

[deoldify-auth]
enabled = true
port = http,https
filter = deoldify-auth
logpath = /var/log/nginx/deoldify_access.log
maxretry = 5
bantime = 3600
findtime = 600

创建过滤器:

sudo nano /etc/fail2ban/filter.d/deoldify-auth.conf

添加:

[Definition]
failregex = ^.*"remote_addr":"<HOST>".*"status":"(401|403|429)".*$
ignoreregex =

重启Fail2ban:

sudo systemctl restart fail2ban
sudo systemctl enable fail2ban

10. 故障排除和优化

10.1 常见问题解决

问题1:Nginx返回502错误
# 检查Nginx错误日志
sudo tail -f /var/log/nginx/error.log

# 检查Token验证服务
sudo systemctl status deoldify-auth
sudo journalctl -u deoldify-auth -f

# 检查端口是否监听
sudo netstat -tlnp | grep :9090
问题2:Token验证失败
# 手动验证Token
sudo /etc/deoldify-auth/validate_token.py validate "your_token"

# 检查Token数据库
sudo cat /etc/deoldify-auth/tokens.db | jq .

# 检查Token验证服务日志
sudo tail -f /var/log/deoldify-auth.log
问题3:API响应慢
# 检查系统资源
top
free -h
df -h

# 检查Nginx连接数
sudo netstat -an | grep :80 | wc -l

# 优化Nginx配置
sudo nano /etc/nginx/nginx.conf

在nginx.conf的events块中添加:

events {
    worker_connections 4096;
    multi_accept on;
    use epoll;
}

在http块中添加:

http {
    # 启用gzip压缩
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/octet-stream;
    
    # 优化缓冲区
    client_body_buffer_size 10K;
    client_header_buffer_size 1k;
    client_max_body_size 50M;
    large_client_header_buffers 4 8k;
    
    # 优化超时
    client_body_timeout 12;
    client_header_timeout 12;
    keepalive_timeout 15;
    send_timeout 10;
}

10.2 性能优化建议

  1. 启用缓存:对于相同的图片,可以缓存处理结果
  2. 使用CDN:将处理后的图片缓存到CDN
  3. 负载均衡:如果流量大,可以考虑多实例部署
  4. 数据库优化:如果Token很多,考虑使用Redis代替JSON文件
  5. 监控告警:设置资源使用告警,及时扩容

11. 总结

通过本文的配置,我们为DeOldify图像上色API构建了一个完整的安全接入方案:

11.1 实现的安全特性

  1. Token鉴权:只有持有有效Token的用户才能访问API
  2. 请求限流:防止API被滥用,保护后端服务
  3. 反向代理:隐藏真实服务地址,增加安全性
  4. HTTPS加密:数据传输加密,防止中间人攻击
  5. WAF防护:防止常见Web攻击
  6. 访问日志:完整记录所有访问,便于审计
  7. 自动监控:实时监控服务状态和使用情况

11.2 部署步骤回顾

  1. 安装和配置Nginx反向代理
  2. 创建Token管理系统
  3. 集成Token验证到Nginx
  4. 配置限流和防护规则
  5. 设置监控和告警
  6. 启用HTTPS加密
  7. 配置防火墙和Fail2ban

11.3 使用建议

  1. 定期轮换Token:建议每30-90天更换一次Token
  2. 按需生成Token:为不同用户生成不同的Token
  3. 监控使用情况:定期检查API使用统计
  4. 及时更新:保持系统和软件更新到最新版本
  5. 备份配置:定期备份Nginx和Token配置

11.4 扩展可能性

这个方案还可以进一步扩展:

  1. 多级权限:为不同Token设置不同的访问权限
  2. 使用量限制:限制每个Token的每日使用次数
  3. Web管理界面:提供图形化的Token管理界面
  4. OAuth集成:支持第三方登录认证
  5. 审计日志:更详细的访问审计和报告

现在,你的DeOldify API已经具备了企业级的安全防护能力,可以放心地对外提供服务了。记得定期检查日志和监控,确保服务稳定运行。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐