μ•ˆλ…•ν•˜μ„Έμš”! Nκ°œμ›” μ°¨ ν™ˆ μ„œλ²„ μš΄μ˜μžμž…λ‹ˆλ‹€.

μ˜€λŠ˜μ€ μ œκ°€ 거의 ν•œ 달간 κ²ͺμ—ˆλ˜ λ”μ°ν•œ λ¬Έμ œμ™€, λ„ˆλ¬΄λ‚˜λ„ ν—ˆλ¬΄ν•˜κ³  κ°„λ‹¨ν–ˆλ˜ κ·Έ 해결책을 κ³΅μœ ν•˜λ € ν•©λ‹ˆλ‹€.

ν˜Ήμ‹œ “Cloudflared ν„°λ„λ‘œ μ—°κ²°ν•œ λ‚΄ μ„œλΉ„μŠ€κ°€ 1~2λΆ„λ§ˆλ‹€ λŠκ²Όλ‹€κ°€ λ‹€μ‹œ λΆ™μ–΄μš”!” ν˜Ήμ€ “SSH 접속이 자꾸 λŠκ²¨μš”!” ν•˜λŠ” 뢄이 μžˆλ‹€λ©΄, 이 글이 λ‹Ήμ‹ μ˜ μ‹œκ°„μ„ 아껴쀄 κ²ƒμž…λ‹ˆλ‹€.

😭 ν•œ 달간 μ €λ₯Ό 괴둭힌 증상

μ €λŠ” λ§₯λ―Έλ‹ˆ(Mac mini)에 Docker둜 각쒅 μ„œλΉ„μŠ€λ₯Ό μ˜¬λ €λ‘κ³ , Cloudflare의 cloudflared 터널을 μ΄μš©ν•΄ μ™ΈλΆ€ 도메인을 μ—°κ²°ν•΄ μ‚¬μš©ν•˜κ³  μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

ν•˜μ§€λ§Œ μ–Έμ  κ°€λΆ€ν„° λͺ¨λ“  μ„œλΉ„μŠ€κ°€ 1~2λΆ„ κ°„κ²©μœΌλ‘œ 접속이 λŠκ²Όλ‹€ μ‚΄μ•„λ‚˜λŠ” ‘μ’€λΉ„’ μƒνƒœκ°€ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

  1. μ›Ή μ„œλΉ„μŠ€ 접속이 κ°„ν—μ μœΌλ‘œ 먹톡이 λ˜μ—ˆλ‹€κ°€ μƒˆλ‘œκ³ μΉ¨ν•˜λ©΄ λ‹€μ‹œ λ©λ‹ˆλ‹€.
  2. cloudflared 터널을 톡해 μ—°κ²°ν•œ SSH μ„Έμ…˜μ΄ 타이핑을 μž μ‹œ λ©ˆμΆ”λ©΄ κ·ΈλŒ€λ‘œ λ©ˆμΆ°λ²„λ¦½λ‹ˆλ‹€.
  3. μ»¨ν…Œμ΄λ„ˆ μž¬μ‹œμž‘, autoheal 적용 λ“± λ‹€μ–‘ν•œ μ‹œλ„λ₯Ό ν•΄λ΄€μ§€λ§Œ λͺ¨λ‘ μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€. 문제λ₯Ό ν™•μΈν•˜κΈ° μœ„ν•΄ cloudflared μ»¨ν…Œμ΄λ„ˆμ˜ 둜그λ₯Ό μ°μ–΄λ΄€μŠ΅λ‹ˆλ‹€.

docker logs -f [λ‚΄ cloudflared μ»¨ν…Œμ΄λ„ˆ 이름]

λ‘œκ·Έμ—λŠ” 1~2λΆ„ κ°„κ²©μœΌλ‘œ λ‹€μŒκ³Ό 같은 μ§€μ˜₯의 λ©”μ‹œμ§€κ°€ 반볡되고 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

ERR failed to accept incoming stream requests error=“failed to accept QUIC stream: timeout: no recent network activity”

ERR failed to run the datagram handler error="timeout: no recent network activity"

INF Retrying connection in up to 1s...

INF Registered tunnel connection ... protocol=quic

… (1~2λΆ„ λ’€) …

ERR failed to accept QUIC stream: timeout: no recent network activity

“졜근 λ„€νŠΈμ›Œν¬ ν™œλ™μ΄ μ—†μ–΄μ„œ” νƒ€μž„μ•„μ›ƒμ΄ λ‚¬λ‹€λŠ” λ©”μ‹œμ§€μ˜€μŠ΅λ‹ˆλ‹€.


πŸ•΅οΈβ€β™‚οΈ μ§„μ§œ 범인은 λ”°λ‘œ μžˆμ—ˆλ‹€: ν™ˆ 곡유기

둜그의 핡심 ν‚€μ›Œλ“œλŠ” **QUIC**μ˜€μŠ΅λ‹ˆλ‹€.

cloudflaredλŠ” 기본적으둜 Cloudflare μ—£μ§€ μ„œλ²„μ™€ QUIC (UDP 기반) ν”„λ‘œν† μ½œλ‘œ 톡신을 μ‹œλ„ν•©λ‹ˆλ‹€. λΉ λ₯΄κ³  νš¨μœ¨μ μ΄λ‹ˆκΉŒμš”.

“UDP… νƒ€μž„μ•„μ›ƒ…?”

ν˜Ήμ‹œλ‚˜ ν•˜λŠ” λ§ˆμŒμ— 저희 μ§‘ 메인 곡유기(ipTIME) μ„€μ • νŽ˜μ΄μ§€μ— μ ‘μ†ν–ˆμŠ΅λ‹ˆλ‹€.

❗️ (κΏ€νŒ) λ‚΄ λ§₯λ―Έλ‹ˆκ°€ μ—°κ²°λœ 곡유기 IP 확인법

ν„°λ―Έλ„μ—μ„œ netstat -nr | grep defaultλ₯Ό 치면 λ‚˜μ˜€λŠ” Gateway IPκ°€ λ°”λ‘œ λ‹Ήμ‹ μ˜ 곡유기 μ£Όμ†Œμž…λ‹ˆλ‹€.

곡유기 관리 νŽ˜μ΄μ§€μ˜ νŠΈλž˜ν”½ 관리 > 컀λ„₯μ…˜ μ œμ–΄ λ©”λ‰΄μ—μ„œ μ €λŠ” 범인을 λ§ˆμ£Όν–ˆμŠ΅λ‹ˆλ‹€.

  • TCP ESTABLISHED TIMEOUT: 86400초 (24μ‹œκ°„)
  • UDP TIMEOUT: 30초 λ°”λ‘œ μ΄κ²ƒμ΄μ—ˆμŠ΅λ‹ˆλ‹€!

cloudflaredλŠ” UDP둜 μ—°κ²°ν–ˆλŠ”λ°, 제 κ³΅μœ κΈ°λŠ” UDP 연결이 단 30초 λ™μ•ˆ μ•„λ¬΄λŸ° ν™œλ™μ΄ μ—†μœΌλ©΄ “λ„ˆ μ£½μ—ˆλ‹ˆ?” ν•˜κ³  연결을 κ°•μ œλ‘œ λŠμ–΄λ²„λ Έλ˜ κ²ƒμž…λ‹ˆλ‹€.

이둜 인해 λ‹€μŒκ³Ό 같은 ‘죽음의 사이클’이 λ°˜λ³΅λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

  1. cloudflaredκ°€ QUIC(UDP)으둜 연결에 μ„±κ³΅ν•©λ‹ˆλ‹€. (protocol=quic)
  2. μ„œλΉ„μŠ€μ— νŠΈλž˜ν”½μ΄ 30μ΄ˆκ°„ μ—†μŠ΅λ‹ˆλ‹€. (SSH μž μ‹œ λŒ€κΈ° λ“±)
  3. κ³΅μœ κΈ°κ°€ “30초 지났넀? 아웃!“이라며 UDP 연결을 κ°•μ œ μ’…λ£Œν•©λ‹ˆλ‹€.
  4. cloudflaredλŠ” λ’€λŠ¦κ²Œ 연결이 끊긴 것을 κ°μ§€ν•˜κ³  timeout 였λ₯˜λ₯Ό λΏœμ–΄λƒ…λ‹ˆλ‹€.
  5. cloudflaredκ°€ μž¬μ—°κ²°μ„ μ‹œλ„ν•©λ‹ˆλ‹€. (1번으둜 λŒμ•„κ°)

πŸ’‘ “그럼 UDP νƒ€μž„μ•„μ›ƒμ„ 24μ‹œκ°„μœΌλ‘œ 늘리면 λ˜μ§€!” …라고 μƒκ°ν•˜μ…¨λ‹€λ©΄?

🚨 μ ˆλŒ€ μ•ˆ λ©λ‹ˆλ‹€! (함정 μΉ΄λ“œ)

저도 μ²˜μŒμ—” “UDP νƒ€μž„μ•„μ›ƒμ„ 30μ΄ˆμ—μ„œ 86400초둜 λ°”κΏ”μ•Όκ² λ‹€!“라고 μƒκ°ν–ˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ΄λŠ” 더 큰 μž¬μ•™μ„ λΆ€λ¦…λ‹ˆλ‹€.

  • TCPλŠ” 연결을 μ‹œμž‘(SYN)ν•˜κ³  μ’…λ£Œ(FIN)ν•  λ•Œ μ„œλ‘œ “μ•ˆλ…•!”, “잘 κ°€!” ν•˜κ³  μ‹ ν˜Έλ₯Ό μ£Όκ³ λ°›μŠ΅λ‹ˆλ‹€. κ³΅μœ κΈ°λŠ” 이 “잘 κ°€!” μ‹ ν˜Έλ₯Ό 보고 연결을 λ°”λ‘œ λͺ©λ‘μ—μ„œ μ§€μ›λ‹ˆλ‹€. 24μ‹œκ°„ νƒ€μž„μ•„μ›ƒμ€ ν˜Ήμ‹œλ‚˜ μ‹ ν˜Έ 없이 죽은 ‘μ’€λΉ„ μ„Έμ…˜’을 치우기 μœ„ν•œ μ΅œν›„μ˜ 보루일 λΏμž…λ‹ˆλ‹€.
  • UDPλŠ” 그런 μ‹ ν˜Έκ°€ μ—†μŠ΅λ‹ˆλ‹€. κ·Έλƒ₯ 데이터λ₯Ό λ˜μ§‘λ‹ˆλ‹€. 곡유기 μž…μž₯μ—μ„œλŠ” 이 연결이 λλ‚œ 건지, μž μ‹œ μ‰¬λŠ” 건지 μ•Œ 방법이 μ—†μŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ ‘νƒ€μž„μ•„μ›ƒ’이 연결을 μ²­μ†Œν•˜λŠ” μœ μΌν•œ μˆ˜λ‹¨μž…λ‹ˆλ‹€. λ§Œμ•½ UDP νƒ€μž„μ•„μ›ƒμ„ 24μ‹œκ°„μœΌλ‘œ 늘리면, 잠깐 μ‚¬μš©λœ λͺ¨λ“  UDP μ—°κ²°(DNS 쑰회, κ²Œμž„ μ‹ ν˜Έ λ“±)이 곡유기 λ©”λͺ¨λ¦¬μ— 24μ‹œκ°„ λ™μ•ˆ μŒ“μ΄κ²Œ λ©λ‹ˆλ‹€. κ°€μ •μš© κ³΅μœ κΈ°λŠ” 이 λ©”λͺ¨λ¦¬(μ„Έμ…˜ ν…Œμ΄λΈ”)κ°€ 맀우 μž‘μ•„μ„œ, λͺ‡ μ‹œκ°„ μ•ˆμ— ν…Œμ΄λΈ”μ΄ 꽉 μ°¨ 인터넷 전체가 먹톡이 λ˜λŠ” λŒ€μ°Έμ‚¬κ°€ λ²Œμ–΄μ§‘λ‹ˆλ‹€.

30μ΄ˆλŠ” λ‹€ μ΄μœ κ°€ μžˆμ—ˆλ˜ κ²ƒμž…λ‹ˆλ‹€.


βœ… μ΅œμ’… ν•΄κ²°μ±…: κ³΅μœ κΈ°κ°€ μ•„λ‹Œ Cloudflaredλ₯Ό λ°”κΎΈμž

원인을 μ•Œμ•˜μœΌλ‹ˆ 해결은 κ°„λ‹¨ν•©λ‹ˆλ‹€. 곡유기 섀정을 κ±΄λ“œλ¦¬λŠ” 것이 μ•„λ‹ˆλΌ, **cloudflared**κ°€ 30초 룰을 피해가도둝 λ§Œλ“€λ©΄ λ©λ‹ˆλ‹€.

“UDP(30초) 말고, TCP(24μ‹œκ°„)둜 μ—°κ²°ν•΄!”

cloudflaredλŠ” μΉœμ ˆν•˜κ²Œλ„ 이 μ˜΅μ…˜μ„ μ œκ³΅ν•©λ‹ˆλ‹€. docker-compose.yml νŒŒμΌμ— ν™˜κ²½ λ³€μˆ˜ ν•œ μ€„λ§Œ μΆ”κ°€ν•˜λ©΄ λ©λ‹ˆλ‹€.

μˆ˜μ • μ „ **docker-compose.yml** (μ˜ˆμ‹œ):

YAML

services: cloudflared: container_name: assemblywatch-tunnel image: cloudflare/cloudflared:latest restart: unless-stopped environment: - CLOUDFLARE_TUNNEL_TOKEN # ... (기타 μ„€μ •) ...

μˆ˜μ • ν›„ **docker-compose.yml** (μ΅œμ’… ν•΄κ²°μ±…):

YAML

services: cloudflared: container_name: assemblywatch-tunnel image: cloudflare/cloudflared:latest restart: unless-stopped environment: - CLOUDFLARE_TUNNEL_TOKEN # πŸ‘‡ [ν•΄κ²°μ±…] 이 ν•œ 쀄을 μΆ”κ°€ν•©λ‹ˆλ‹€! - TUNNEL_TRANSPORT_PROTOCOL=http2 # ... (기타 μ„€μ •) ... dns: # (선택 사항) DNS도 Cloudflare둜 μ§€μ •ν•΄μ£Όλ©΄ μ’‹μŠ΅λ‹ˆλ‹€. - "1.1.1.1" - "1.0.0.1"

  • TUNNEL_TRANSPORT_PROTOCOL: http2λŠ” cloudflaredμ—κ²Œ “UDP(QUIC) λŒ€μ‹  TCP 기반인 HTTP/2 ν”„λ‘œν† μ½œλ‘œ 터널을 λš«μ–΄λΌ"κ³  λͺ…λ Ήν•˜λŠ” ν™˜κ²½ λ³€μˆ˜μž…λ‹ˆλ‹€. 이제 μ»¨ν…Œμ΄λ„ˆλ₯Ό λ‹€μ‹œ μƒμ„±ν•©λ‹ˆλ‹€.

Bash

docker-compose up -d --force-recreate cloudflared


πŸŽ‰ 확인 사살: 평화가 μ°Ύμ•„μ˜¨ 둜그

λ‹€μ‹œ 둜그λ₯Ό 확인해 λ΄€μŠ΅λ‹ˆλ‹€.

Bash

assemblywatch-tunnel | 2025-11-14T12:50:07Z INF Environmental variables map[... TUNNEL_TRANSPORT_PROTOCOL:http2] assemblywatch-tunnel | 2025-11-14T12:50:07Z INF Initial protocol http2 assemblywatch-tunnel | 2025-11-14T12:50:07Z INF Registered tunnel connection ... protocol=http2 assemblywatch-tunnel | 2025-11-14T12:50:07Z INF Registered tunnel connection ... protocol=http2

protocol=quic이 protocol=http2둜 바뀐 것이 λ³΄μ΄μ‹œλ‚˜μš”?

이제 제 터널은 24μ‹œκ°„ νƒ€μž„μ•„μ›ƒμ΄ 보μž₯된 TCP μœ„μ—μ„œ μ•ˆμ •μ μœΌλ‘œ μž‘λ™ν•©λ‹ˆλ‹€. ν•œ 달간 μ €λ₯Ό 괴둭히던 λŠκΉ€ ν˜„μƒκ³Ό SSH 먹톡 ν˜„μƒμ΄ μ™„λ²½ν•˜κ²Œ μ‚¬λΌμ‘ŒμŠ΅λ‹ˆλ‹€!

맺으며

미래의 λ‚˜μ™€ 또 λ‹€λ₯Έ ν™ˆ μ„œλ²„ μœ μ €λΆ„λ“€μ—κ²Œ…

“λ¬Έμ œκ°€ 생기면 둜그λ₯Ό μžμ„Ένžˆ 보고, κ·Έ λ‘œκ·Έμ— λ‚˜μ˜¨ ν‚€μ›Œλ“œ(ν”„λ‘œν† μ½œ)κ°€ λ‚΄ λ„€νŠΈμ›Œν¬ ν™˜κ²½(곡유기)의 λ£°κ³Ό μΆ©λŒν•˜μ§€ μ•ŠλŠ”μ§€ κΌ­ 확인해 λ³΄μ„Έμš”!”

정말 κ°„λ‹¨ν•œ ν™˜κ²½ λ³€μˆ˜ ν•˜λ‚˜μ˜€μ§€λ§Œ, 이걸 μ°ΎκΈ° μœ„ν•΄ ν•œ 달을 λŒμ•„μ™”λ„€μš”. 이 글이 μ—¬λŸ¬λΆ„μ˜ μ‚½μ§ˆμ„ 단 5λΆ„ λ§Œμ— 끝내주길 λ°”λžλ‹ˆλ‹€.

λͺ¨λ‘ 즐거운 ν™ˆ μ„œλ²„ 운영 λ˜μ„Έμš”! πŸ₯³