Files
arasystem/frontend/nginx-share-api-open.conf
T
ttipo 93147b88b7 feat(docker): 대용량 첨부 — ClamAV 검사기 · 공개 내려받기 호스트 · 받기 동시 연결 상한
- ClamAV 1.4.6 LTS 를 둘로 나눴다: clamd 는 백엔드와만 닿는 internal 네트워크(바깥 길 없음 · 서명 볼륨 읽기 전용),
  freshclam 은 자기 바깥 길에만. 비-root · cap_drop ALL. 운영은 늘 뜨고 개발은 profile clamav.
  clamd.conf 는 한 파일 한도 2047M 까지 끝까지 검사하고 암호 · 한도 초과를 판정으로 알린다(실측표는 mail/README).
  검사 중에 죽으면 남던 임시 파일을 띄울 때 지운다.
- nginx 를 포털 · 공개 내려받기(files.) 두 server 로 가른다(SHARE_PUBLIC_URL 과 CORS_ORIGIN 의 호스트 비교 — 같으면 포털이 함께 연다).
  조각 PUT 17m, 받기는 버퍼링 · 압축 끔 + X-Accel-Buffering 넘김 + 머리글 버퍼 16k,
  limit_conn 은 X-Forwarded-For 마지막 칸으로 IP 마다 공개 10 · 앱 안 30, 전체 공개 400 · 앱 안 200.
  받기 location 은 /api/ 블록 안의 대소문자를 가리지 않는 정규식이다(리뷰 — /FILES/ 같은 변형이 상한을 비켜 갔다).
  접근 로그는 경로 모양과 43자 토큰 모양으로 토큰을 가린다.
- 파일은 named volume <PROJECT_NAME>_files(개발도 — builder 단계가 /app/files 를 node 소유로 만든다), 백업하지 않는다.
- CI infra 잡: nginx 두 꼴 · 받기 경로 변형 시험(가짜 백엔드) · clamconf(-n 없이 기본값까지) · 틀린 SHARE_PUBLIC_URL 거부.
- mail/README: 악성 검사 · 공개 호스트 · NPM 칸(Advanced 다섯 줄) · 메모리 예산 · 문제 해결.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:37:21 +09:00

48 lines
4.2 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ==========================================
# 대용량 첨부의 공개 API — /api/public-links/ (11단계 — docs/mail/api-contract.md 4절 "공개 내려받기")
#
# 두 server 의 location ^~ /api/ 블록 **안에** 넣는다(nginx.conf) — 공개 내려받기 server 는 늘, 포털은 공개 호스트를 따로 두지 않을 때
# (nginx-env.envsh 의 NGINX_PORTAL_SHARE=open). 템플릿이 아니다 — /etc/nginx/snippets/share-api-open.conf 로 그대로 들어간다(Dockerfile).
# $backend_upstream 과 limit_conn 의 영역(download_public_*)은 nginx.conf 의 http 단계, @api_* 는 nginx-api-errors.conf.
# /api/ 블록의 add_header_inherit off 를 물려받는다 — 응답의 머리글(no-store · noindex · no-referrer · 파일의 CSP 등)은 백엔드가 정한다.
#
# 대소문자를 가리지 않는다(~*) — 백엔드(Express) 라우팅이 가리지 않아 /api/Public-Links/…/FILES/… 도 받기 처리기에 닿는다(nginx.conf 머리말).
# 정규식은 적은 차례로 처음 맞은 것을 쓴다 — 파일 받기를 링크 정보보다 먼저 둔다.
# ==========================================
# 파일 받기 GET·HEAD /api/public-links/{token}/files/{fileId} — 200 · 206(Range) · 416, 2GB 까지
# - 버퍼링을 끈다: 기본값이면 받는 쪽이 느릴 때 nginx 가 응답을 임시 파일(/tmp/proxy_temp)에 1GB 까지 받아 둔다 — 받는 사람마다.
# 백엔드가 보내는 X-Accel-Buffering: no 로도 꺼지지만 그 머리글에 기대지 않는다(실시간 알림과 같다)
# - X-Accel-Buffering 을 넘긴다: nginx 계열 외부 리버스 프록시(Nginx Proxy Manager 등)도 이 응답만 버퍼링을 끈다
# - proxy_buffer_size 16k — 머리글 버퍼. 한글 255자 파일 이름이면 응답 머리글이 3.5KB 쯤이다(Content-Disposition 하나가 2.5KB) — 기본 4k 로는 빠듯하다
# 버퍼링을 끈 응답은 본문도 이 크기로 받아 넘긴다(기본 4k 보다 시스템 호출이 적다). proxy_busy_buffers_size 는 nginx 가 함께 맞추라고 하는 값이다 —
# 안 적으면 2 × 16k = 32k 가 proxy_buffers(8 × 4k)의 "하나 뺀 합" 28k 를 넘어 설정 검사가 멈춘다. 버퍼링을 끈 location 이라 proxy_buffers 는 쓰이지 않는다
# - 압축하지 않는다(gzip_types 에 application/octet-stream 이 없지만 목록을 넓혀도 이 경로는 그대로) · Range · If-Range 는 손대지 않고 넘긴다
# (nginx 는 프록시한 응답을 스스로 자르지 않는다 — 백엔드의 206 · 416 이 그대로 간다)
# - 시간: proxy_read_timeout 은 백엔드에서 "두 번 읽는 사이", send_timeout(기본 60s)은 받는 쪽에 "두 번 쓰는 사이"다 — 느려도 조금씩
# 받아 가면 끊지 않고, 받는 쪽이 60초 동안 하나도 받지 않으면 끊는다(브라우저 · 내려받기 관리자는 Range 로 이어 받는다 — mail/README.md 의 시험)
# - 동시 연결: 클라이언트 주소마다 10 · 공개 받기 전체 400 — 넘으면 429 REQ_001 (nginx.conf 의 http 단계 "동시 연결 수")
# - 토큰 칸은 [^/]+ 가 아니라 .+ — nginx 는 %2F 를 / 로 풀어 location 을 고르고 백엔드는 한 칸으로 읽는다(지금은 백엔드의 토큰 검사가 그 꼴을 404 로 막지만 기대지 않는다)
# - 같은 줄들이 nginx.conf 의 앱 안 받기(/api/messages/{id}/large-files/…)에 있다 — 한쪽을 고치면 다른 쪽도
# error_page 를 하나라도 쓰면 위의 것을 물려받지 않아 셋을 다 적는다
location ~* ^/api/public-links/.+/files/ {
limit_conn download_public_ip 10;
limit_conn download_public_total 400;
error_page 413 @api_payload_too_large;
error_page 429 @api_too_many_requests;
error_page 500 502 503 504 @api_unavailable;
proxy_buffering off;
proxy_buffer_size 16k;
proxy_busy_buffers_size 16k;
gzip off;
proxy_pass_header X-Accel-Buffering;
proxy_pass $backend_upstream;
}
# 링크 정보 GET /api/public-links/{token}(JSON) 등 — 백엔드로 넘긴다. 공개 내려받기 server 의 /api/ 블록은 404 만 정하므로 여기서 다 적는다
location ~* ^/api/public-links(?:/|$) {
error_page 413 @api_payload_too_large;
error_page 500 502 503 504 @api_unavailable;
proxy_pass $backend_upstream;
}