Hướng dẫn cấu hình giới hạn tần suất truy cập cho AnythingLLM

Trong bối cảnh các mô hình ngôn ngữ lớn (LLM) đang dần được triển khai rộng rãi, việc xây dựng các hệ thống quản lý tri thức AI nội bộ bằng AnythingLLM đã trở thành lựa chọn phổ biến của nhiều doanh nghiệp và nhà phát triển. Tuy nhiên, khi đưa hệ thống ra môi trường công cộng hoặc sử dụng chung trong tổ chức, vấn đề lạm dụng API hoặc các cuộc tấn công từ chối dịch vụ (DoS) cấp độ ứng dụng trở thành một thách thức lớn.

Việc kiểm soát truy cập trực tiếp từ mã nguồn ứng dụng thường không mang lại hiệu quả tối ưu vì nó tiêu tốn tài nguyên xử lý của chính service đó. Giải pháp bền vững hơn là thiết lập một lớp bảo vệ ở tầng biên (Edge) thông qua cơ chế Rate Limiting (Giới hạn tần suất). Điều này giúp đảm bảo tính khả dụng của hệ thống, ngăn chặn các kịch bản spam yêu cầu làm tê liệt server.

Sử dụng Nginx làm lớp bảo vệ tiền phương

Nginx là một trong những giải pháp Reverse Proxy mạnh mẽ và ổn định nhất để triển khai giới hạn tốc độ. Thay vì để AnythingLLM trực tiếp đối mặt với lưu lượng truy cập từ internet, Nginx sẽ đóng vai trò "người gác cổng", thống kê và lọc các yêu cầu dựa trên địa chỉ IP của người dùng.

Cấu hình giới hạn trong Nginx dựa trên hai chỉ thị chính là limit_req_zonelimit_req. Dưới đây là cách thiết lập mẫu để bảo vệ các endpoint API của AnythingLLM:

http {
    # Thiết lập vùng nhớ chia sẻ 15MB để lưu trạng thái IP, giới hạn 5 yêu cầu/giây
    limit_req_zone $binary_remote_addr zone=llm_api_limit:15m rate=5r/s;

    server {
        listen 80;
        server_name ai.your-system.com;

        location /api/ {
            # Áp dụng giới hạn: cho phép vượt ngưỡng (burst) 15 yêu cầu, xử lý ngay lập tức
            limit_req zone=llm_api_limit burst=15 nodelay;

            proxy_pass http://anythingllm_container:3001;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location / {
            # Các tài nguyên giao diện web không áp dụng giới hạn gắt gao
            proxy_pass http://anythingllm_container:3001;
        }
    }
}

Trong cấu hình trên, việc sử dụng $binary_remote_addr giúp tối ưu hóa bộ nhớ hơn so với dạng chuỗi thông thường. Tham số nodelay cực kỳ quan trọng đối với trải nghiệm người dùng trong các ứng dụng AI, vì nó cho phép các yêu cầu trong ngưỡng burst được xử lý ngay thay vì bị xếp hàng chờ, đồng thời trả về lỗi 503 ngay lập tức nếu vượt quá giới hạn.

Thiết lập hạ tầng bảo mật với Docker Compose

Để triển khai kiến trúc này một cách chuyên nghiệp, bạn nên cô lập service AnythingLLM bên trong một mạng nội bộ của Docker và chỉ để lộ cổng thông qua Nginx. Điều này ngăn chặn việc người dùng truy cập trực tiếp vào cổng 3001 của ứng dụng, bỏ qua các lớp bảo vệ.

version: '3.9'

services:
  gateway:
    image: nginx:stable-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - llm-core
    networks:
      - private-net

  llm-core:
    image: mintplexlabs/anything-llm:latest
    environment:
      - SERVER_PORT=3001
      - STORAGE_DIR=/app/storage
    volumes:
      - ./llm_data:/app/storage
    expose:
      - "3001"
    networks:
      - private-net
    restart: always

networks:
  private-net:
    driver: bridge

Việc sử dụng lệnh expose thay vì ports cho service llm-core là một thủ thuật quan trọng. Nó chỉ cho phép các container trong cùng mạng private-net giao tiếp với nhau qua cổng 3001, tạo ra một rào cản vật lý đối với các truy cập từ bên ngoài.

Giải pháp hiện đại với Traefik

Nếu bạn đang vận hành trong môi trường Cloud Native hoặc cần khả năng tự động cấp phát chứng chỉ SSL (Let's Encrypt), Traefik là một lựa chọn thay thế Nginx tuyệt vời. Traefik hỗ trợ Rate Limiting thông qua các Middleware được cấu hình trực tiếp bằng Labels trong Docker Compose.

services:
  traefik:
    image: traefik:v2.10
    command:
      - "--providers.docker=true"
      - "--entrypoints.websecure.address=:443"
    ports:
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - private-net

  anything-llm:
    image: mintplexlabs/anything-llm:latest
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.llm.rule=Host(`ai.example.com`)"
      - "traefik.http.routers.llm.entrypoints=websecure"
      - "traefik.http.routers.llm.tls=true"
      # Định nghĩa Middleware Rate Limit
      - "traefik.http.middlewares.limit-logic.ratelimit.average=10"
      - "traefik.http.middlewares.limit-logic.ratelimit.burst=25"
      - "traefik.http.routers.llm.middlewares=limit-logic"
    networks:
      - private-net

Chiến lược tối ưu hóa trong thực tế

Việc đặt một con số giới hạn duy nhất thường không phù hợp cho mọi đối tượng khách hàng. Để tối ưu hóa, bạn cần cân nhắc các yếu tố sau:

  • Phân loại API: Các yêu cầu chat (/api/v1/chat) tiêu tốn nhiều tài nguyên GPU/CPU hơn, do đó cần giới hạn chặt chẽ hơn so với các yêu cầu lấy thông tin hệ thống.
  • Cơ chế Whitelist: Đối với các IP nội bộ của công ty hoặc các tool giám sát, bạn nên cấu hình để bỏ qua giới hạn tần suất bằng cách sử dụng module map trong Nginx.
  • Theo dõi và cảnh báo: Luôn ghi lại nhật ký (logs) các yêu cầu bị chặn. Việc theo dõi tỷ lệ lỗi 503 tăng đột biến có thể là dấu hiệu của một cuộc tấn công đang diễn ra hoặc cấu hình giới hạn đang quá khắt khe đối với người dùng thật.

Ví dụ cấu hình bỏ qua giới hạn cho mạng nội bộ:

map $remote_addr $limit_identifier {
    default          $binary_remote_addr;
    127.0.0.1        ""; # Không giới hạn localhost
    192.168.1.0/24   ""; # Không giới hạn mạng nội bộ
}

limit_req_zone $limit_identifier zone=flexible_limit:10m rate=10r/s;

Bằng cách kết hợp giữa việc cô lập hạ tầng bằng Docker và triển khai các quy tắc kiểm soát luồng dữ liệu tại Proxy, hệ thống AnythingLLM của bạn sẽ trở nên kiên cố hơn trước những rủi ro từ môi trường mạng phức tạp.

Thẻ: AnythingLLM nginx docker-compose Traefik rate-limiting

Đăng vào ngày 18 tháng 9 lúc 12:17