Unturned 서버를 DDoS 공격으로부터 방어하기
Unturned 서버에 실제로 필요한 포트는 무엇인지, 27017이 2021년부터 왜 불필요한지, 쿼리 플러드와 접속 플러드, 플러그인 부하는 어떻게 제한하는지, 그리고 어느 공격 규모부터 서버 앞단 네트워크의 필터링만이 통하는지 정리했습니다.
저녁마다 몇 분씩 서버 목록에서 사라지면서 접속해 있던 플레이어 전원을 타임아웃으로 내보내는 Unturned 서버는 하드웨어 문제인 경우가 드뭅니다. 대개는 공격이 진행 중이고, 그것도 사람이 가장 많은 시간대에 벌어집니다. 이 글은 Unturned 서버의 DDoS 방어를 세 단계로 나누어, 먼저 추가 비용 없이 직접 조치할 수 있는 것을 보여 주고, 그다음 그 조치가 기술적으로 어디에서 한계에 이르는지, 마지막으로 서버 앞단 네트워크에서 무엇이 이뤄져야 하는지 설명합니다.
모든 내용은 Debian 12, Debian 13, Ubuntu 22.04 LTS 또는 Ubuntu 24.04 LTS에서 운영하는 Unturned 전용 서버(U3DS, SteamCMD 애플리케이션 ID 1110390)를 기준으로 합니다. 명령은 root 기준으로 적었으니, 일반 사용자라면 앞에 sudo를 붙이세요. 공격이 지금 진행 중이라면, 설정을 바꾸거나 서버를 재시작하지 마시고 먼저 10번 절의 측정값부터 확보하세요. 공격이 끝나면 그 값은 사라집니다.
Unturned 서버가 DDoS 공격의 표적이 되는 이유
Unturned 서버가 공격받는 이유는 주소가 공개되어 있고, 게임 트래픽이 UDP로 흐르며, 공격을 시작하는 쪽에 실력도 이렇다 할 비용도 들지 않기 때문입니다. 세 가지 모두 다른 대부분의 게임보다 여기서 더 강하게 작용합니다.
공개된 Unturned 서버는 자기 IP 주소를 스스로 공개합니다. 그렇게 해야만 하고, 그러지 않으면 아무도 서버를 찾지 못합니다. Steam 서버 브라우저가 서버에 직접 조회하고, unturned-servers.net이나 BattleMetrics 같은 제3자 목록은 IP 주소와 포트를 평문으로 싣습니다. unturned-servers.net은 자체 설명에 따르면 5분마다 서버가 서버 포트에서 UDP 연결을 받는지 확인합니다. 공격자에게 이것은 수고가 아니라 그냥 입력 양식입니다.
여기에 플레이어층이 더해집니다. Unturned는 무료이고 진입 장벽이 없으며, 롤플레이 프로젝트와 서바이벌 프로젝트는 같은 플레이어를 두고 실제로 경쟁합니다. 차단된 플레이어, 감정이 상한 전 관리자, 옆 프로젝트는 여러분의 서버를 한 시간 동안 쓸 수 없게 만들기 위해 서버 접근 권한이 전혀 필요하지 않습니다. DDoS 공격이 기술적으로 무엇이고 위조된 출발지 주소가 추적을 왜 그렇게 어렵게 만드는지는 DDoS 공격이란 무엇인가? 글에서 설명합니다.
실제로 문제가 되는 포트
Unturned 서버는 연속된 UDP 포트 정확히 두 개를 차지합니다. Commands.dat에 설정한 값과 그 값에 1을 더한 값입니다. 기본값으로는 27015와 27016입니다. Smartly Dressed Games의 공식 문서는 역할 분담을 이렇게 설명합니다. 첫 번째 포트는 서버 목록의 조회를 나르고, 두 번째 포트는 게임 트래픽을 나릅니다. 설정하는 것은 첫 번째 포트뿐이고, 두 번째는 자동으로 정해집니다.
Name 내 Unturned 서버
Port 27015
MaxPlayers 24
Map PEI
Mode Normal
Perspective Both
Owner 76561198000000000
Commands.dat는 U3DS/Servers/<INSTANCE>/Server/Commands.dat에 있습니다. 형식이 독특하고 흔한 오류의 원인입니다. 한 줄에 명령 하나, 등호 없음, 값은 공백 하나로 구분, 그리고 명령은 대소문자를 구분합니다. //로 시작하는 줄은 주석입니다.
방화벽에 가장 중요한 점은 이것입니다. 포트 27017은 2021년 11월 21일에 나온 3.21.30.0 버전부터 더 이상 필요하지 않습니다. 그전에는 Steam 쿼리가 게임 포트에 2를 더한 자리에 있었기 때문에 Unturned 서버에 포트 세 개가 필요했습니다. 이 업데이트로 쿼리가 서버 자체와 같은 포트를 함께 쓰게 되었고, 세 번째 포트는 없어졌습니다. 그런데도 라우터 안내서, 호스팅 업체 위키, 포럼 글은 지금까지 27017을 언급합니다. 열려 있는 27017은 이제 아무 이점도 주지 않고, 순수한 공격 표면일 뿐입니다.
이것도 중요합니다. Unturned에는 내장 RCON 포트가 없습니다. 공식 문서에는 콘솔 입력과 콘솔 출력만 있고, 이는 ICommandInputOutput 인터페이스를 통해 직접 구현한 것으로 대체할 수 있습니다. Unturned 서버에서 보게 되는 모든 원격 제어는 플러그인에서 나오고 자체 TCP 포트를 함께 가져옵니다. 이 포트는 여러분이 직접 찾아서 직접 제한해야 합니다. 아무도 대신 막아 두지 않았습니다.
| 항목 | 값(기본값) | 프로토콜 | 설정 위치 |
|---|---|---|---|
| 쿼리 포트(Steam A2S, 서버 목록) | 27015 | UDP | Commands.dat의 Port |
| 게임 포트 | 27016(Port에 1을 더한 값) | UDP | 따로 설정할 수 없음 |
| 세 번째 포트 27017 | 3.21.30.0(2021.11.21.)부터 없어짐 | 없음 | 닫기 |
| 같은 머신의 두 번째 서버 | 27017, 세 번째는 27019 | UDP | Port, 간격 2 |
| RCON | 내장 포트 없음 | 플러그인을 통한 TCP만 | 플러그인 설정 |
| 바인딩 주소 | 모든 인터페이스 | 없음 | Commands.dat의 Bind |
| 플레이어 한 명의 초당 패킷 | 50.0 | UDP | Max_Packets_Per_Second |
| 허용되는 최대 핑 | 750 ms | 없음 | Max_Ping_Milliseconds |
| 시간 창당 접속 시도 한도 | 40.0초 안에 10회 | 없음 | Rate_Limit_Kick_Threshold |
| 대기열 | 8자리, 최대 64자리 | 없음 | Commands.dat의 Queue_Size |
| 안티치트 | VAC와 BattlEye, 둘 다 활성 | 없음 | VAC_Secure, BattlEye_Secure |
| Steam 쿼리의 증폭 계수 | 5.5(US-CERT TA14-017A) | UDP | 프로토콜 특성 |
| 플레이어 24명일 때 평상시 수신 패킷 전송률 | 초당 약 1,200 패킷 | UDP | 24 곱하기 50 |
| 1 Gbit/s 회선의 포화 | 초당 125 MB, 64 바이트 패킷일 때 초당 약 149만 개 | 없음 | 회선의 물리 법칙 |
| KernelHost 서버에서 걸러 낸 공격 | 초당 4,150만 패킷과 함께 473.4 Gbit/s, 112.2 Gbit/s UDP 플러드 | UDP | 운영 중 측정값 |
돈을 쓰기 전에 직접 할 수 있는 일
이 절이 가장 길고, 의도한 바입니다. 설정이 깔끔한 Unturned 서버는 어디에 놓여 있든 작거나 중간 규모의 공격을 자체 힘으로 견뎌 냅니다.
1. 현황 파악: 실제로 무엇이 대기하고 있나요
규칙을 한 줄이라도 쓰기 전에 서버가 외부에 무엇을 내주고 있는지 확인하세요. 추측하지 말고 직접 확인합니다.
ss -lnup
ss -lntp
첫 번째 명령은 대기 중인 UDP 소켓을, 두 번째 명령은 TCP 소켓을 보여 줍니다. 중요한 것은 로컬 주소 열입니다. 0.0.0.0:27015와 [::]:27015는 “인터넷 전체에서 접근할 수 있음”을 뜻하고, 127.0.0.1:3306은 “로컬에서만 접근할 수 있음”을 뜻하므로 방화벽 규칙이 필요하지 않습니다. 게임 외에도 RCON 플러그인, 웹 패널, 데이터베이스, 그리고 아무도 더는 쓰지 않는 27017의 오래된 테스트 서버가 함께 나타나는 일이 잦습니다. 공격자의 시선은 외부에서 실행하는 포트 스캔이 보여 주며, Unturned에서는 반드시 UDP까지 함께 확인해야 합니다.
nmap -Pn -sU -p 27000-27050 YOUR.SERVER.IP.ADDRESS
nmap -Pn -p- --min-rate 1000 YOUR.SERVER.IP.ADDRESS
2. 27015와 27016만 열어 두기
Unturned에는 외부로 UDP 허용 두 개면 충분합니다. 게임 자체에는 TCP 포트가 단 하나도 필요하지 않습니다. 공식 문서는 두 포트 모두에 UDP를 명시적으로 요구하고, 게임의 네트워크 계층(Steam Networking Sockets, 어느 업데이트 이후 기본값)은 UDP만으로 동작합니다. TCP까지 추가로 여는 사람은 오래된 안내서를 따르고 있는 것입니다.
ufw allow 22/tcp comment 'SSH'
ufw allow 27015/udp comment 'Unturned 쿼리'
ufw allow 27016/udp comment 'Unturned 게임'
ufw default deny incoming
ufw default allow outgoing
ufw --force enable
ufw status verbose
순서가 중요합니다. 그러지 않으면 스스로 접속이 막힙니다. 복구 방법까지 포함한 전체 안내는 스스로 접속이 막히지 않게 UFW 방화벽 설정하기에 있습니다. 여러 인스턴스를 운영한다면 권장 간격인 2를 지키고(27015, 27017, 27019), 인스턴스마다 실제로 차지하는 두 포트만 정확히 열어 주세요.
웹 패널, 데이터베이스, RCON 플러그인은 공개 네트워크에 둘 것이 아닙니다. 해당 포트는 ufw allow from 203.0.113.10 to any port 8080 proto tcp로 본인 주소에만 허용하거나, ssh -N -L 8080:127.0.0.1:8080 root@YOUR.SERVER.IP.ADDRESS로 로컬 SSH 포워딩을 통해 화면에 접근하세요. 데이터베이스는 127.0.0.1에 바인딩합니다.
3. 서버 목록에서 사라지지 않으면서 쿼리 포트 지키기
쿼리 포트는 Unturned 서버에서 가장 취약한 지점입니다. 이 포트로 서버가 Steam 쿼리 A2S_INFO, A2S_PLAYERS, A2S_RULES에 응답합니다. 이 포트를 완전히 차단하면 서버가 아무 문제 없이 돌아가고 있어도 모든 서버 목록에서 사라집니다.
A2S 응답은 조회보다 훨씬 큽니다. US-CERT는 UDP 증폭 공격 개요(TA14-017A)에서 Steam 프로토콜의 대역폭 증폭 계수를 5.5로 제시합니다. 구체적으로는 이런 뜻입니다. 공격자는 출발지 주소를 위조한 조회를 남의 게임 서버에 보내고, 약 다섯 배 반 큰 응답을 자신의 실제 표적으로 돌립니다. 그러면 여러분의 서버는 피해자가 아니라 제3자를 향한 증폭기가 됩니다. 반대 방향에서는 쿼리 플러드 하나만으로 플레이어가 한 명도 튕기지 않은 채 서버가 서버 브라우저에서 사라집니다. 운영자들이 보고하는 그림이 정확히 이것입니다. 서버는 돌아가고 접속해 있는 플레이어는 아무것도 느끼지 못하는데, 서버를 찾을 수 없습니다.
작은 쿼리 플러드에는 출발지 주소별 상한이 도움이 됩니다. 정상적인 조회는 드물게 옵니다. Steam 브라우저는 목록을 표시할 때 한 번 조회하고, 상태 서비스는 몇 분마다 조회합니다.
iptables -I INPUT -p udp --dport 27015 -m hashlimit --hashlimit-name unturned_query --hashlimit-mode srcip --hashlimit-above 10/sec --hashlimit-burst 20 -j DROP
iptables -I INPUT -p udp --dport 27016 -m hashlimit --hashlimit-name unturned_game --hashlimit-mode srcip --hashlimit-above 300/sec --hashlimit-burst 500 -j DROP
두 번째 숫자는 게임에서 곧바로 나옵니다. Unturned는 플레이어 한 명을 기본값으로 초당 50 패킷으로 제한합니다(Max_Packets_Per_Second). 따라서 출발지 주소별 초당 300 패킷이면 같은 주소 뒤에 플레이어 여러 명이 있어도 한 회선에 넉넉합니다. 두 값은 모두 출발점일 뿐이고 정답이 아닙니다. 먼저 평상시 운영을 한 주는 측정하세요. 그러지 않으면 자기 플레이어를 내쫓습니다.
iptables 규칙만 쓰면 재시작 후에 사라집니다. Debian과 Ubuntu에서는 apt-get install -y iptables-persistent와 netfilter-persistent save로 저장합니다. UFW를 쓴다면 이런 규칙은 /etc/ufw/before.rules에 들어가야 하며, 그러지 않으면 다음 ufw reload에서 사라집니다.
여기에 돈이 들지 않는 습관 하나를 더합니다. 홈페이지나 Discord 봇이 플레이어 수를 보여 준다면, 방문자마다 서버에 조회하지 말고 일정한 간격으로 결과를 저장해 두고 쓰세요. 그러지 않으면 방문자가 많은 상태 페이지가 간격당 한 번이 아니라 방문자당 한 번의 조회를 만들어 냅니다.
4. Config.json에 내장된 한도 설정하기
Unturned는 Commands.dat와 같은 Server 폴더에 있는 Config.json에, 이름만 보고는 짐작하기 어렵지만 방어에 중요한 절을 하나 담고 있습니다. 기본값은 다음과 같습니다.
"Server": {
"VAC_Secure": true,
"BattlEye_Secure": true,
"Max_Ping_Milliseconds": 750,
"Timeout_Queue_Seconds": 15.0,
"Timeout_Game_Seconds": 30.0,
"Max_Packets_Per_Second": 50.0,
"Join_Rate_Limit_Window_Seconds": 40.0,
"Rate_Limit_Kick_Threshold": 10,
"Use_FakeIP": false
}
Max_Packets_Per_Second는 접속해 있는 플레이어를 초당 50 패킷으로 제한합니다. Join_Rate_Limit_Window_Seconds와 Rate_Limit_Kick_Threshold는 40초 안에 열 번 넘게 한도를 넘어서는 연결을 내보냅니다. VAC_Secure와 BattlEye_Secure는 플레이어 쪽에 두 안티치트 시스템을 모두 요구하며, 그것만으로 일회용 클라이언트 대부분을 막아 냅니다.
여기서 한 가지는 분명해야 합니다. 이 한도는 실제로 접속하거나 접속을 시도하는 클라이언트에 작용합니다. 출발지 주소를 위조한 플러드에는 세션이 아예 만들어지지 않으므로 작용하지 않습니다. 그래도 중요한 까닭은 가장 흔한 단일 사례, 곧 혼자서 서버를 과부하로 몰아가는 조작된 클라이언트 하나를 걸러 내기 때문입니다. Max_Ping_Milliseconds는 750으로 두는 것이 알맞습니다. 더 낮게 잡으면 네트워크가 잠깐 흔들릴 때마다 서버가 판을 절반씩 내보냅니다.
5. 연결 추적 부담 덜기
이 항목은 거의 항상 간과되고, 볼류메트릭 공격처럼 보이지만 실은 그렇지 않은 장애를 설명해 줍니다. 커널은 UDP 트래픽에도 연결 추적(conntrack) 항목을 만들고, 출발지 주소가 위조되면 새 주소마다 새 항목이 생깁니다. 테이블이 가득 차면 커널은 구별하지 않고 패킷을 폐기합니다. 공격과 여러분의 플레이어가 함께 튕겨 나갑니다. 그럴 때 시스템 로그에는 nf_conntrack: table full, dropping packet이 남습니다.
sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max
dmesg -T | grep -i conntrack
가장 효과적인 조치는 Unturned 트래픽을 애초에 추적하지 않게 하는 것입니다. 게임은 세션을 자체적으로 관리하므로 커널의 상태 추적이 필요하지 않습니다.
iptables -t raw -A PREROUTING -p udp --dport 27015 -j NOTRACK
iptables -t raw -A PREROUTING -p udp --dport 27016 -j NOTRACK
이때 두 포트의 허용 규칙이 더 이상 ESTABLISHED,RELATED를 거치지 않고 독자적인 허용 규칙으로 서 있어야 한다는 점에 주의하세요. nf_conntrack_max를 올리는 것은 그다음에야 의미가 있습니다. 테이블을 먼저 키우는 사람은 문제를 몇 분 뒤로 미루면서 그 대가로 메모리를 씁니다.
서버 프로세스가 가져가는 속도보다 패킷이 빨리 도착하면 소켓의 수신 버퍼까지 넘칩니다. 회선은 비어 있는데도 플레이어에게는 패킷 손실처럼 보입니다.
net.core.rmem_max = 16777216
net.core.rmem_default = 1048576
net.core.netdev_max_backlog = 16384
값은 /etc/sysctl.d/에 넣고 sysctl --system으로 적용하세요. 필요한지 여부는 커널이 알려 줍니다. nstat -az의 UdpRcvbufErrors가 올라가거나 ss -lunp의 수신 대기열에 뭔가 계속 쌓여 있으면 이 값이 효과를 냅니다. 둘 다 0에 머물러 있으면 조정해도 달라지는 것이 없습니다. 이것은 여유분이고 방어 수단이 아닙니다.
6. 접속 플러드, 대기열, 허용 목록
접속 플러드는 공격자가 회선을 채우는 대신 정상 접속 경로를 이용해 슬롯과 연산 시간을 소모하는 공격입니다. Unturned는 이에 맞서는 도구 네 가지를 갖추고 있고, 모두 Commands.dat에 들어갑니다.
Queue_Size 32는 대기열을 설정합니다. 기본값은 8자리, 최대는 64자리입니다. 대기열이 너무 크면 공격자를 돕고, 너무 작으면 재시작할 때마다 실제 플레이어를 떨어뜨립니다.Whitelisted는 서버를 접근 목록 방식으로 바꿉니다. 콘솔에서permit <SteamID64>로 등록하고unpermit <SteamID64>로 해제합니다.Password YOUR_PASSWORD는 어떤 목록에서 주소만 알아낸 쪽을 모두 배제합니다.Filter는 이름에 허용되지 않는 문자가 들어간 플레이어를 거부하고,MaxPlayers 24는 하드웨어가 실제로 버티는 수준으로 슬롯 수를 맞춰 둡니다.
허용 목록은 여러분의 게임 로직을 지키고 회선은 지키지 않습니다. 서버를 플러딩하는 공격자는 애초에 접속할 생각이 없습니다. 그의 패킷은 거부되지만 이미 도착해 있고, 문제는 정확히 그 지점입니다.
7. RocketMod, OpenMod와 플러그인 측면
Unturned에는 널리 쓰이는 플러그인 플랫폼이 두 개 있고, 둘 다 서버와 같은 프로세스에서 돌아갑니다. RocketMod가 더 오래된 쪽입니다. 원래 관리자들은 2019년 12월 20일에 유지 관리를 중단하고 소스 코드를 MIT 라이선스로 공개했습니다. 그 뒤로 Smartly Dressed Games가 파생 버전 Legally Distinct Missile(LDM)을 관리하며, 이것은 전용 서버에 이미 함께 들어 있습니다. Extras 폴더의 Rocket.Unturned를 Modules 폴더로 복사하면 됩니다. 개발자들은 스레딩 오류나 텔레포트 익스플로잇 같은 옛 Rocket 문제를 고쳤다는 이유로 이 파생 버전을 명시적으로 권장합니다.
OpenMod는 더 새로운 후속 플랫폼이고, 원래 Rocket 관리자 가운데 한 사람이 개발했습니다. RocketMod를 대체하지 않고 나란히 돌아가며, 통합 기능을 통해 기존 Rocket 플러그인을 함께 쓸 수 있습니다. 방어 측면에서는 두 가지를 뜻합니다.
첫째, 모든 플러그인은 메인 프로세스 안의 공격 표면입니다. 채팅 메시지마다 또는 게임 이벤트마다 데이터베이스 조회를 일으키는 플러그인은 스스로 만든 서비스 거부입니다. 이벤트를 반복해서 일으키는 플레이어 한 명이 대역폭을 전혀 쓰지 않고도 서버를 멈춰 세웁니다. 플러그인 목록을 짧게 유지하고, 소스가 공개된 플러그인을 우선하고, 확장을 추가할 때마다 서버의 프레임 속도를 측정하세요.
둘째, Unturned에는 자체 RCON 포트가 없으므로 모든 원격 제어는 플러그인에서 나옵니다. 설치한 뒤에 ss -lntp로 어떤 TCP 포트가 열렸는지 확인하고 본인 주소로 제한하세요. 비밀번호가 약한 채로 열려 있는 원격 제어 포트는 DDoS 문제가 아니라 서버를 빼앗기는 문제입니다.
8. Workshop 콘텐츠와 접속 과정
Workshop 콘텐츠는 접속을 무겁게 만들고, 그것이 공격받기 쉬운 정도에 곧바로 영향을 줍니다. 이는 같은 Server 폴더의 WorkshopDownloadConfig.json으로 조정합니다.
{
"File_IDs": [],
"Ignore_Children_File_IDs": [],
"Query_Cache_Max_Age_Seconds": 600,
"Max_Query_Retries": 2,
"Use_Cached_Downloads": true,
"Should_Monitor_Updates": true,
"Shutdown_Update_Detected_Timer": 600
}
File_IDs에는 맵과 모드의 Workshop 식별자가 들어갑니다. 서버는 시작할 때 이것을 의존 항목까지 함께 내려받고, 플레이어는 접속할 때 자동으로 따라 내려받습니다. 결과 세 가지를 알아 두셔야 합니다. 첫째, 모드 목록이 크면 접속이 오래 걸리고, 공격이 끝난 뒤에는 모든 플레이어가 동시에 돌아오면서 서버에 두 번째 부담을 줍니다. 둘째, Should_Monitor_Updates는 Workshop 파일이 갱신되는 즉시 서버를 멈춥니다. 기본값인 Shutdown_Update_Detected_Timer 600초가 지나면 재시작이 일어나고, 운영자들은 공격 중에 이를 공격의 성과로 오해하는 일이 잦습니다. 셋째, 모든 모드는 여러분의 서버에서 돌아가는 남의 코드입니다.
실무적으로는 이렇습니다. 목록을 가능한 한 짧게 유지하고, 예상하지 못한 재시작이 있을 때마다 서버 로그에서 Workshop 갱신 관련 메시지부터 확인하고, 갱신을 직접 일정에 넣어 관리할 때만 Should_Monitor_Updates를 끄세요.
9. 서버 목록, 서버 코드, Fake IP 기능
서버가 공개 목록에 올라 있는 동안에는 IP 주소를 비밀로 유지할 수 없습니다. 한 번이라도 접속한 플레이어는 모두 주소를 알고, 제3자 목록은 어차피 주소를 공개합니다. 그래도 습관 두 가지는 도움이 됩니다. 원시 주소를 어디에도 직접 공개하지 말고, 플레이어가 호스트 이름으로 접속하게 해서 주소가 바뀌어도 모든 안내가 깨지지 않게 하세요. 전형적인 사례는 옛 주소를 가리키는 잊힌 A 레코드이며, 이것이 어떤 변경도 무의미하게 만듭니다.
인터넷에서 운영하려면 어차피 애플리케이션 식별자 304930에 대한 Steam 서버 관리 페이지의 Game Server Login Token(GSLT)이 필요합니다. 이것은 서버의 서버 코드가 시작할 때마다 새로 만들어지는 대신 재시작을 넘어 그대로 유지되게 하는 역할도 합니다.
Unturned에는 Fake IP 기능도 있습니다. Config.json에 "Use_FakeIP": true로 켜고, 콘솔 명령 CopyFakeIP가 공개할 주소를 알려 줍니다. 그다음부터 트래픽은 Steam Datagram Relay 중계망으로 흐르고, 발급되는 주소는 169.254.0.0부터 169.254.255.255까지의 구간에 있으며, 서버의 실제 주소는 플레이어에게 더 이상 표시되지 않습니다. Valve는 이 트래픽을 인증되고 암호화되며 속도가 제한된다고 설명합니다.
대가는 크고, 함께 말해 주는 경우는 드뭅니다. 주소와 포트가 재시작할 때마다 바뀌고, 도메인 이름은 자체 스크립트 없이는 그쪽으로 향하게 할 수 없으며, Steam의 “즐겨찾기”와 “최근 기록” 목록은 이와 함께 동작하지 않고 북마크 기능만 동작합니다. 무엇보다 이 기능은 게임 경로만 지킵니다. 서버는 실제 주소를 그대로 가지고 있고, SSH, 웹 패널, 데이터베이스, 홈페이지는 그 주소로 계속 접근할 수 있습니다. 오래된 DNS 항목, 상태 페이지, 이전 접속에서 주소를 아는 사람은 여전히 서버를 직접 공격합니다. 따라서 Fake IP 기능은 서버 앞단 네트워크의 필터링을 대체하지 않고, 여러분의 주소를 아는 사람의 수를 줄여 줄 뿐입니다.
10. 공격 중에 추측하지 않도록 로그 기록하기
가장 중요하면서 거의 아무도 미리 하지 않는 단계가 있습니다. 모든 것이 정상으로 돌아가는 동안에 기준값을 만들어 두는 것입니다. 평상시 값이 없으면 사건이 끝난 뒤에 초당 40,000 패킷이 많았던 것인지 그냥 금요일 저녁이었던 것인지 말할 수 없습니다. apt-get install -y vnstat sysstat으로 측정이 상시 돌아갑니다. 사건이 진행되는 동안에는 네 개의 명령으로 충분합니다.
sar -n DEV 1 10
ip -s link show eth0
dmesg -T | tail -50
tcpdump -ni eth0 udp portrange 27015-27016 -c 200 -q
tcpdump에는 한 가지 원칙이 있습니다. 항상 -c로 개수를 제한하세요. 과부하 상태에서의 캡처는 이미 과부하인 서버에 부담을 더 얹습니다. 측정값을 해석하고 공격과 소프트웨어 오류를 구별하는 방법은 서버에서 DDoS 공격 알아내기에 있습니다.
이 조치들이 한계에 이르는 지점
지금까지의 모든 조치는 여러분의 서버, 즉 회선의 끝에서 동작합니다. 방화벽 규칙은 이미 케이블을 지나온 패킷을 두고 판단합니다. 그 패킷을 폐기할 수는 있지만, 보내지 않은 것으로 만들 수는 없습니다.
한번 계산해 보겠습니다. 일반적인 게임 서버는 1 Gbit/s 회선에 물려 있고, 이는 초당 125 메가바이트이며, 누군가 그보다 많이 보내는 순간 회선은 꽉 찹니다. 평상시 운영은 그보다 훨씬 아래에 머무릅니다. 플레이어 24명과 기본값으로 허용되는 플레이어당 초당 50 패킷이면 초당 약 1,200 패킷이 들어옵니다. booter 서비스는 아무 준비 없이도 그 몇 배를 만들어 냅니다.
두 번째 수치는 패킷 전송률이고, 거의 항상 대역폭보다 먼저 터집니다. 64 바이트짜리 작은 패킷이라면 1 Gbit/s 회선에 초당 약 149만 개가 들어갑니다. 일반적인 서버 커널은 CPU와 네트워크 카드에 따라 그중 수십만 개를 처리한 뒤 폐기를 시작합니다. 따라서 회선을 3분의 1도 채우지 못하는 공격도 폐기에 연산 시간이 들어가는 탓에 서버를 멈춰 세울 수 있습니다. 운영자는 이것을 “사용률은 전혀 높지 않았는데 그래도 전부 죽었다”로 경험합니다.
실제로 어떤 규모가 나오는지 가늠해 보면 이렇습니다. KernelHost 서버에서는 음성 서버를 향한 초당 4,150만 패킷과 함께 473.4 Gbit/s를 넘는 공격, 그리고 게임 서버를 향한 112.2 Gbit/s를 넘는 UDP 플러드가 걸러졌습니다. 여기에 대응하는 로컬 설정은 없습니다. 볼류메트릭 공격은 서버 앞단 네트워크에서 끝나야 합니다.
KernelHost가 이에 맞서 제공하는 것
모든 서버에 포함된 상시 방어
KernelHost의 DDoS 방어는 두 단계로 구성되어 있고 상시 동작합니다. 여러분이 무엇을 켜거나 주문하거나 설정할 필요가 없습니다.
- 1단계: 글로벌 스크러빙 네트워크의 17 Tbps 방어 용량. 볼류메트릭 공격은 발생지에 가까운 곳에서 정화되어 데이터센터에 닿기 전에 걸러집니다.
- 2단계: 프랑크푸르트암마인의 3.2 Tbps Arbor 실시간 필터링. 서버 바로 앞에서 프로토콜별 패턴을 찾아내 패킷 하나하나를 폐기합니다.
두 가지 특성이 결정적입니다. 이 방어는 상시 동작하므로 공격에 반응해서 비로소 시작될 필요가 없습니다. 그래서 초반에 서버가 사라지는 몇 분이 존재하지 않습니다. 그리고 null-routing을 쓰지 않습니다. 여러분의 IP 주소는 네트워크에 그대로 남고, 폐기되는 것은 악성 패킷뿐입니다. IP 주소를 네트워크에서 빼 버리면 여러분에게는 공격이 성공한 것과 같은 결과가 됩니다. 위치는 프랑크푸르트암마인입니다. 어떤 게임과 프로토콜이 포함되는지는 실시간 게임 서버 DDoS 방어에 정리되어 있습니다.
계속 공격받는 프로젝트를 위한 Advanced DDoS Protection
어떤 프로젝트는 어쩌다 한두 번이 아니라, 표적이 되어 몇 주에 걸쳐 공격받습니다. 이런 경우를 위해 Advanced DDoS Protection이 월 50.00 EUR부터, PrePaid 방식으로, 최소 이용 기간과 설치비 없이 제공됩니다. 차이는 용량이 더 커지는 데 있지 않고 통제권에 있습니다.
- 전용 방어 IP: 프랑크푸르트 코어에서 발급되며, 서버는 자체 네트워크에서 이 IP로 전환됩니다. 여러분 쪽에서 손볼 것은 없습니다.
- 포트와 프로토콜별로 직접 관리하는 방어 규칙: 고객 포털에서 27015 UDP(조회)에 무엇을 허용할지와 27016 UDP(게임 트래픽)에 무엇을 허용할지를 티켓을 쓰지 않고 따로 설정합니다.
- 변경은 실시간으로 반영: 공격이 진행되는 중에도 값을 조정할 수 있습니다. 예를 들어 조회는 더 좁게 잡고 게임 트래픽은 그대로 둘 수 있습니다.
- 게임에 맞춘 방어 프로필: 개조된 애플리케이션과 자체 애플리케이션도 임의의 TCP 또는 UDP 포트에서 같은 방식으로 다루므로, 자체 포트를 쓰는 플러그인도 포함됩니다.
두 단계 비교
| 항목 | 포함된 DDoS 상시 방어 | Advanced DDoS Protection |
|---|---|---|
| 요금 | 모든 서버 상품에 추가 요금 없이 포함 | 월 50.00 EUR부터, PrePaid |
| 필터링 용량 | 17 Tbps 글로벌 스크러빙과 프랑크푸르트암마인의 3.2 Tbps Arbor 실시간 필터링 | 동일한 2단계 필터링 |
| IP 주소 | 서버의 IP 주소 | 추가로 받는 전용 방어 IP |
| 규칙 세트 | 자동 프로필, 설정 불필요 | 고객 포털에서 포트와 프로토콜별 자체 규칙 |
| 변경 | 자동으로 함께 적용 | 실시간 반영, 공격 중에도 가능 |
| 게임 프로필 | Unturned를 포함한 주요 게임에 최적화된 프로필 | 게임에 맞춘 프로필, 개조된 애플리케이션도 가능 |
| null-routing | 없음 | 없음 |
| 이용 기간 | 서버 상품에 연동 | PrePaid, 최소 이용 기간 없음, 해지 통보 기간 없음, 설치비 없음 |
대부분의 Unturned 프로젝트에는 깔끔한 서버 설정과 포함된 상시 방어면 충분합니다. Advanced DDoS Protection은 누군가 이 일을 개인적으로 받아들였을 때의 답입니다.
자주 나오는 실수와 해결 방법
“제가 본 안내서에는 27015부터 27017까지 열라고 되어 있습니다”: 그 안내서는 2021년 11월보다 오래되었습니다. 3.21.30.0 버전부터는 Steam 쿼리가 게임 포트에 2를 더한 자리에 없으므로 Unturned 서버에 포트 두 개만 있으면 됩니다. 27017에서 두 번째 인스턴스가 돌아가고 있지 않다면 닫으세요.
“서버는 돌아가는데 어느 서버 목록에도 보이지 않습니다”: 쿼리 플러드 또는 27015 UDP에 너무 좁게 잡은 자체 규칙의 전형적인 모습입니다. iptables -L INPUT -n -v로 본인 규칙의 매칭 카운터가 올라가는지 확인하세요. 카운터가 크게 올라가면 지금 여러분이 자기 목록 등록을 걸러 내고 있는 것입니다. 27015를 완전히 차단하는 일은 절대 하지 마세요.
“플레이어 전원이 동시에 타임아웃으로 튕깁니다”: 먼저 연결 추적이 넘쳤는지 확인하세요(dmesg -T | grep -i conntrack). 테이블이 가득 차면 커널은 구별하지 않고 폐기합니다. Timeout_Game_Seconds는 기본값이 30초입니다. 그 안에 돌아오는 사람은 자리를 유지합니다.
“서버가 운영 중에 갑자기 재시작됩니다”: 이것이 공격인 경우는 드뭅니다. 로그에서 Workshop 갱신이 감지되었다는 메시지를 확인하세요. Should_Monitor_Updates는 기본 설정인 600초가 지나면 서버를 내립니다.
“IP 주소를 바꿨는데 두 시간 뒤에 다시 오프라인이 되었습니다”: 공격자는 새 주소를 옛 주소와 같은 출처에서 얻었습니다. 대개 서버 목록, Discord 봇, 또는 오래된 DNS 항목입니다. 주소 변경은 시간을 벌어 주지만 해결책은 아닙니다.
“Fake IP 기능을 켰는데도 공격을 받습니다”: 이 기능은 새 플레이어에게서 주소를 숨기지만 서버에서 주소를 빼앗지는 않습니다. 오래된 목록 등록, 상태 페이지, 이전 접속에서 주소를 아는 사람은 여러분의 서버에 계속 직접 닿고, 그 위의 SSH와 모든 웹 패널에도 닿습니다.
“기존 업체가 제 IP 주소를 차단했습니다”: 그것이 null-routing입니다. 업체는 그렇게 자기 네트워크를 지키지만, 여러분에게 남는 결과는 공격이 성공한 것과 똑같고, 보통 그 뒤로 몇 시간 더 이어집니다. 확실하지 않으면 필터링을 하는지 null-routing을 하는지 물어보세요. 그 답이 어떤 하드웨어 사양보다 여러분의 가용성을 더 크게 좌우합니다.
“tcpdump에 이상한 것이 보이지 않습니다”: 트래픽이 이미 앞단 네트워크에서 걸러지고 있으면 서버에는 아무것도 도착하지 않는 것이 당연합니다. 필터링이 작동하고 있을 때의 정상적인 모습입니다. 반대로 회선이 포화되면 측정에 쓰려던 SSH 세션조차 닿지 않을 수 있습니다. 그럴 때는 게스트 시스템의 네트워크와 무관하게 동작하는 고객 포털의 VNC 콘솔을 이용하세요.
핵심 요약
- Unturned 서버에는 열려 있는 UDP 포트가 정확히 두 개 필요합니다.
Commands.dat에 설정한Port(기본값 27015)와 그 값에 1을 더한 값(27016)입니다. 게임 자체에는 TCP가 필요하지 않습니다. - 포트 27017은 2021년 11월 21일에 나온 3.21.30.0 버전부터 불필요합니다. Steam 쿼리가 더 이상 게임 포트에 2를 더한 자리에 없기 때문입니다. 아직 열어 두고 있다면 오래된 안내서를 따르고 있는 것입니다.
- Unturned에는 내장 RCON 포트가 없습니다. 모든 원격 제어는 플러그인에서 나오고, 자체 TCP 포트를 함께 가져오며, 여러분이 직접 제한해야 합니다.
- 쿼리 포트 27015가 가장 취약한 지점입니다. 쿼리 플러드는 플레이어를 한 명도 건드리지 않고 서버를 서버 목록에서 보이지 않게 만들며, Steam 프로토콜은 US-CERT TA14-017A 기준으로 증폭 계수가 5.5입니다.
Config.json의 한도(Max_Packets_Per_Second50.0, 40초당Rate_Limit_Kick_Threshold10)는 실제로 접속하는 클라이언트에만 작용하고 위조된 출발지 주소에는 작용하지 않습니다.- 1 Gbit/s 회선은 초당 125 메가바이트에서 꽉 차고, 64 바이트짜리 패킷이라면 이미 초당 약 149만 개에서 꽉 찹니다. 플레이어 24명의 평상시 운영은 초당 약 1,200 패킷입니다. 그 위의 모든 것은 여러분의 방화벽이 아니라 서버 앞단 네트워크가 결정합니다.
- KernelHost에서는 2단계 상시 방어가 모든 서버 상품에 추가 요금 없이 포함되어 서버 제공 시점부터 동작하며, null-routing을 쓰지 않습니다. 필터 규칙을 직접 조정하려면 월 50.00 EUR부터의 Advanced DDoS Protection을 더하면 됩니다.
프로젝트가 이미 KernelHost에 있다면 필터링은 여러분이 아무것도 하지 않아도 동작하고 있습니다. 그래도 이상한 점이 보이면 지원 티켓을 열어 주세요. 해당 IP 주소의 필터 규칙을 다시 맞춰 드립니다. 공격이 진행 중일 때는 WhatsApp 긴급 채팅 +43 650 8209883으로도 연락하실 수 있습니다.
자주 묻는 질문
Unturned 서버에 열어 두어야 하는 포트는 무엇인가요?
Unturned에서 포트 27017을 열어야 하나요?
Unturned 서버는 돌아가는데 어느 서버 목록에도 보이지 않습니다. 공격인가요?
Unturned에는 내장 RCON 포트가 있나요?
Unturned의 Fake IP 기능이 DDoS 공격을 막아 주나요?
iptables나 UFW로 DDoS 공격에 맞설 수 있나요?
어느 공격 규모부터 Unturned 서버가 혼자 버티지 못하나요?
Unturned 서버는 왜 그렇게 자주 공격받나요?
RocketMod나 OpenMod 플러그인이 DDoS 공격에 도움이 되나요?
KernelHost의 서버는 공격 중에 오프라인이 되나요?
KernelHost의 DDoS 방어는 추가 요금이 드나요?
Unturned 서버에 Advanced DDoS Protection이 추가로 필요한 때는 언제인가요?
2026 KernelHost GmbH. 모든 권리를 보유합니다. 본 가이드는 저작권법의 보호를 받습니다. 전체든 일부든, 또는 수정된 형태이든 저희의 서면 동의 없이 다른 웹사이트에 게시할 수 없습니다. 출처를 밝히고 링크를 덧붙인 인용은 언제든지 환영합니다.

