원문 캡처 · frimin.fr
원문 캡처 · frimin.fr

OVH 전용 서버에서 FreeBSD 사용하기

2026-10-28

OVH 전용 서버에서 FreeBSD를 사용한다. 서버에서 잘 작동하는 설정을 하나씩 찾는 데 오랜 시간이 걸렸고, 이 글에 그 설정을 정리했다.

설치

OVH는 더 이상 설치 카탈로그에서 FreeBSD를 제공하지 않으므로 직접 설치해야 한다. 제어판의 KVM에 FreeBSD ISO를 가상 장치로 연결해 부팅한 뒤 설치 프로그램을 수동으로 실행했다. 루트 파일 시스템은 ZFS를 사용하며, NVMe 디스크 두 개에 미러링하고 GELI로 암호화했다.

GELI를 사용하면 부팅할 때마다 로더가 암호 문구를 물어보므로 콘솔이 필요하다.

SOL을 통한 콘솔 접속

KVM도 작동하지만 붙여넣기가 불안정하다. 웹 페이지에서 긴 암호 문구를 직접 입력하고 싶지도 않다.

OVH는 서버의 직렬 콘솔에 SOL(Serial over LAN)로 접속하는 기능도 제공한다. 웹이나 SSH로 접속할 수 있다. SSH로 접속하면 일반 터미널을 사용할 수 있어 암호 관리자로 암호 문구를 입력하기가 훨씬 쉽다.

현재 서버는 UEFI로 부팅하므로 따로 설정할 것이 없다. 펌웨어가 콘솔을 첫 번째 직렬 포트로 전송하고 FreeBSD 로더가 이를 자동으로 인식한다.

$ kenv | grep cons
boot_multicons="YES"
comconsole_pcidev=""
comconsole_port="1016"
comconsole_speed="115200"
console="efi"
hw.uart.console="io:1016,br:115200"

1016은 첫 번째 직렬 포트(COM1)의 주소인 0x3F8이다. 이후 커널은 두 콘솔을 모두 사용한다.

$ dmesg | grep -i console
uart0: console (115200,n,8,1)
Dual Console: Video Primary, Serial Secondary

이전 설정에서는 SOL이 두 번째 직렬 포트(COM2)에 연결돼 있어 /boot/loader.conf에 다음 줄을 추가해야 했다.

boot_multicons="YES"
boot_serial="YES"
comconsole_speed="115200"
comconsole_port="0x2F8"
console="comconsole,efi"

0x2F8은 시행착오를 거쳐 찾았다. 포트를 바꾸고 재부팅한 뒤 SOL 세션을 확인하면 된다. 서버에서 SOL 화면이 계속 비어 있다면 0x3F8을 시도한 다음 0x2F8도 시도해 볼 수 있다.

IPv4

서버에는 IPv4 주소 하나가 있으며, 게이트웨이는 같은 /24 대역의 .254 주소다. OVH는 DHCP를 제공하지만 부팅할 때 임대 주소를 기다리지 않도록 /etc/rc.conf에서 정적으로 설정했다.

ifconfig_ixl0="inet 141.94.75.198 netmask 255.255.255.0 broadcast 141.94.75.255"
defaultrouter="141.94.75.254"

IPv6

IPv6 설정이 가장 까다로웠다. 서버는 수년 동안 IPv4만 사용했고, IPv6 설정을 여러 차례 시도한 끝에야 안정적으로 작동하게 됐다.

OVH의 IPv6는 농담거리처럼 여겨질 정도다. 포럼에는 IPv6가 몇 시간 뒤 끊긴다는 사례나 시스템이 게이트웨이의 요청을 무시한다는 사례가 올라와 있다.

서버에 할당된 대역은 2001:41d0:303:ffc6::/64이고, 게이트웨이는 그 대역 밖에 있는 2001:41d0:303:ffff:ff:ff:ff:ff다. OVH 문서는 라우터 광고나 DHCPv6 없이 정적으로 설정하는 방법만 안내한다. 작동하게 만들기까지 세 가지 문제를 해결해야 했다.

게이트웨이가 직접 연결된 대역에 있지 않음

다음 설정은 작동하지 않는다.

ifconfig_ixl0_ipv6="inet6 2001:41d0:303:ffc6::1 prefixlen 64"
ipv6_defaultrouter="2001:41d0:303:ffff:ff:ff:ff:ff"

FreeBSD는 인터페이스의 접두사 안에 있는 이웃만 직접 연결된 대상으로 취급하므로 /64 대역 밖의 게이트웨이에 도달할 수 없다. 먼저 ixl0을 통해 게이트웨이로 가는 경로를 추가해야 한다.

ipv6_static_routes="gw6"
ipv6_route_gw6="-host 2001:41d0:303:ffff:ff:ff:ff:ff -iface ixl0"

몇 시간 뒤 IPv6 연결이 끊김

2024년에는 몇 시간 뒤 IPv6가 작동을 멈췄다. 게이트웨이의 이웃 캐시 항목이 만료된 뒤 다시 생성되지 않는다고 생각해 정적 NDP 항목을 추가했다.

ipv6_ndp_interfaces="ixl0"
ipv6_ndp_entries="2001:41d0:303:ffff:ff:ff:ff:ff <gateway MAC address>"

이 방법은 효과가 없었고, 2026년까지 IPv6를 꺼 두었다.

원인은 pf였다. 규칙 집합에 ICMPv6 상태를 추적하는 규칙이 있었다.

pass proto icmp6 keep state

이웃 탐색은 ICMPv6를 사용하므로 게이트웨이의 이웃 요청이 상태 항목을 만들었다. 이웃 캐시 항목이 만료됐을 때 오래된 상태 항목이 게이트웨이의 응답을 차단했고, IPv6 연결이 끊겼다.

이제 이웃 탐색과 라우터 탐색은 다른 규칙보다 먼저 상태를 추적하지 않고 통과시킨다.

pass quick inet6 proto icmp6 \
 icmp6-type { neighbrsol, neighbradv, routersol, routeradv } no state

연결 세 개 중 하나가 응답 없이 멈춤

이후 IPv6는 계속 연결됐지만 연결 세 개 중 하나꼴로 응답을 받지 못했다. FreeBSD는 버려진 패킷 수를 기록했다.

$ netstat -s -p icmp6 | grep 'bad neighbor solicitation'
 19569 bad neighbor solicitation messages

게이트웨이는 여러 OVH 라우터가 공유하는 가상 주소다. 이웃 캐시에는 게이트웨이와 함께 Cisco HSRP 가상 MAC 주소, 그리고 그 뒤에 있는 라우터 두 대가 표시된다.

$ ndp -an
Neighbor Linklayer Address Netif Expire S Flags
2001:41d0:303:ffff:ff:ff:ff:ff 00:05:73:a0:00:01 ixl0 23h59m55s S R
2001:41d0:303:ffff:ff:ff:ff:fe bc:4a:56:af:20:f7 ixl0 23h43m21s S R
2001:41d0:303:ffff:ff:ff:ff:fd 3c:13:cc:d6:96:37 ixl0 23h47m58s S R

라우터들은 서버로 트래픽을 전달하기 전에 각자 자신의 주소에서 서버 주소를 찾는 이웃 요청을 보낸다.

$ tcpdump -n -i ixl0 'icmp6 and ip6[40] == 135'
IP6 2001:41d0:303:ffff:ff:ff:ff:fe > 2001:41d0:303:ffc6::1: ICMP6,
 neighbor solicitation, who has 2001:41d0:303:ffc6::1, length 32

라우터 주소는 서버의 /64 대역 밖에 있다. 게이트웨이만 직접 연결된 대상으로 설정돼 있었기 때문에 FreeBSD는 이 요청을 이웃이 아닌 주소에서 온 것으로 보고 버렸다. 그 결과 이 라우터들을 통과하는 트래픽이 손실됐다.

해결 방법은 라우터의 전체 접두사를 직접 연결된 대역으로 설정하는 것이다.

ipv6_route_gw6="-net 2001:41d0:303:ffff::/64 -iface ixl0"

돌이켜 보면 주소를 통해 문제를 이해할 수 있다. 서버의 대역 2001:41d0:303:ffc6::/64와 라우터의 접두사 2001:41d0:303:ffff::/64는 모두 2001:41d0:303:ff00::/56에 속한다. OVH 라우터는 할당된 /64가 아니라 /56 대역에 있다. 대신 주소를 /56 접두사로 설정하는 사람들도 있다. 그러면 게이트웨이와 라우터가 한 번에 직접 연결된 대상으로 설정된다. 이 경우에는 OVH가 할당한 /64를 유지하고 경로를 추가하는 방식을 택했다.

최종 설정

/etc/rc.conf에는 다음을 설정한다.

ipv6_activate_all_interfaces="YES"
ifconfig_ixl0_ipv6="inet6 2001:41d0:303:ffc6::1 prefixlen 64"
ipv6_static_routes="gw6"
ipv6_route_gw6="-net 2001:41d0:303:ffff::/64 -iface ixl0"
ipv6_defaultrouter="2001:41d0:303:ffff:ff:ff:ff:ff"

/etc/pf.conf에서는 다른 ICMPv6 규칙보다 앞에 다음 규칙을 둔다.

pass quick inet6 proto icmp6 \
 icmp6-type { neighbrsol, neighbradv, routersol, routeradv } no state

이제 정적 NDP 항목은 필요하지 않다.

설정이 한 번 제대로 작동하고 나면 어려워 보이지 않지만, SOL과 IPv6를 제대로 설정하는 데 오랜 시간이 걸렸다. OVH 문서는 엉망이다. FreeBSD 예제가 없고, 여기서 겪은 문제들도 다루지 않는다.