외부 장치에서 접근되는 WSL 서버 구성하기

WSL2로 bare metal 서버처럼 SSH, SAMBA, HTTP, NFS, TFTP 서버를 구성하여 외부 장치에서도 접근할 수 있는 방법을 정리한다.

WSL로 개발시 장점

임베디드 디바이스 개발 시에는 별도의 개발 서버를 구축하여 사용하는 경우가 많은데, 요즘에는 워낙 데스크톱이나 노트북 모두 성능이 좋고 코어도 많아서, 별도의 개발 서버를 이용하지 않고 자체 PC를 이용하는 경우도 많다.
이 경우에 보통은 VirtualBox와 같은 Virtual Machine을 많이 이용하지만, 이는 오버헤드가 크고 속도가 느리다는 치명적인 단점이 있다. 반면에 WSL은 Hyper-V 기반의 경량 VM이라서 굉장히 가볍고 속도가 빠르다는 장점이 있다.

나의 경우에 회사 노트북이 (100만 원 중반대로 비싼 노트북이 아닌데도 불구하고) Ryzen 6850U(8코어 16스레드), 메모리가 32GiB, SSD가 1TB인데, 기존에 사용 중이던 웬만한 독립 서버보다 WSL 배포판에서 소스를 빌드하는 시간이 더 짧게 걸린다.
또 현재 회사 내부망 네트워크를 이용하는 경우에는 내 PC와 개발 서버 간의 통신 속도는 회사 네트워크 망의 속도 제약을 받는 것에 비하여, WSL을 사용하는 경우에는 내 PC와 WSL 배포판의 네트워크 속도는 아주 빨라서 (나의 경우 iperf3 툴로 확인해 보면 약 10Gbps로 나옴), VS Code와 같은 소스 편집기에서 소스 브라우징은 물론이고 대용량 파일 복사 등 시에 비교가 되지 않을 정도로 WSL을 사용하는 경우가 속도가 더 빠르다.

거기다 내 마음대로 WSL 배포판 서버를 다룰 수 있는 것은 덤이다. (나에게 필요한 툴, 서비스, Docker 등을 고민 없이 바로 설치할 수 있다)

WSL 네트워크 문제

일반적인 임베디드 개발 시에는 보통 아래와 같은 형태로 네트워크를 구성하여 개발한다.

위에서 개발 서버는 bare metal에 Linux를 설치하여 운용하고 별도의 고정 IP를 할당받고, 내 PC는 개발 서버에 SSH, SAMBA 등으로 접속하여 소스 수정하고 빌드 한 후에, target 디바이스에서는 NFS로 개발 서버에 연결하여 서버에 빌드 된 파일을 바로 실행하여 테스트한다.

그런데 WSL 배포판으로 서버를 구성하는 경우에는 네트워크 할당을 NAT로 172 대역을 할당하므로, 내 PC에서는 쉽게 access가 되지만, 위와 같은 target 디바이스에서는 접근이 되지 않아서, NFS 등을 이용하기가 쉽지 않다.
그래서 이번 글에서는 WSL 배포판을 설치한 이후에, 어떻게 bare metal 서버처럼 구성하여 개발 서버의 역할을 모두 내 WSL 배포판 서버에서 제공할 수 있는지를 설명한다.

WSL 네트워크 구성

이 글에서는 위 기본 개발 환경 상태에서, WSL을 설치하여 아래와 같이 네트워크 구성을 한 경우를 예로 든다.

위 구성에서 목표는 target 디바이스에서 내 WSL 배포판이나 외부 개발 서버에 접속이 되는 것이다.
즉, 위와 같이 WSL 배포판 서버의 IP를 NAT 대신에 bridge 모드로 받아서 고정 IP로 사용하면 (여기서는 192.168.0.100), target 디바이스에서 WSL 배포판 서버나 개발 서버에 접근할 수 있다.

참고로 이 글에서는 Windows 11에서 WSL2를 설치하여 사용하는 방법을 설명한다. Windows 11의 경우에는 .wslconfig 파일에서 vmSwitch 항목으로 가상 스위치를 선택할 수 있어서 부팅 시마다 별다른 조작 없이도 잘 되지만, Windows 10은 이를 지원하지 않으므로 부팅 시마다 일부 수작업이 필요하다.

WSL 설치

이 글에서는 Windows에서 WSL 설치와 WSL 배포판 설치 등은 다루지 않는다. 필요하면 이 과정은 WSL2 소개 등의 페이지를 참조하기 바란다.
WSL을 설치한 이후에는 아래와 같이 최신 버전으로 업데이트한다.

C:\>wsl --update

WSL 배포판 설치

  1. WSL 배포판을 설치한다. (본 글에서는 예로 Ubuntu 18.04 이상을 사용하였음)
    설치한 배포판을 실행해 보면 네트워크를 NAT로 할당받아서 (172 대역으로 IP를 할당받았음을 확인할 수 있음) 동작함을 확인할 수 있다. 따라서 Windows 호스트에서는 WSL로 접근이 잘 되지만, target 디바이스에서는 WSL로 접근이 되지 않는다. (예를 들어 target 디바이스에서 ping으로 확인해 보면 ping이 되질 않음)
  2. 참고로 작업 시작 전에 ipconfig 명령을 실행해보니 아래와 같았다.
    C:\>ipconfig
    이더넷 어댑터 이더넷:      
       연결별 DNS 접미사. . . . :
       링크-로컬 IPv6 주소 . . . . : fe80::b834:8433:8315:c0c9%23
       IPv4 주소 . . . . . . . . . : 192.168.0.2
       서브넷 마스크 . . . . . . . : 255.255.255.0
       기본 게이트웨이 . . . . . . : 192.168.0.1
    이더넷 어댑터 vEthernet (Default Switch):      
       연결별 DNS 접미사. . . . :
       링크-로컬 IPv6 주소 . . . . : fe80::c966:e3f8:a321:44cf%38
       IPv4 주소 . . . . . . . . . : 172.22.240.1
       서브넷 마스크 . . . . . . . : 255.255.240.0
       기본 게이트웨이 . . . . . . :
    이더넷 어댑터 vEthernet (WSL):
       연결별 DNS 접미사. . . . :
       링크-로컬 IPv6 주소 . . . . : fe80::eefa:9757:1b50:47f4%62
       IPv4 주소 . . . . . . . . . : 172.31.128.1
       서브넷 마스크 . . . . . . . : 255.255.240.0
       기본 게이트웨이 . . . . . . :
    

가상 스위치 설정

  1. “Windows 기능 켜기/끄기”를 실행한 후 (또는 콘솔에서 OptionalFeatures.exe 실행), “Hyper-V” 항목의 체크를 켠다.
  2. 설치가 완료되면 Hyper-V 관리자를 관리자 권한으로 실행시킨 후, 해당 가상 컴퓨터에서 가상 스위치 관리자 항목을 클릭한다. 여기서 외부 유형을 선택한 후, “가상 스위치 만들기” 버튼을 누른다. 이름을 예를 들어 WSL_external로 세팅하고, 외부 네트워크를 원하는 인터페이스로 선택한 후, 확인 버튼을 누르면 생성된다. (나의 경우는 시스템에 이더넷 장치로 “Realtek PCIe GbE Family Controller”가 설치되어 있으므로 이것을 선택함, 아래 캡처 참조)
  3. 참고로 위와 같이 GUI를 이용하는 대신에, 관리자 권한의 PowerShell에서 아래와 같이 작업할 수도 있다.
    먼저 아래와 같이 시스템에 있는 네트워크 어댑터 이름을 얻는다. (이 글에서는 이더넷 장치를 이용할 것임)
    PS C:\>Get-NetAdapter
    Name                      InterfaceDescription                    ifIndex Status       MacAddress             LinkSpeed
    ----                      --------------------                    ------- ------       ----------             ---------
    이더넷                    Realtek PCIe GbE Family Controller           23 Up           9C-2D-CD-48-E8-22       100 Mbps
    ...
    

    아래 예와 같이 WSL_external 이름의 가상 스위치를 생성한다. (위에서 얻은 “Realtek PCIe GbE Family Controller” 사용)

    PS C:\>New-VMSwitch -Name "WSL_external" -InterfaceDescription "Realtek PCIe GbE Family Controller"
    Name         SwitchType NetAdapterInterfaceDescription
    ----         ---------- ------------------------------
    WSL_external External   Realtek PCIe GbE Family Controller
    

    이제 아래와 같이 가상 스위치를 확인해 보면, 정상적으로 생성된 것을 확인할 수 있다.

    PS C:\>Get-VMSwitch
    Name           SwitchType NetAdapterInterfaceDescription
    ----           ---------- ------------------------------
    Default Switch Internal
    WSL_external   External   Realtek PCIe GbE Family Controller
    WSL            Internal
    
  4. 참고로 이제 ipconfig로 확인해 보면 기존 이더넷 인터페이스는 보이지 않고, 아래 예와 같이 WSL_external 인터페이스가 보인다.
    C:\>ipconfig
    이더넷 어댑터 vEthernet (WSL_external):      
       연결별 DNS 접미사. . . . :
       링크-로컬 IPv6 주소 . . . . : fe80::998f:637:e048:1725%32
       IPv4 주소 . . . . . . . . . : 192.168.0.2
       서브넷 마스크 . . . . . . . : 255.255.255.0
       기본 게이트웨이 . . . . . . : 192.168.0.1
    이더넷 어댑터 vEthernet (Default Switch):      
      연결별 DNS 접미사. . . . :
      링크-로컬 IPv6 주소 . . . . : fe80::c966:e3f8:a321:44cf%38
      IPv4 주소 . . . . . . . . . : 172.22.240.1
      서브넷 마스크 . . . . . . . : 255.255.240.0
      기본 게이트웨이 . . . . . . :
    이더넷 어댑터 vEthernet (WSL):
       연결별 DNS 접미사. . . . :
       링크-로컬 IPv6 주소 . . . . : fe80::eefa:9757:1b50:47f4%62
       IPv4 주소 . . . . . . . . . : 172.31.128.1
       서브넷 마스크 . . . . . . . : 255.255.240.0
       기본 게이트웨이 . . . . . . :
    

WSL 설정

  1. Windows의 사용자 홈 (%UserProfile%) 디렉토리에서 .wslconfig 파일을 아래와 같이 작성한다.
    [wsl2]
    networkingMode = bridged
    vmSwitch = WSL_external
    dhcp = false
    

    위 설정은 WSL 네트워크를 가상 스위치 WSL_external을 사용하여 bridge 모드를 사용하게 하고, DHCP는 사용하지 않게 한다. (⛔ 현재 Windows 10은 vmSwitch 항목을 지원하지 않음)

  2. 설치된 WSL 배포판에 로그인한 후, 아래 예와 같이 네트워킹 모드를 확인할 수 있다.
    $ wslinfo --networking-mode
    bridged
    

    그런데 ifconfig 명령을 실행해 보면 아직은 eth0가 보이지 않는다.
    이제 WSL에서 DHCP로 동적 IP를 할당받는 대신에 독립적인 서버에 고정 주소를 사용하는 것처럼, 지정한 고정 IP로 할당하기 위하여 /usr/lib/systemd/network/wsl_external.network 파일을 아래 예와 같이 작성한다. (여기서는 예로, 배포판의 IP를 192.168.0.100으로 고정 할당함)

    [Match]
    Name = eth0
    
    [Network]
    DHCP = false
    Address = 192.168.0.100/24
    Gateway = 192.168.0.1
    
  3. 또 배포판에서 /etc/wsl.conf 파일을 아래와 같이 작성한다. 즉, NFS, SAMBA 등의 서비스를 운용하기 위하여 systemd 항목을 enable 시켰고, 수동으로 IP를 할당했으므로 DNS도 수동으로 세팅할 수 있도록 generateResolvConf 항목을 false로 세팅한다. (결과로 /etc/resolv.conf 파일이 overwrite 되지 않게 됨)
    [boot]
    systemd = true
    
    [network]
    generateResolvConf = false
    

    이후 WSL 배포판을 restart 시킨 후, 다시 로그인해 보면, 네트워크가 원하는 대로 구성되었음을 확인할 수 있다.

  4. 추가로 DNS를 설정하기 위하여 /etc/resolv.conf 파일을 아래 예와 같이 작성한다. (위의 네트워크 구성도에서 사내망 DNS 주소를 10.1.1.25로 가정하였으므로)
    nameserver 10.1.1.25
    

    다시 WSL 배포판을 restart 시키면 고정 IP 할당 작업이 완료된다. 물론 Windows를 재기동하거나 WSL 배포판을 재기동해도 동일한 IP로 잘 할당된다.

WSL 배포판 IP 테스트

WSL 배포판에 로그인한 후, eth0를 확인해 보면 아래와 같이 나온다.

$ ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.0.100  netmask 255.255.255.0  broadcast 192.168.0.255
        inet6 fe80::5ebb:f6ff:fe9e:eefa  prefixlen 64  scopeid 0x20<link>
        ether 5c:bb:f6:9e:ee:fa  txqueuelen 1000  (Ethernet)
        RX packets 196  bytes 242986 (242.9 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 151  bytes 11785 (11.7 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

DNS 설정 확인은 아래 예와 같이 할 수 있다.

$ resolvectl status | grep "DNS Servers"
         DNS Servers: 10.1.1.25

위의 결과를 보면 IP와 DNS 할당이 모두 기대대로 되었음을 확인할 수 있다. 이제 아래 경우를 ping 테스트해 보면 모두 정상 동작한다. 😊

  • Windows에서 WSL 배포판으로 (192.168.0.100) ping 테스트
  • Target 디바이스에서 WSL 배포판으로 (192.168.0.100) ping 테스트
  • Target 디바이스에서 개발 서버로 (172.16.7.YYY) ping 테스트

이로써 WSL 배포판에 고정 IP와 DNS 적용이 완료되었다. 또한 Windows를 재부팅해도 별도의 수작업 없이도 마찬가지로 잘 된다.
이제부터는 WSL 배포판에서 마음껏 원하는 서비스를 구축하고, 이를 Windows PC는 물론이고 target 디바이스에서도 액세스할 수 있다.

또, 내 PC와 WSL 배포판의 네트워크 속도를 iperf3 툴로 테스트해 보면, 내 환경의 경우 아래와 같이 약 10Gbps의 속도가 나오고, WSL 배포판에서 GUI 프로그램을 설치해서 실행해 보면 마치 Windows에서 실행시키는 것처럼 빠르게 동작하는 것을 볼 수 있다.

WSL 배포판에 서비스 구축 예

  • SSH

    사실 WSL 배포판은 bare metal 서버처럼 SSH가 필수가 아니고 사실상 굳이 설치할 필요가 없지만, 설치 시에 약간의 설정이 필요하기도 하여, 이 글에서는 서비스 설치의 예로 든다.
    WSL 배포판에서 다음과 같이 OpenSSH 서버를 재설치한다.

    $ sudo apt purge openssh-server
    $ sudo apt install openssh-server
    

    이후 /etc/ssh/sshd_config 파일에서 아래 내용을 주석 해제한다.

    PermitRootLogin prohibit-password
    

    이제 아래와 같이 SSH 서비스를 실행시키면 된다.

    $ sudo service ssh --full-restart
    

    이제 Windows에서 아래 예와 같이 SSH로 WSL 배포판에 로그인할 수 있다.

    C:\>ssh 172.16.0.100 -l {userid}
    

    추가로 SSH 설치/접속/설정 정리 내용을 참조하여 SSH 환경을 셋업하면, 매번 로그인 할 때마다 암호를 입력하지 않아도 된다.

  • SAMBA

    WSL 배포판에서 아래와 같이 SAMBA 서비스를 설치한다.

    $ sudo apt install samba
    

    이후 /etc/samba/smb.conf 파일에 아래 예와 같이 사용자를 추가한다. (아래에서 userid 부분을 본인의 user ID로 변경 필요)

    [userid]
        comment = userid's samba
        path = /home/userid
        writeable = yes
        browseable = yes
        valid users = userid
        create mask = 644
        directory mask = 755
    

    아래와 같이 사용자를 추가하고 삼바 접속 암호를 설정한다.

    $ sudo smbpasswd -a $USER
    

    이후 아래와 같이 삼바 서버를 재시작한다.

    $ sudo service smbd restart
    

    이제 Windows에서 \\192.168.0.100\{userid} 주소로 삼바 연결이 된다.
    참고로 나는 사용 편의상 /etc/samba/smb.conf 파일의 [global] 섹션에서 아래 내용을 추가해서 사용한다.

    [global]
    wide links = yes
    unix extensions = no
    map archive = no
    store dos attributes = no
    
  • HTTP

    예로 Nginx 서버는 아래와 같이 설치한 후, 서비스를 실행시키면 된다.

    $ sudo apt install nginx
    $ sudo service nginx start
    

    이제 Windows에서 브라우저로 http://192.168.0.100/ 주소에 접속하면 Nginx welcome 화면이 나온다.
    참고로 테스트로 /var/www/html/ 경로에 test.txt 파일을 생성한 후에 Windows나 아래와 같이 target 디바이스에서 wget 툴로 받아보면 기대대로 잘 받아진다.

    $ wget http://192.168.0.100/test.txt
    
  • NFS

    NFS 서버 역시 어렵지 않게 구축할 수 있다. WSL 배포판에서 아래와 같이 NFS 서버 패키지를 설치한다.

    $ sudo apt install nfs-kernel-server
    

    NFS 디렉토리로 사용할 경로를 생성하고 (여기서는 /opt/nfs 사용), /etc/exports 파일에 아래 예와 같이 추가한다.

    /opt/nfs *(rw,root_squash,sync,no_subtree_check)
    

    아래와 같이 NFS 데몬을 실행시킨다.

    $ sudo service nfs-server restart
    

    이 WSL 배포판의 NFS 디렉토리는 target 디바이스에서 아래 예와 같이 마운트시킬 수 있다.

    $ sudo mount -o nolock 192.168.0.100:/opt/nfs/ /mnt/
    
  • TFTP

    TFTP 서버도 tftpd-hpa 패키지를 설치하면 간단히 구축할 수 있다.

    $ sudo apt install tftpd-hpa
    

    TFTP 설정 파일인 /etc/default/tftpd-hpa 파일을 확인해 보면 아래 예와 같다. (TFTP 디렉토리를 변경하려면 TFTP_DIRECTORY 옵션에서 바꾸면 됨)

    TFTP_USERNAME="tftp"
    TFTP_DIRECTORY="/srv/tftp"
    TFTP_ADDRESS=":69"
    TFTP_OPTIONS="--secure"
    

    참고로 만약에 파일의 업로드도 허용하려면 TFTP_OPTIONS 항목에서 --create 옵션을 추가하면 된다.
    이제 아래와 같이 TFTP 데몬을 재시작 시킨다.

    $ sudo service tftpd-hpa restart
    

    테스트로 /srv/tftp/test.bin 파일을 만든 후에, target 디바이스에서 busybox에 있는 tftp 명령을 이용하여 아래 예와 같이 GET 할 수 있다.

    $ tftp -r test.bin -g 192.168.0.100
    
  • Docker

    Docker도 systemd를 사용하는 경우에는 간단히 아래와 같이 설치할 수 있다.

    $ sudo apt install docker.io
    

    편의상 docker 명령시에 sudo 명령을 생략할 수 있도록 아래와 같이 docker 그룹에 추가한다.

    $ sudo usermod -aG docker $(whoami)
    

    이제 다시 로그인을 한 후에 아래 예와 같이 docker 명령을 실행해 보면 정상적으로 실행이 된다.

    $ docker images
    

WSL 배포판 실행 유지

그런데 현재 설계상 WSL 배포판의 로그인 shell을 종료하면 WSL이 약 15초 후에 자동으로 해당 배포판을 종료시키는 것 같다. 배포판의 로그인 shell을 종료시키더라도 배포판이 stop 되는 것을 막기 위해서는 여러 방법들이 있겠지만, 구글링을 통해서 내가 찾은 방법은 다음과 같다.

  1. 배포판에서 아래와 같이 keychain 패키지를 설치한다.
    $ sudo apt install keychain
    
  2. 이후 배포판에서 /etc/profile.d/wsl_keep_alive.sh 파일을 아래와 같이 작성한다. (파일 이름은 상관없음)
    #!/usr/bin/env sh
    eval $(keychain -q)
    
  3. 위와 같이 한 상태에서는 로그인을 한 이후에 로그인 shell을 종료하더라도 배포판이 stop 되지 않는다. 참고로 편의상 Windows 부팅 시에 자동으로 해당 배포판을 실행시키려면, 관리자 권한의 콘솔에서 아래 예와 같이 실행하여 작업 스케줄러에 등록하면 된다.
    C:\>schtasks /CREATE /TN "WSL start" /SC ONLOGON /TR "wsl -d 배포판이름 --cd ~"
    

참고로 기존에 systemd를 사용하지 않을 때에는 WSL 배포판 부팅 시에 서비스를 수동(또는 자동화)으로 실행시켜 주어야 하는데, systemd를 사용하면 (기존 bare metal 서버와 마찬가지로) 수동으로 기동 작업을 하지 않아도 된다. (WSL이 점점 bare metal Linux와 비슷해지고 있다. 👏)

외부에서 WSL의 SSH, 웹 접근

참고로 외부에서 WSL 배포판의 SSH나 웹 서버에 접근할 수 있게 하려면, 내 공유기에서 포트 포워딩 규칙을 추가해 주면 된다. 예를 들어 SSH 접속을 위해서는 TCP 포트 22, 웹 접속을 위해서는 TCP 포트 80을 WSL 배포판의 IP 주소로 포트 포워딩하면 된다.
이후 외부에서 WSL 배포판의 SSH나 웹 서버에 접속할 때는 내 공유기의 IP 주소로 접속하면 된다.

맺음말

WSL의 경우에 Windows 10과 11의 경우가 조금 다르고, WSL 자체도 계속 업데이트되면서 WSL 관련 설정 방법들이 조금씩 다른 관계로, 구글링해서 올바른 최신 자료를 찾기가 쉽지 않다. 이 글에서는 최근 WSL에서 지원되는 systemd를 이용하여 WSL 배포판을 마치 독립적인 서버처럼 구성하는 방법을 정리해 보았다.

카테고리:

업데이트: