1. 문제 상황 및 현상
Synology NAS를 운용하며 동일한 계정으로 DSM File Station과 macOS SMB로 접속했을 때는 모든 폴더가 정상적으로 보였으나,
유독 macOS Finder(네이티브 WebDAVFS)로 마운트했을 때 특정 폴더(예: Mac)만 목록에서 완전히 사라지는 현상이 발생했습니다. 사용자 확인
- 기이한 증상: 사라진
Mac폴더의 이름을 더 긴 영문 이름이나 한글 이름으로 변경하면 Finder에 즉시 나타나고, 다시Mac으로 바꾸면 즉시 사라짐. - 해결 목표: NAS에 저장된 실제 폴더명이나 파일 내용을 전혀 변경하지 않고, 기존에 사용하던 외부 접속 주소(
https://nas.example.com:5006)를 그대로 유지하며 해결.
테스트 및 재현 환경 실측
| 구분 | 세부 사양 / 버전 | 비고 |
|---|---|---|
| NAS 하드웨어 | Synology DS1821+ | AMD Ryzen V1500B |
| 운영체제 (DSM) | DSM 7.4.1-90080 | 실측 설치 버전 (최신 여부 미검증) |
| WebDAV 패키지 | Synology WebDAV Server 2.4.8-20135 | HTTP 5005 구동 |
| 클라이언트 OS | macOS 27.0.1 | 네이티브 Finder WebDAVFS |
| 컨테이너 환경 | Docker 24.0.2 / Python 3.11.17 / aiohttp 3.14.5 | 내부 보정 게이트웨이 |
2. 기술 분석: 유니코드 정규화(NFC vs NFD)와 길이 판별 버그
이 문제는 Apple의 오픈소스 WebDAV 클라이언트인 webdavfs의 디렉터리 계층 파싱 로직에서 기인한 것으로 판단됩니다. 원인 분석 (공개 소스 기반 추정)
Apple 오픈소스 webdavfs (mount.tproj/webdav_parse.c의 GetNormalizedPathLength 및 GetComponentName) 소스코드를 살펴보면,
macOS Finder는 서버로부터 전달받은 PROPFIND 207 Multi-Status XML 응답을 처리할 때 URL 퍼센트 디코딩을 거친 후
CFStringGetLength(UTF-16 코드 유닛 길이)를 기준으로 부모 경로와 자식 경로의 길이를 단순 비교합니다.
macOS 클라이언트는 서버에 요청을 보낼 때 부모 경로를 NFD (자모 분리형 정규화)로 전송합니다. 반면 Synology WebDAV Server는 내부 저장소에 저장된 형태 그대로 NFC (완성형 정규화) 경로를
DAV:href 태그에 담아 반환합니다.
실제 경로별 UTF-16 코드 유닛 길이 비교 실측표 실측
| 항목 구분 | 경로 문자열 | NFC 길이 (UTF-16) | NFD 길이 (UTF-16) | Finder 표시 여부 및 판정 로직 |
|---|---|---|---|---|
| 부모 폴더 (요청 기준) | /home/#설치어플/ |
12 | 18 | macOS Finder가 요청 시 사용한 부모 경로 기준 길이: 18 |
| 자식 폴더 1 (누락됨) | /home/#설치어플/Mac/ |
16 | 22 | 누락 (16 ≤ 18): 자식 NFC 길이가 부모 NFD보다 길지 않아 스킵됨! |
| 자식 폴더 2 (정상 표시) | /home/#설치어플/Android/ |
20 | 26 | 정상 표시 (20 > 18): 자식 길이가 부모 길이보다 길어 정상 인식 |
| 자식 폴더 3 (정상 표시) | /home/#설치어플/Windows/ |
20 | 26 | 정상 표시 (20 > 18): 자식 길이가 부모 길이보다 길어 정상 인식 |
위 표에서 명확히 드러나듯이, 부모 폴더의 NFD 길이(18)와 Mac 자식 폴더의 NFC 응답 길이(16)를 단순 비교하면
16 ≤ 18이 성립하여 Finder의 파서가 "자식 경로가 부모 경로보다 길지 않으므로 하위 항목이 아니다"라고 잘못 판단하고 목록에서 완전히 제외(skip)해 버립니다.
반면 Android와 Windows는 영문 글자 수가 충분하여 NFC 전체 길이가 20이 되므로 20 > 18이 되어 정상 노출되었던 것입니다.
본 원인 분석은 Apple의 공개 소스코드, 실제 재현 증상, 보정 게이트웨이 적용 후 복구 결과를 바탕으로 논리적으로 도출된 기술적 추정(inferred from public source)이며, Apple 또는 Synology 제조사의 공식 버그 확정(vendor confirmed)이나 향후 OS 지원 약속을 의미하는 것은 아닙니다. 추정/판단
3. 해결 방안: NFD 응답 보정 게이트웨이 및 데이터 흐름
근본적인 해결을 위해 NAS 저장 파일이나 폴더명을 변경하지 않고, 클라이언트와 WebDAV 서버 중간에 경량 비동기 보정 게이트웨이(Python aiohttp)를 배치하였습니다.
- 동작 원리: 클라이언트의
User-Agent가 macOS WebDAVFS인 경우에 한하여,PROPFIND 207 Multi-StatusXML 응답 내DAV:multistatus/DAV:response/DAV:href경로만 NFD로 실시간 보정합니다. 실측 - 데이터 전달 및 속성 보존: 클라이언트의 요청 경로는 임의로 변환하지 않으며, 일반 파일 본문(file body) 및 DAV LOCK 토큰 등은 변경 없이 원본 그대로 전달됩니다. 반면, NFD로 보정된 PROPFIND 207 응답에서는 본문 변환에 따라
ETag,Digest,Content-MD5헤더가 제거되고Content-Length헤더는 재계산되어 전송됩니다. (모든 HTTP 헤더의 원본 보존이나 무조건적인 복구를 주장하지 않음) - 스트리밍 및 버퍼/형식 제한: 일반 파일 다운로드/업로드는 64 KiB 단위로 청크 스트리밍 처리되며, XML 목록 응답만 최대 10 MiB 버퍼 내에서 처리됩니다. XML 크기가 10 MiB를 초과하거나 구문 오류(malformed XML)가 있는 경우 조용히 무시하지 않고 명시적으로 실패(502) 처리합니다.
- 정규화 충돌 방지: 동일 디렉터리 내에 서로 다른 NFC/NFD 변형 항목들이 공존하여 NFD 변환 시 동일한 href로 귀결되는 경우, 항목을 임의로 누락(silent drop)시키는 대신
502 Bad Gateway오류를 명시적으로 반환하여 데이터 불일치 위험을 방지합니다.
4. 실제 동작 및 복구 증빙 스크린샷
아래는 개인정보가 포함될 수 있는 사이드바 영역을 비공개 처리하고 새로 캡처한 실제 화면입니다. 실측 스크린샷
finder-after.png):개인정보 보호를 위해 좌측 사이드바 영역을 숨긴 상태로 촬영되었습니다.
/Volumes/home/#설치어플 경로 내에 기존 네이티브 WebDAV에서 보이지 않던 'Mac' 폴더가
이름을 바꾸지 않고도 Android, Windows와 함께 정상적으로 표시되는 것을 확인할 수 있습니다
(화면에 표시된 3개 폴더는 숨김 항목을 제외한 화면입니다).
gateway-health.png):Synology Container Manager 상에서 내부 보정 게이트웨이가 정상 구동되어 미인증 PROPFIND 요청 시 원본 WebDAV 서버의 권한 검증에 따라
401 Unauthorized를 정상 반환하고 있는 실제 화면입니다 (개인 주소가 없는 401 필터 화면).
5. 설치 및 구성 가이드 (Synology DSM 포트 점유 특성 포함)
중요: Synology DSM WebDAV 5006 포트 점유 특성 및 우회법
기존에 사용하던 외부 접속 주소(https://nas.example.com:5006)를 유지하기 위해서는
외부 포트 5006을 DSM 역방향 프록시가 수신하도록 설정해야 합니다.
하지만 Synology WebDAV Server 패키지는 다음과 같은 특이한 포트 점유 동작을 보입니다:
1. WebDAV Server 패키지 GUI에서 HTTPS 활성화 체크를 끄기만 해도 백그라운드에서 5006 포트 예약이 유지됩니다.
2. 비활성화된 상태에서는 HTTPS 포트 입력 필드가 잠기므로 포트 번호를 수정해도 저장되지 않습니다.
3. 따라서 HTTPS가 체크된 상태에서 다른 미사용 포트(예: 18081)로 변경하여 [적용]한 후, 다시 HTTPS 체크를 해제(OFF)하여 [적용]해야 비로소 5006 포트 점유가 완전히 풀립니다.
단계별 설정 절차
-
Synology WebDAV Server 포트 변경 및 비활성화:
- DSM 패키지 센터 → WebDAV Server 실행
- HTTP 활성화: 체크 (포트:
5005유지) - HTTPS 활성화: 체크 후 포트를
18081로 변경 → [적용] - [적용] 완료 후 다시 HTTPS 활성화: 체크 해제(OFF) → [적용]
- (최종 상태: 직접 HTTPS 18081 OFF, 기존 HTTP 5005 ON)
-
내부 보정 게이트웨이 빌드 및 실행 (Docker Compose):
사전 빌드된 DockerHub 이미지는 배포되지 않으므로, GitHub 저장소 소스를 복제하여 직접 빌드 및 실행합니다.
docker-compose.yml이 구성의 기준(Source of Truth)입니다:# 1. 저장소 복제 및 디렉터리 이동 git clone https://github.com/armsone/webdav-finder-compat.git cd webdav-finder-compat # 2. 환경 설정 파일 복사 및 공개 접속 주소 설정 (REQUIRED) cp env.example .env # .env 파일 내 WEBDAV_PUBLIC_ORIGIN 필수(REQUIRED) 설정: 클라이언트 실제 접속 scheme+hostname+port 정확 일치 필요 (불일치 시 COPY/MOVE 400 거절 발생 가능, 예: https://nas.example.com:5006) # 3. Docker Compose 빌드 및 백그라운드 실행 docker compose up -d --build※
WEBDAV_PUBLIC_ORIGIN은 필수(REQUIRED) 설정으로 클라이언트가 실제로 접속하는scheme+hostname+port와 정확히 일치해야 합니다. 불일치 시 Destination 헤더 검증 실패로 WebDAV COPY/MOVE 요청이 400 Bad Request로 거절될 수 있습니다. 호스트 게이트웨이(host.docker.internal) 연결 및 세부 환경변수 설정은 저장소의 README.md 및 docker-compose.yml을 참고하십시오. -
DSM 역방향 프록시 규칙 추가:
- 제어판 → 로그인 포털 → 고급 → 역방향 프록시 → [생성]
- 소스: 프로토콜
HTTPS, 호스트 이름nas.example.com, 포트5006 - 대상: 프로토콜
HTTP, 호스트 이름127.0.0.1, 포트18080 - ※ 본 해결책 구성을 위해 별도의 HSTS 변경은 요구되지 않습니다.
-
SSL/TLS 인증서 수동 할당 및 호스트 확인:
- 제어판 → 보안 → 인증서 → [설정] 버튼 클릭
- 새로 생성한 역방향 프록시 규칙(
nas.example.com:5006) 항목에 기존의 유효한 도메인 인증서를 직접 할당(수동 지정)하고 호스트 이름을 확인합니다 (역방향 프록시 규칙 생성 시 인증서가 자동 할당되지 않음).
롤백(Rollback) 절차
이전 순정 상태로 되돌리고자 할 때는 반드시 아래 순서를 준수해야 포트 충돌 오류가 발생하지 않습니다:
- 역방향 프록시 규칙 제거: DSM 제어판의 역방향 프록시에서 5006 포트 규칙을 먼저 삭제하거나 비활성화합니다.
- WebDAV Server 패키지 HTTPS 복원: WebDAV Server 패키지 설정에서 HTTPS를 활성화하고 포트 번호를
18081에서 원래의5006으로 수정한 뒤 [적용]합니다.
※ 본 설정은 NAS 원본 nginx.conf 시스템 설정 파일이나 SSL 인증서 개인키를 직접 수정·복사하지 않고 독립된 역방향 프록시 규칙과 컨테이너를 사용하므로 변경 범위가 격리됩니다. (단, 시스템 손상 위험 0%나 절대적 안전을 무조건 보장하는 것은 아니므로 작업 전 설정을 확인하십시오.)
6. 실측 검증 범위 및 한계점 고지
문제 디렉터리인
/home/#설치어플/ 하위 전체 161개 항목(폴더 36개, 파일 125개)에 대해
파일시스템과 WebDAV 클라이언트의 이름 및 구조 메타데이터(목록 구조)를 비교 검증한 결과,
누락 0건, 추가 항목 0건, 정규화 충돌 0건으로 일치함을 확인하였습니다. 실측(※ 본 검증은 디렉터리 이름 및 구조 메타데이터 목록 비교이며, 파일 내용 무결성(file content integrity) 전수 검증이 아님에 유의하십시오.)
또한 사용자가 확인했던 다른 문제 경로 1곳 역시 정상 표시 및 접근 가능함을 확인하였습니다. 사용자 확인
⚠️ 보증 불가 및 한계점 고지 (전수 보장 금지)
- 전체 홈 디렉터리 미검사: 전체 홈 디렉터리 전수 비교는 시스템 부하 방지를 위해 사용자의 명시적 지시로 제외/중단되었으며, 임의로 재개하지 않았습니다. 미검증
- 전체 환경 무누락 보장 금지: 본 결과는 검증된 특정 환경에서의 실측 결과이며, 모든 기종의 NAS, 모든 DSM 버전, 모든 macOS 릴리스 및 모든 폴더 구조에서의 무누락을 보증하지 않습니다.
- 정규화 변형 공존 충돌 시 502 오류 처리: 동일 디렉터리 내에 서로 다른 NFC/NFD 변형 항목들이 공존하여 NFD 변환 시 동일한 href로 충돌하는 경우, 항목을 임의로 누락(silent drop)시키는 대신
502 Bad Gateway오류를 명시적으로 반환합니다. - 응답 크기 10 MiB 초과 및 XML 구문 오류: PROPFIND XML 응답이 10 MiB를 초과하거나 구문 오류(malformed XML)가 존재하는 경우에도 조용히 무시하지 않고 명시적으로 실패(502) 처리합니다.
- 전송 속도 및 성능에 관한 주의: 게이트웨이 자체는 대용량 파일을 64 KiB 단위로 청크 스트리밍 처리하지만, 앞단 DSM Nginx의 업로드 버퍼링(
proxy_request_buffering) 및 네트워크 부하에 따른 전송 속도는 정밀 실측하지 않았습니다. 따라서 "동일 속도 유지", "속도 저하 전혀 없음", "무손실 최고 속도"와 같은 과장된 주장은 하지 않습니다. 미검증
7. 보안 및 네트워크 설계 고려사항
- 인증 및 권한 위임: 클라이언트의 자격 증명(
Authorization헤더)은 백엔드 WebDAV 서버로 그대로 전달(forward)되어 기존 WebDAV 서버가 인증 및 접근 권한을 최종 판정합니다. 보정 게이트웨이는 사용자 계정 및 비밀번호를 로그에 남기거나 영구 저장하지 않습니다. - 인증 요구 401 응답 유지: 비인증 접근 시
401 Unauthorized가 정상적으로 반환됨을 확인하였습니다. 실측 - Docker localhost 바인딩 관련 주의 (Docker < 28.0):
Docker 공식 문서에 따르면 Docker 28.0 미만 버전에서는
127.0.0.1에 포트를 바인딩하더라도 동일 L2 세그먼트 내에서의 접근 관련 주의사항이 존재합니다. 따라서 루프백 매핑만으로 완벽한 내부 격리를 과신하지 말아야 하며, 공유기나 외부 방화벽에서5005나18080포트를 절대 외부 WAN으로 포트포워딩(Port-forwarding)하지 마십시오. 오직 공인 인증서가 적용된 DSM 역방향 프록시의 HTTPS 5006 포트만 외부에 노출되어야 합니다.
8. 커뮤니티 공유용 텍스트 (원클릭 복사용)
아래 텍스트 영역의 내용을 복사하여 NAS 카페, 맥 커뮤니티, 클리앙 등에 바로 게시할 수 있습니다.