원격 개발 환경

SSH 최적화, ProxyJump, 포트 포워딩, Mosh, sshfs, tmux, GNU Screen, VS Code Remote Development를 활용한 커널 원격 개발 환경 구축 및 원격 디버깅(Debugging) 가이드입니다.

개요

커널 개발은 고성능 머신이 필요하므로, 원격 서버에서 빌드하고 로컬에서 편집하는 패턴이 흔합니다. 특히 대규모 커널 트리의 make -j$(nproc) 빌드는 수십 분이 소요되기 때문에, 빌드 전용 서버를 활용하면 생산성이 크게 향상됩니다. 일반적인 원격 커널 개발 워크플로는 로컬 편집 → 원격 빌드 → 타겟 배포/테스트의 3단계로 구성됩니다.

이 문서에서 다루는 주제는 다음과 같습니다.

로컬 워크스테이션 VS Code / Vim / Emacs sshfs 마운트 GDB 프론트엔드 로컬 포트 포워딩 :1234(GDB) :5900(VNC) SSH / Mosh 포트 포워딩 빌드 서버 커널 소스 트리 make -j$(nproc) clangd / GCC 툴체인 tmux 세션 편집 | 빌드 | 로그 | 디버그 QEMU / KVM 로컬 VM 테스트 환경 SCP / rsync NFS / TFTP 시리얼 / GDB 타겟 보드 / VM 커널 이미지 부팅 모듈 로드 / 테스트 디버그 인터페이스 시리얼 콘솔 115200 KGDB stub :1234

SSH 설정 최적화

# ~/.ssh/config

# 커널 빌드 서버
Host kernel-build
    HostName 192.168.1.100
    User kdev
    Port 22
    IdentityFile ~/.ssh/id_ed25519
    # 연결 유지
    ServerAliveInterval 60
    ServerAliveCountMax 3
    # 멀티플렉싱 (연결 재사용)
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 600
    # 압축
    Compression yes
    # GDB 포트 포워딩
    LocalForward 1234 localhost:1234

SSH 키 관리

커널 빌드 서버에 접속할 때는 비밀번호 대신 공개키 인증을 사용하는 것이 보안과 편의성 모두에서 유리합니다. Ed25519 알고리즘은 현재 가장 권장되는 키 타입입니다.

# Ed25519 키 생성 (권장)
ssh-keygen -t ed25519 -C "kdev@kernel-build" -f ~/.ssh/id_ed25519

# 공개키를 빌드 서버에 등록
ssh-copy-id -i ~/.ssh/id_ed25519.pub kdev@kernel-build

# ssh-agent 시작 및 키 등록 (~/.bashrc에 추가)
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

# 키 등록 확인
ssh-add -l

Agent Forwarding을 활성화하면 빌드 서버에서 다시 다른 서버(예: Git 리포지토리, 타겟 보드)에 접속할 때 로컬 키를 사용할 수 있습니다.

# ~/.ssh/config — Agent Forwarding 설정
Host kernel-build
    ForwardAgent yes
    # 주의: 신뢰하지 않는 서버에는 ForwardAgent를 사용하지 마십시오.
    # 악의적인 서버 관리자가 forwarded agent를 악용할 수 있습니다.
보안 주의: ForwardAgent yes는 원격 서버의 root 사용자가 로컬 SSH 에이전트의 키를 임의로 사용할 수 있게 합니다. 신뢰할 수 있는 서버에만 설정하고, 가능하면 ssh -o ForwardAgent=yes로 필요할 때만 활성화하는 것이 안전합니다.

ProxyJump / 다단계 접속

커널 개발 환경에서 타겟 보드나 빌드 서버가 내부 네트워크에 있어 직접 접속이 불가능한 경우, 점프 호스트(Jump Host)를 경유해야 합니다. OpenSSH 7.3+에서 지원하는 ProxyJump 지시자를 사용하면 간단하게 설정할 수 있습니다.

# ~/.ssh/config — ProxyJump 다단계 접속

# 1단계: 외부에서 접근 가능한 게이트웨이
Host lab-gateway
    HostName gateway.company.com
    User kdev
    Port 22
    IdentityFile ~/.ssh/id_ed25519

# 2단계: 게이트웨이를 경유하여 빌드 서버 접속
Host kernel-build
    HostName 10.0.1.50
    User kdev
    ProxyJump lab-gateway
    IdentityFile ~/.ssh/id_ed25519

# 3단계: 빌드 서버를 경유하여 타겟 보드 접속
Host target-board
    HostName 10.0.1.200
    User root
    ProxyJump kernel-build
    Port 22
# 명령줄에서 직접 점프 호스트 지정
ssh -J lab-gateway kdev@10.0.1.50

# 다단계 점프 (게이트웨이 → 빌드서버 → 타겟)
ssh -J lab-gateway,kdev@10.0.1.50 root@10.0.1.200

# 레거시 방식 (ProxyCommand, OpenSSH 7.3 미만)
ssh -o ProxyCommand="ssh -W %h:%p lab-gateway" kdev@10.0.1.50

SSH 포트 포워딩 전략

원격 커널 개발에서 포트 포워딩은 필수적입니다. GDB 원격 디버깅, QEMU VNC 접속, 시리얼 콘솔 네트워크 접속 등 다양한 상황에서 SSH 터널(Tunnel)을 통해 원격 서비스에 안전하게 접근할 수 있습니다.

로컬 포워딩 (-L): 로컬 포트 → SSH 터널 → 원격 서비스 로컬 머신 localhost:1234 → GDB localhost:5900 → VNC localhost:2222 → 시리얼 VS Code / GDB 클라이언트 SSH 암호화 터널 ssh -L 1234:localhost:1234 kernel-build ssh -L 5900:localhost:5900 kernel-build 빌드 서버 QEMU -gdb :1234 QEMU -vnc :0 (5900) ser2net :2222 원격 서비스 (loopback) 리모트 포워딩 (-R): 원격 포트 → SSH 터널 → 로컬 서비스 로컬 머신 로컬 Git 서버 :3000 로컬 웹 서버 :8080 로컬에서만 접근 가능한 서비스 SSH 암호화 터널 ssh -R 3000:localhost:3000 kernel-build 빌드 서버 localhost:3000 → 로컬 Git localhost:8080 → 로컬 웹 원격에서 로컬 서비스 접근
# ── 로컬 포워딩 (-L): 로컬 포트로 원격 서비스 접근 ──

# GDB 원격 디버깅: 로컬 1234 → 원격 QEMU의 GDB stub
ssh -L 1234:localhost:1234 kernel-build

# QEMU VNC: 로컬 5900 → 원격 QEMU의 VNC 디스플레이
ssh -L 5900:localhost:5900 kernel-build

# 시리얼 콘솔 네트워크: 로컬 2222 → 원격 ser2net/socat
ssh -L 2222:localhost:2222 kernel-build

# 여러 포트를 한 번에 포워딩
ssh -L 1234:localhost:1234 -L 5900:localhost:5900 -L 2222:localhost:2222 kernel-build

# ── 리모트 포워딩 (-R): 원격에서 로컬 서비스 접근 ──

# 빌드 서버에서 로컬 Git 리포지토리에 접근
ssh -R 3000:localhost:3000 kernel-build

# ── 다이나믹 포워딩 (-D): SOCKS 프록시 ──

# 로컬 SOCKS 프록시로 원격 내부 네트워크 전체 접근
ssh -D 1080 kernel-build
# 브라우저에서 SOCKS5 프록시 localhost:1080 설정 → 내부 웹 UI 접근
# ~/.ssh/config — 포트 포워딩 영구 설정
Host kernel-build
    # GDB 디버깅용
    LocalForward 1234 localhost:1234
    # QEMU VNC용
    LocalForward 5900 localhost:5900
    # 시리얼 콘솔 네트워크용
    LocalForward 2222 localhost:2222
    # 다이나믹 포워딩 (SOCKS)
    DynamicForward 1080

SSH 보안 강화

커널 빌드 서버는 민감한 코드와 커널 이미지를 다루므로, SSH 서버 설정을 강화하는 것이 좋습니다.

# /etc/ssh/sshd_config — 보안 강화 설정

# 비밀번호 인증 비활성화 (키 전용)
PasswordAuthentication no
ChallengeResponseAuthentication no

# root 직접 로그인 금지
PermitRootLogin no

# 접속 허용 사용자 제한
AllowUsers kdev

# 빈 비밀번호 금지
PermitEmptyPasswords no

# X11 포워딩 비활성화 (불필요 시)
X11Forwarding no

# 최대 인증 시도 횟수
MaxAuthTries 3

# 유휴 세션 타임아웃 (서버 측)
ClientAliveInterval 300
ClientAliveCountMax 2
fail2ban 설정: SSH 무차별 대입 공격을 방어하려면 fail2ban을 설치하고 SSH jail을 활성화하는 것을 권장합니다. sudo apt install fail2ban 후 기본 설정만으로도 5회 실패 시 IP가 10분간 차단됩니다. 커널 빌드 서버처럼 외부에 노출된 경우 특히 중요합니다.

Mosh (모바일 셸)

Mosh(Mobile Shell)는 SSH의 대안으로, UDP 기반 프로토콜을 사용하여 불안정한 네트워크 환경에서도 끊김 없는 원격 세션을 제공합니다. Wi-Fi 전환, 네트워크 로밍, 노트북 절전/복귀 상황에서 SSH 연결이 끊어지는 문제를 해결합니다.

# 설치
sudo apt install mosh                # Debian/Ubuntu
sudo dnf install mosh                # Fedora/RHEL
sudo pacman -S mosh                  # Arch Linux

# 기본 접속 (SSH와 동일한 문법)
mosh kdev@kernel-build

# SSH config의 Host alias 사용
mosh kernel-build

# SSH 포트가 다른 경우
mosh --ssh="ssh -p 2222" kernel-build

# 서버 측 방화벽(Firewall) 설정 (Mosh는 UDP 60000-61000 사용)
sudo ufw allow 60000:61000/udp
# 또는 iptables
sudo iptables -A INPUT -p udp --dport 60000:61000 -j ACCEPT
비교 항목SSHMosh
프로토콜TCPUDP (SSP 프로토콜)
연결 유지TCP 상태 의존 (끊김 가능)IP 변경·절전에도 유지
입력 지연서버 RTT만큼 지연로컬 에코로 즉시 표시
포트 포워딩지원 (-L, -R, -D)미지원
출력 히스토리터미널 자체 지원미지원 (tmux와 조합)
X11 포워딩지원미지원
방화벽(Firewall)TCP 22번 포트UDP 60000-61000 추가 필요
커널 개발 추천안정적 네트워크 환경모바일/불안정 네트워크
Mosh + tmux 조합: Mosh는 포트 포워딩과 출력 히스토리를 지원하지 않으므로, 실무에서는 mosh kernel-build -- tmux attach -t kernel-dev처럼 tmux와 함께 사용하는 것이 일반적입니다. Mosh가 네트워크 안정성을 담당하고, tmux가 세션 관리와 화면 분할을 담당합니다.

sshfs를 활용한 원격 파일 마운트

sshfs(SSH Filesystem)는 FUSE 기반으로 원격 파일 시스템을 로컬에 마운트하는 도구입니다. 로컬 에디터로 원격 서버의 커널 소스를 직접 편집할 수 있어, 로컬 편집 + 원격 빌드 하이브리드 워크플로를 구현할 때 유용합니다.

기본 사용법

# 설치
sudo apt install sshfs               # Debian/Ubuntu
sudo dnf install fuse-sshfs          # Fedora/RHEL
sudo pacman -S sshfs                 # Arch Linux

# 원격 커널 소스를 로컬에 마운트
mkdir -p ~/remote-linux
sshfs kdev@kernel-build:/home/kdev/linux ~/remote-linux

# 최적화 옵션 (캐시, 압축, 재연결)
sshfs kdev@kernel-build:/home/kdev/linux ~/remote-linux \
    -o cache=yes \
    -o compression=yes \
    -o reconnect \
    -o ServerAliveInterval=15 \
    -o kernel_cache \
    -o auto_cache

# 마운트 해제
fusermount -u ~/remote-linux

# macOS에서 마운트 해제
umount ~/remote-linux

커널 개발 하이브리드 워크플로

sshfs로 마운트된 디렉토리에서 로컬 에디터를 사용하고, 빌드는 원격 서버의 tmux 세션에서 실행하는 패턴입니다.

# 1. sshfs 마운트
sshfs kdev@kernel-build:/home/kdev/linux ~/remote-linux -o reconnect,cache=yes

# 2. 로컬 에디터로 편집
vim ~/remote-linux/kernel/sched/core.c
# 또는 VS Code
code ~/remote-linux

# 3. 원격 tmux 세션에서 빌드 (별도 터미널)
ssh kernel-build -t "tmux attach -t kernel-dev"
# tmux 내에서: make -j$(nproc)
sshfs vs VS Code Remote vs rsync 비교:
  • sshfs: 별도 에디터 설정 없이 즉시 사용 가능하지만, 대형 커널 트리에서 grep이나 find가 느릴 수 있습니다
  • VS Code Remote-SSH: 원격 서버에서 직접 clangd가 동작하므로 코드 탐색 성능이 우수하며, 커널 개발에 가장 권장됩니다
  • rsync: 양방향 동기화가 필요할 때 사용합니다. rsync -avz --exclude='.git' ~/linux/ kernel-build:~/linux/로 소스를 동기화하고, 빌드 결과물은 rsync -avz kernel-build:~/linux/arch/x86/boot/bzImage ./로 가져옵니다

터미널 멀티플렉서(Terminal Multiplexer) 개요

터미널 멀티플렉서는 하나의 터미널 연결 안에서 여러 가상 터미널을 생성·관리하고, 세션을 분리(detach)/재연결(attach)할 수 있는 도구입니다. 커널 개발에서 특히 중요한 이유는 다음과 같습니다.

SSH 클라이언트 로컬 터미널 SSH 멀티플렉서 서버 tmux server / screen 백그라운드 데몬 프로세스 detach 후에도 유지 SSH 끊김 → 서버 계속 실행 세션(Session) 계층 세션: kernel-dev 윈도우 0: edit 페인(Pane) 0 vim kernel/sched/core.c [65% 너비] 페인 1 make -j$(nproc) [빌드 출력] [35% 너비] 윈도우 1: debug 페인 0 qemu-system-x86_64 [QEMU 실행] 페인 1 gdb vmlinux [GDB 디버거] 세션: monitoring 윈도우 0: logs 페인 0 dmesg -wH 페인 1 htop / perf top 윈도우 1: trace trace-cmd trace-cmd record \ -e sched_switch

tmux

tmux(terminal multiplexer)는 BSD 라이선스로 개발된 현대적 터미널 멀티플렉서입니다. 클라이언트-서버 아키텍처로 동작하며, 서버 프로세스(Process)가 모든 세션을 관리하고 클라이언트는 소켓(Socket)을 통해 접속합니다. 커널 개발자들이 가장 널리 사용하는 도구입니다.

tmux 핵심 개념

개념설명비유
서버(Server)모든 세션을 관리하는 백그라운드 프로세스OS 커널
세션(Session)독립된 작업 공간 (여러 윈도우 포함)가상 데스크톱
윈도우(Window)세션 내 탭 (전체 화면 차지)브라우저 탭
페인(Pane)윈도우 내 분할된 영역화면 분할
프리픽스 키tmux 명령의 시작 키 (기본 Ctrl+b)Vim의 : 명령 모드

tmux 주요 키 바인딩

분류키 바인딩동작
세션Prefix d세션 분리(detach)
Prefix s세션 목록 표시 및 전환
Prefix $세션 이름 변경
Prefix ( / )이전/다음 세션 전환
윈도우Prefix c새 윈도우 생성
Prefix n / p다음/이전 윈도우 이동
Prefix 0~9번호로 윈도우 이동
Prefix ,윈도우 이름 변경
Prefix &윈도우 종료 (확인 요청)
페인Prefix %수직 분할 (좌우)
Prefix "수평 분할 (상하)
Prefix 방향키페인 간 이동
Prefix z페인 확대/축소(zoom) 토글
Prefix x현재 페인 닫기
Prefix Space페인 레이아웃 순환 변경
복사 모드Prefix [복사 모드 진입 (스크롤/검색)
Space → Enter선택 시작 → 복사
Prefix ]붙여넣기
/ (복사 모드 중)앞으로 검색

커널 개발용 tmux 설정

# ~/.tmux.conf — 커널 개발 최적화 설정

# ── 기본 설정 ──
set -g default-terminal "tmux-256color"
set -ag terminal-overrides ",xterm-256color:RGB"
set -g history-limit 100000        # 커널 빌드 로그가 길므로 충분히
set -g mouse on                    # 마우스 페인 선택/리사이즈
set -g base-index 1               # 윈도우 번호 1부터 시작
setw -g pane-base-index 1          # 페인 번호도 1부터
set -g renumber-windows on          # 윈도우 삭제 시 번호 재정렬
set -sg escape-time 0             # Vim ESC 지연 제거
set -g focus-events on             # Vim autoread 지원

# ── 프리픽스 키 변경 (Ctrl+a) ──
set -g prefix C-a
unbind C-b
bind C-a send-prefix

# ── 직관적 페인 분할 ──
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
bind c new-window -c "#{pane_current_path}"

# ── 페인 이동 (Vim 스타일) ──
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R

# ── 페인 리사이즈 (반복 가능) ──
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5

# ── 복사 모드 (vi 키 바인딩) ──
setw -g mode-keys vi
bind -T copy-mode-vi v send -X begin-selection
set -s set-clipboard external       # OSC 52 지원 터미널에서 로컬 클립보드 연동
bind -T copy-mode-vi y send -X copy-selection-and-cancel
bind -T copy-mode-vi Escape send -X cancel

# ── 상태바 ──
set -g status-left "[#S@#H] "
set -g status-left-length 30
set -g status-right "#{?client_prefix,#[bg=red] PREFIX ,} %H:%M %d-%b"
set -g status-interval 5

# ── 설정 즉시 리로드 ──
bind r source-file ~/.tmux.conf \; display "Config reloaded!"

tmux 필수 명령어

# 세션 관리
tmux new -s kernel-dev               # 세션 생성
tmux ls                              # 세션 목록
tmux attach -t kernel-dev            # 세션 재연결
tmux kill-session -t kernel-dev      # 세션 종료

# 분리(detach) 후 재연결 — SSH 끊김 시 빌드 유지의 핵심
# 세션 내에서 Ctrl+a d → SSH 종료 → SSH 재접속 후:
tmux attach -t kernel-dev            # 진행 중이던 빌드 화면 그대로

# 세션 외부에서 명령 전송
tmux send-keys -t kernel-dev:build "make -j\$(nproc)" C-m

# 페인 레이아웃 저장/복원 (수동)
tmux list-windows -t kernel-dev -F "#{window_layout}"

# 버퍼 캡처 (빌드 로그 저장)
tmux capture-pane -t kernel-dev:build -p > build.log

# 공유 세션 (페어 디버깅)
tmux new -s shared                   # 사용자 A: 세션 생성
tmux attach -t shared -r             # 사용자 B: 읽기 전용 접속

커널 개발 세션 자동화 스크립트

#!/bin/bash
# kernel-tmux.sh — 커널 개발용 tmux 세션 자동 생성
# 이미 세션이 있으면 재연결, 없으면 새로 생성

SESSION="kernel"
LINUX_DIR="$HOME/linux"

if tmux has-session -t $SESSION 2>/dev/null; then
    tmux attach -t $SESSION
    exit 0
fi

tmux new-session -d -s $SESSION -c $LINUX_DIR

# 윈도우 1: 에디터
tmux rename-window -t $SESSION:1 "edit"
tmux send-keys -t $SESSION:1 "vim ." C-m

# 윈도우 2: 빌드
tmux new-window -t $SESSION -n "build" -c $LINUX_DIR

# 윈도우 3: QEMU + GDB (수직 분할)
tmux new-window -t $SESSION -n "debug" -c $LINUX_DIR
tmux split-window -h -t $SESSION:3 -c $LINUX_DIR
tmux send-keys -t $SESSION:3.1 "echo '# QEMU: qemu-system-x86_64 -kernel arch/x86/boot/bzImage -s -S -nographic'" C-m
tmux send-keys -t $SESSION:3.2 "echo '# GDB: gdb -ex \"target remote :1234\" vmlinux'" C-m

# 윈도우 4: 로그 모니터링 (수평 3분할)
tmux new-window -t $SESSION -n "logs" -c $LINUX_DIR
tmux split-window -v -t $SESSION:4 -c $LINUX_DIR
tmux split-window -v -t $SESSION:4.2 -c $LINUX_DIR
tmux send-keys -t $SESSION:4.1 "echo '# dmesg -wH'" C-m
tmux send-keys -t $SESSION:4.2 "echo '# tail -f /var/log/kern.log'" C-m
tmux send-keys -t $SESSION:4.3 "echo '# htop'" C-m

tmux select-window -t $SESSION:2
tmux attach -t $SESSION

tmux 유용한 플러그인

플러그인기능커널 개발 활용
tpmtmux 플러그인 매니저아래 플러그인 설치/관리
tmux-resurrect세션 저장/복원재부팅 후 빌드 환경 즉시 복구
tmux-continuum자동 저장 (15분 간격)resurrect 자동화
tmux-yank시스템 클립보드 복사빌드 에러 메시지 복사
tmux-logging페인 출력 자동 로깅QEMU 시리얼 콘솔 로그 자동 저장
# ~/.tmux.conf — 플러그인 설정 (TPM 사용)
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'
set -g @plugin 'tmux-plugins/tmux-yank'

# resurrect: Vim 세션도 함께 복원
set -g @resurrect-strategy-vim 'session'
set -g @resurrect-capture-pane-contents 'on'

# continuum: 15분마다 자동 저장, tmux 시작 시 자동 복원
set -g @continuum-save-interval '15'
set -g @continuum-restore 'on'

# TPM 초기화 (반드시 맨 마지막)
run '~/.tmux/plugins/tpm/tpm'

GNU Screen

GNU Screen은 1987년에 처음 공개된 가장 오래된 터미널 멀티플렉서입니다. tmux보다 오래되었지만 여전히 많은 서버에 기본 설치되어 있으며, 특히 레거시(Legacy) 환경이나 임베디드(Embedded) 시스템에서 유용합니다. 커널 개발에서는 시리얼 콘솔(Serial Console) 접속(screen /dev/ttyUSB0)에 특히 많이 쓰입니다.

GNU Screen screen 프로세스 (단일 바이너리) 서버+클라이언트 통합 / SUID 필요 가능 윈도우 0 전체 화면 (분할 제한적) 윈도우 1 시리얼 콘솔 /dev/ttyUSB0 윈도우 2 빌드 make -j$(nproc) 특징 시리얼 디바이스 직접 접속 | 기본 설치 빈도 높음 수직 분할 버전 제한 | 스크립팅 API 제한적 tmux tmux server 백그라운드 데몬 tmux client 소켓으로 서버 접속 윈도우 0 페인 0 (vim) 페인 1 (make) 윈도우 1 페인 0 (QEMU) 페인 1 (GDB) 특징 자유로운 수평/수직 분할 | 강력한 스크립팅 API 클라이언트-서버 분리 | 풍부한 플러그인 생태계

screen 주요 키 바인딩

분류키 바인딩동작tmux 대응
세션Ctrl+a d세션 분리(detach)Prefix d
Ctrl+a "윈도우 목록Prefix w
Ctrl+a A윈도우 이름 변경Prefix ,
윈도우Ctrl+a c새 윈도우Prefix c
Ctrl+a n / p다음/이전 윈도우Prefix n/p
Ctrl+a 0~9번호로 윈도우 이동Prefix 0~9
Ctrl+a k윈도우 종료Prefix &
분할Ctrl+a S수평 분할Prefix "
Ctrl+a |수직 분할 (v4.1+)Prefix %
Ctrl+a Tab분할 영역 이동Prefix 방향키
복사/스크롤Ctrl+a [복사(Copy) 모드 (스크롤)Prefix [
Ctrl+a ]붙여넣기Prefix ]
Ctrl+a H화면 로깅 토글tmux-logging 플러그인

screen 설정과 커널 개발 활용

# ~/.screenrc — GNU Screen 설정

# 시작 메시지 비활성화
startup_message off

# 출력 히스토리 버퍼 확대 (커널 빌드 로그 대비)
defscrollback 50000

# 256색 지원
term "screen-256color"

# vi 키 바인딩 (복사 모드)
markkeys "h=^B:l=^F:$=A"

# 하드스테이터스 (상태바)
hardstatus alwayslastline
hardstatus string '%{= kG}[%{G}%H%{g}] %{= kw}%-w%{= Bw}%n %t%{-}%+w %= %{= kG}%Y-%m-%d %c'

# UTF-8 지원
defutf8 on

# 자동 detach (SSH 끊김 시)
autodetach on

# bell → visual bell
vbell on
# screen 필수 명령어

# 세션 생성 및 관리
screen -S kernel                     # 이름 있는 세션 생성
screen -ls                           # 세션 목록
screen -r kernel                     # 세션 재연결
screen -d -r kernel                  # 다른 곳에서 detach 후 재연결
screen -x kernel                     # 공유 세션 접속 (멀티디스플레이)

# 시리얼 콘솔 접속 — 커널 개발의 핵심 용도
screen /dev/ttyUSB0 115200          # 시리얼 디바이스, 보드레이트 지정
screen /dev/ttyACM0 9600            # Arduino/임베디드 보드

# 로깅 — 시리얼 콘솔 출력 자동 저장
screen -L -Logfile serial.log /dev/ttyUSB0 115200

# 원격 명령 전송
screen -S kernel -X stuff "make -j\$(nproc)\n"
시리얼 콘솔 디버깅 팁: 커널 패닉(Kernel Panic)이나 부팅 문제를 디버깅할 때, 타겟 보드의 시리얼 포트에 screen /dev/ttyUSB0 115200로 접속하면 콘솔 메시지를 실시간(Real-time)으로 확인할 수 있습니다. -L 옵션으로 자동 로깅하면 나중에 분석도 가능합니다. 종료 시 Ctrl+a k를 사용합니다 (Ctrl+c로는 종료되지 않음).

nohup과 disown

멀티플렉서 없이도 SSH 끊김에서 프로세스를 보호하는 간단한 방법이 있습니다. 전체 세션 관리는 불가능하지만, 단일 명령(예: 장시간 커널 빌드)을 보호하기에는 충분합니다.

systemd-run 주의: systemd-run --user --scope는 현재 로그인 세션의 사용자 매니저에 종속됩니다. 마지막 로그인 세션이 종료될 때 lingering이 비활성화되어 있으면 함께 정리될 수 있으므로, SSH 로그아웃 이후까지 확실히 유지해야 하는 빌드는 tmux/screen을 우선 사용하거나 loginctl enable-linger $USER 후 사용자 서비스로 실행하는 편이 안전합니다.
# nohup: SIGHUP 무시 + stdout/stderr를 nohup.out으로 리디렉션
nohup make -j$(nproc) &             # 백그라운드 빌드, SSH 끊어져도 유지
nohup make -j$(nproc) > build.log 2&1 &   # 출력 파일 지정

# disown: 이미 실행 중인 작업을 쉘 job 목록에서 제거 → SIGHUP 미전송
make -j$(nproc) &                    # 백그라운드 실행
disown %1                            # job 1을 쉘에서 분리

# disown -h: HUP 무시만 설정 (job 목록에서는 유지)
make -j$(nproc) &
disown -h %1                         # HUP만 무시, jobs로 여전히 확인 가능

# 실행 중인 포그라운드 프로세스를 백그라운드로 전환 → disown
# 1. Ctrl+z (중지)
# 2. bg (백그라운드 재개)
# 3. disown %1 (쉘에서 분리)

# ── systemd-run: 사용자 서비스 기반 대안 (systemd 기반 시스템) ──
# SSH 로그아웃 뒤에도 유지하려면 lingering 활성화가 필요할 수 있음
loginctl enable-linger $USER

# 분리된 사용자 서비스로 실행 (현재 디렉토리 유지)
systemd-run --user --unit=kernel-build --same-dir --collect make -j$(nproc)

# 현재 로그인 세션 안에서만 묶어둘 일회성 작업
systemd-run --user --scope make olddefconfig

# 상태 확인
systemctl --user status kernel-build.service

# 로그 확인
journalctl --user -u kernel-build.service -f
방법용도한계
nohup cmd &새로 실행하는 명령 보호출력 확인 어려움, 상호작용 불가
disown이미 실행 중인 작업 보호터미널 분리 후 재연결 불가
systemd-run --userlingering이 설정된 사용자 서비스에서 독립 실행linger 설정 필요 가능, 로그는 journalctl로 확인
tmux / screen전체 세션 관리별도 설치 필요할 수 있음

터미널 멀티플렉서 비교

기능tmuxGNU ScreenZellij
초기 릴리스200719872021
라이선스ISC (BSD 계열)GPL-3.0MIT
언어CCRust
아키텍처클라이언트-서버 (소켓)단일 프로세스 (SUID)클라이언트-서버 (WASM 플러그인)
수직 분할기본 지원v4.1+ (Ctrl+a |)기본 지원
수평 분할기본 지원기본 지원 (Ctrl+a S)기본 지원
설정~/.tmux.conf~/.screenrcKDL (config.kdl)
플러그인TPM (풍부한 생태계)없음WASM 플러그인
스크립팅강력 (명령줄 API)제한적WASM + CLI
시리얼 접속불가 (별도 도구 필요)내장 지원불가
UI 힌트없음 (학습 필요)없음 (학습 필요)키 바인딩 힌트 표시
기본 설치 빈도높음 (대부분 배포판)매우 높음 (레거시 포함)낮음 (별도 설치)
Mosh 호환호환 (SSH 레이어 위)호환 (SSH 레이어 위)호환 (SSH 레이어 위)
커널 개발 추천최우선 권장시리얼 콘솔/레거시 환경대안 (발전 중)
선택 가이드:
  • 일반 커널 개발: tmux 권장 — 자유로운 화면 분할, 강력한 스크립팅, 플러그인 생태계
  • 시리얼 콘솔 디버깅: screen 권장 — screen /dev/ttyUSB0 115200로 즉시 접속
  • 멀티플렉서 처음 사용: Zellij 고려 — UI 힌트가 키 바인딩 학습 부담을 줄여줌
  • 멀티플렉서 없는 환경: nohup / disown으로 최소한의 세션 보호

VS Code Remote Development

VS Code의 Remote-SSH 확장을 사용하면 로컬에서 편집하면서 원격 서버의 clangd, 빌드 시스템(Build System)을 그대로 활용할 수 있습니다. 커널처럼 대규모 C 코드베이스에서는 원격 서버에서 clangd가 직접 동작하므로, sshfs 방식보다 코드 탐색·자동완성 성능이 훨씬 우수합니다.

Remote-SSH 확장 설정

VS Code 마켓플레이스에서 Remote - SSH(ms-vscode-remote.remote-ssh) 확장을 설치한 후, F1 → Remote-SSH: Connect to Host~/.ssh/config에 설정된 호스트에 접속합니다. 첫 접속 시 원격 서버에 VS Code Server가 자동 설치됩니다.

# ~/.ssh/config — VS Code Remote에 최적화된 설정
Host kernel-build
    HostName 192.168.1.100
    User kdev
    IdentityFile ~/.ssh/id_ed25519
    # VS Code 재연결 속도 향상
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 600
    # 연결 유지
    ServerAliveInterval 60
    ServerAliveCountMax 3
    # GDB 포트 포워딩
    LocalForward 1234 localhost:1234

원격 서버 설정

기본 VS Code 설정(확장 프로그램, settings.json, tasks.json, launch.json)은 에디터 설정 가이드와 동일합니다. 아래는 원격 환경에서 추가로 필요한 설정만 설명합니다.

// 원격 서버의 .vscode/settings.json — 원격 환경 추가 설정
{
    "remote.SSH.remotePlatform": {
        "kernel-build": "linux"
    },
    "clangd.path": "/usr/bin/clangd-18",
    "telemetry.telemetryLevel": "off"
}

원격 커널 디버깅 통합

SSH 포트 포워딩(LocalForward 1234 localhost:1234)으로 GDB 포트를 로컬에 노출하면, 에디터 설정 가이드의 launch.json 설정을 그대로 사용하여 원격 QEMU에서 커널을 디버깅할 수 있습니다.

VS Code Remote 최적화

원격 개발 최적화 팁:
  • SSH 멀티플렉싱: ControlMaster auto로 연결 재사용 → VS Code 재연결 속도 대폭 향상
  • 파일 감시 제외: .git/objects, build/, *.o를 감시 대상에서 제외하여 CPU/메모리 절약
  • clangd 메모리 제한: 커널 트리에서 clangd가 메모리를 많이 사용할 수 있습니다. "clangd.arguments": ["--malloc-trim", "-j=2"]로 제한합니다
  • 원격 서버 디스크: VS Code Server는 ~/.vscode-server에 약 500MB를 사용합니다. 디스크 여유를 확인합니다
  • tmux + VS Code: 장시간 빌드는 VS Code 터미널 대신 tmux 세션에서 실행하면 SSH 끊김에도 빌드가 유지됩니다

원격 커널 빌드 및 배포 워크플로

원격 빌드 서버에서 커널을 빌드한 후, 타겟 보드나 VM에 배포하여 테스트하는 전체 워크플로를 설명합니다.

로컬 머신 VS Code Remote-SSH 코드 편집 / clangd GDB 프론트엔드 localhost:1234 VNC 클라이언트 localhost:5900 시리얼 터미널 localhost:2222 SSH 멀티플렉싱 ControlMaster auto 단일 TCP 연결 공유 SSH 터널 -L 1234 -L 5900 -L 2222 암호화 압축 인증 :22 원격 빌드 서버 커널 빌드 환경 GCC/Clang, make -j$(nproc), clangd QEMU / KVM -gdb :1234 -vnc :0 tmux 세션 편집 | 빌드 | 로그 | 디버그 시리얼 브릿지 socat /dev/ttyUSB0 :2222 rsync / NFS / TFTP 배포 타겟 디바이스 커널 부팅 bzImage / Image + DTB 모듈 로드 / 테스트 insmod, kselftest KGDB stub 시리얼 115200 NFS root / TFTP boot SCP rsync 시리얼

빌드 서버에서 타겟으로 배포

커널 이미지와 모듈을 빌드 서버에서 타겟 시스템으로 전송하는 방법은 환경에 따라 다릅니다.

배포판 차이: 아래 예제의 update-initramfsupdate-grub 단계는 Debian/Ubuntu 계열 기준입니다. Fedora/RHEL 계열은 보통 dracut, 임베디드/U-Boot 환경은 별도 부트 엔트리 갱신이나 네트워크 부팅 절차가 필요하므로 그대로 복사하지 말고 대상 환경에 맞게 치환해야 합니다.
# ── rsync: 빌드 서버 → 타겟 (SSH 기반, 가장 범용적) ──

# 커널 이미지 전송
rsync -avz arch/x86/boot/bzImage root@target-board:/boot/vmlinuz-custom

# 모듈 전송 (INSTALL_MOD_PATH로 설치 후 전송)
make modules_install INSTALL_MOD_PATH=/tmp/modules
rsync -avz /tmp/modules/lib/modules/ root@target-board:/lib/modules/

# ── 자동 빌드+배포 스크립트 ──
#!/bin/bash
# deploy-kernel.sh — 커널 빌드 후 타겟에 자동 배포

TARGET="root@target-board"
KVER=$(make kernelrelease)

# 빌드
make -j$(nproc) || exit 1
make modules -j$(nproc) || exit 1

# 모듈 설치 (임시 디렉토리)
make modules_install INSTALL_MOD_PATH=/tmp/kmod

# 타겟으로 전송
rsync -avz arch/x86/boot/bzImage ${TARGET}:/boot/vmlinuz-${KVER}
rsync -avz /tmp/kmod/lib/modules/${KVER}/ ${TARGET}:/lib/modules/${KVER}/

# 타겟에서 initramfs 재생성 및 부트로더 업데이트 (Debian/Ubuntu 예시)
ssh ${TARGET} "update-initramfs -c -k ${KVER} && update-grub"

echo "배포 완료: ${KVER}"
# ── NFS root: 임베디드 개발에 편리한 네트워크 부팅 ──

# 빌드 서버에서 NFS 루트 파일시스템 설정 (/etc/exports)
# /srv/nfs/rootfs 10.0.1.200(rw,no_root_squash,no_subtree_check)

# 커널 모듈을 NFS root에 직접 설치 → 타겟 재부팅만으로 반영
make modules_install INSTALL_MOD_PATH=/srv/nfs/rootfs

# ── TFTP: U-Boot 환경에서 커널 이미지 네트워크 부팅 ──

# 빌드 서버 TFTP 디렉토리에 커널 이미지 복사
cp arch/arm64/boot/Image /srv/tftp/

# U-Boot 명령 (타겟 시리얼 콘솔에서)
# => setenv serverip 10.0.1.50
# => tftp ${kernel_addr_r} Image
# => tftp ${fdt_addr_r} board.dtb
# => booti ${kernel_addr_r} - ${fdt_addr_r}

원격 디버깅 워크플로

빌드 서버에서 QEMU를 실행하거나, 원격 타겟 보드의 KGDB stub에 SSH 터널을 통해 GDB를 연결하는 워크플로입니다.

로컬 클라이언트 SSH 터널 (-L) 빌드 서버 서비스 타겟 / VM GDB 클라이언트 target remote localhost:1234 -L 1234:localhost:1234 GDB 프로토콜 중계 QEMU -gdb :1234 또는 KGDB stub 127.0.0.1:1234 커널 디버깅 중단점, 스택 추적 VNC 클라이언트 localhost:5900 그래픽 콘솔 표시 -L 5900:localhost:5900 RFB 프로토콜 중계 QEMU -vnc :0 그래픽 프레임버퍼 127.0.0.1:5900 VM 화면 GUI 환경 테스트 시리얼 터미널 socat - TCP: localhost:2222 -L 2222:localhost:2222 바이트 스트림 중계 socat / ser2net /dev/ttyUSB0 브릿지 127.0.0.1:2222 타겟 보드 커널 콘솔 출력 QEMU 모니터 socat - TCP: localhost:4445 -L 4445:localhost:4445 모니터 명령 중계 QEMU Monitor VM 상태 / 스냅샷 127.0.0.1:4445 VM 제어 savevm, info regs
디버그 포트 보안: 시리얼, QEMU Monitor, 임시 디버그 소켓은 가능하면 빌드 서버의 loopback(127.0.0.1)에만 바인딩하고 SSH 포트 포워딩으로 접근하십시오. 0.0.0.0에 열면 같은 네트워크의 다른 호스트가 접속할 수 있습니다.
# ── 빌드 서버에서 QEMU + GDB (로컬에서 SSH 터널로 접근) ──

# 1. 빌드 서버의 tmux 세션에서 QEMU 실행
qemu-system-x86_64 \
    -kernel arch/x86/boot/bzImage \
    -append "console=ttyS0 nokaslr root=/dev/sda rw" \
    -drive file=rootfs.img,format=raw \
    -nographic \
    -enable-kvm -m 2G -smp 4 \
    -gdb tcp::1234 -S         # GDB stub 활성화, 시작 시 정지

# 2. 로컬에서 SSH 포트 포워딩으로 GDB 연결
ssh -L 1234:localhost:1234 kernel-build
# 별도 터미널에서:
gdb vmlinux -ex "target remote localhost:1234"

# ── 시리얼 콘솔 네트워크 접속 (socat / ser2net) ──

# 빌드 서버의 loopback에만 바인딩하여 시리얼 디바이스를 TCP로 노출 (socat)
socat TCP-LISTEN:2222,bind=127.0.0.1,reuseaddr,fork FILE:/dev/ttyUSB0,b115200,raw,echo=0

# 로컬에서 SSH 터널을 통해 접속
ssh -L 2222:localhost:2222 kernel-build
# 별도 터미널에서 시리얼 콘솔 접속:
socat - TCP:localhost:2222
# 또는 minicom -D tcp:localhost:2222

원격 QEMU 접근

빌드 서버에서 실행 중인 QEMU의 그래픽 콘솔이나 시리얼 콘솔에 로컬에서 접근하는 방법입니다.

# ── VNC: QEMU 그래픽 콘솔 원격 접근 ──

# 빌드 서버에서 QEMU 실행 (VNC 활성화)
qemu-system-x86_64 \
    -kernel arch/x86/boot/bzImage \
    -vnc :0                   # VNC 포트 5900
    -enable-kvm -m 2G

# 로컬에서 SSH 터널로 VNC 접속
ssh -L 5900:localhost:5900 kernel-build
# VNC 클라이언트로 localhost:5900 접속

# ── 시리얼 콘솔: QEMU 텍스트 콘솔 원격 접근 ──

# QEMU의 시리얼 콘솔을 loopback TCP로 노출
qemu-system-x86_64 \
    -kernel arch/x86/boot/bzImage \
    -append "console=ttyS0 nokaslr" \
    -serial tcp:127.0.0.1:4444,server=on,wait=off \
    -nographic -enable-kvm -m 2G

# 로컬에서 SSH 터널로 시리얼 콘솔 접속
ssh -L 4444:localhost:4444 kernel-build
socat - TCP:localhost:4444

# ── QEMU Monitor: 원격 QEMU 제어 ──

# QEMU Monitor를 loopback TCP로 노출
qemu-system-x86_64 \
    -kernel arch/x86/boot/bzImage \
    -monitor tcp:127.0.0.1:4445,server=on,wait=off \
    -nographic -enable-kvm -m 2G

# 로컬에서 QEMU Monitor 접속 (VM 상태 확인, 스냅샷 등)
ssh -L 4445:localhost:4445 kernel-build
socat - TCP:localhost:4445
# (qemu) info registers
# (qemu) savevm checkpoint1
통합 원격 개발 세션: 실무에서는 빌드 서버에서 tmux 세션 하나에 편집/빌드/QEMU/GDB 윈도우를 배치하고, SSH 포트 포워딩으로 GDB·VNC·시리얼 포트를 로컬에 노출합니다. 로컬에서는 VS Code Remote로 코드를 편집하고, VS Code의 디버거 UI로 GDB에 연결합니다. 이렇게 하면 모든 작업이 하나의 SSH 연결 위에서 통합됩니다.

트러블슈팅

SSH 문제 해결

증상원인해결 방법
Connection refusedSSH 서버 미실행 또는 포트 불일치sudo systemctl start sshd, 포트 확인 (ss -tlnp | grep ssh)
Permission denied (publickey)키 미등록 또는 권한 문제ssh-copy-id 재실행, ~/.ssh 권한 확인 (700), 키 파일 권한 확인 (600)
Connection timed out방화벽 차단 또는 네트워크 문제방화벽 규칙 확인, telnet host 22로 포트 테스트
ControlMaster 소켓 오류비정상 종료로 소켓 파일 잔류rm ~/.ssh/sockets/* 후 재접속
포트 포워딩 실패원격 포트가 이미 사용 중ssh -v로 로그 확인, 원격에서 ss -tlnp으로 포트 점유 확인
SSH 연결 느림DNS 역방향 조회 지연서버 sshd_configUseDNS no 설정
# SSH 연결 문제 디버깅
ssh -vvv kernel-build                # 상세 디버그 출력

# ControlMaster 소켓 정리
rm -f ~/.ssh/sockets/*

# 특정 연결의 소켓 상태 확인
ssh -O check kernel-build

tmux 문제 해결

증상원인해결 방법
sessions should be nested 경고tmux 안에서 tmux 실행 시도TMUX= 환경 변수 해제 후 실행, 또는 tmux attach 사용
256색이 표시되지 않음TERM 환경변수 불일치set -g default-terminal "tmux-256color" 설정, SSH 접속 시 TERM 확인
클립보드 복사 안 됨원격 tmux에서 로컬 클립보드 접근 불가tmux-yank 플러그인 + set-clipboard on, 또는 OSC 52 이스케이프 사용
마우스 스크롤 미동작마우스 모드 미설정set -g mouse on 추가
세션 복원 실패tmux-resurrect 저장 파일 손상~/.tmux/resurrect/ 디렉토리에서 이전 저장 파일 복원

VS Code Remote 문제 해결

증상원인해결 방법
원격 서버 연결 실패VS Code Server 설치 실패원격에서 ~/.vscode-server 삭제 후 재시도, 디스크 공간 확인
높은 CPU 사용률파일 감시자(File Watcher) 과다files.watcherExcludebuild/, .git/objects/ 추가
clangd OOM 종료커널 트리가 너무 큼-j=2로 인덱싱 스레드(Thread) 제한, --malloc-trim 옵션 추가
재연결 느림SSH 매번 새 연결 생성ControlMaster auto + ControlPersist 600 설정
확장 프로그램 미동작원격 측에 확장 미설치확장 관리 화면에서 "Install in SSH: host" 버튼으로 원격 설치