우분투 설치 후 개발자가 처음 할 일: 드라이버·한글 입력·개발 도구·Docker·런타임 초기 세팅

이 글의 핵심

우분투 24.04 LTS를 새로 설치한 개발자가 첫날에 순서대로 해야 할 일을 정리합니다. 시스템 업데이트와 드라이버부터 한글 입력, git·터미널 도구, Node/Python/Go 버전 관리자, Docker, 에디터, snap·flatpak 선택 기준, 보안·백업 설정, 한국 환경 팁, 마지막으로 이 모든 걸 재현 가능한 스크립트로 묶는 법까지 다룹니다.

들어가며

우분투를 새로 설치하고 첫 화면을 마주하면 막막할 수 있습니다. 데스크톱은 떠 있지만 아직 개발 도구는 하나도 없고, 어디서부터 손대야 할지 순서가 잘 안 잡히는 경우가 많습니다. 인터넷에 떠도는 “우분투 세팅 팁” 글들은 대부분 단편적인 명령어 나열이라, 왜 이 순서로 해야 하는지, 왜 이 도구를 쓰는지에 대한 설명이 빠져 있는 경우가 흔합니다.

이 글은 우분투 24.04 LTS(Noble Numbat)를 새로 설치했다고 가정하고, 개발자가 첫날에 해야 할 일을 실제로 겪게 되는 순서대로 정리합니다. 시스템을 최신 상태로 만들고 드라이버를 잡는 것부터 시작해서, 한글 입력, 터미널 필수 도구, 언어별 버전 관리자, Docker, 에디터, 그리고 보안·백업 설정까지 다룹니다. 26.04 LTS를 쓰고 있다면 전체적인 흐름은 크게 다르지 않겠지만, 패키지명이나 기본 구성 요소 버전은 릴리스 노트를 한 번 확인하는 편이 안전합니다. 정확성을 최우선으로 하기 위해 이 글의 모든 명령어는 24.04 기준으로만 서술합니다.

각 항목마다 “무엇을”뿐 아니라 “왜”를 같이 적었습니다. 단순히 명령어를 복사-붙여넣기 하는 것보다, 이 설정이 왜 필요한지 이해하고 넘어가면 나중에 문제가 생겼을 때 스스로 원인을 추적하기가 훨씬 쉬워집니다.

1. 시스템 업데이트, 드라이버, 펌웨어부터

가장 먼저 할 일은 패키지 목록을 새로고침하고 시스템을 최신 상태로 올리는 것입니다.

sudo apt update && sudo apt full-upgrade -y
sudo reboot

apt update는 저장소의 패키지 목록만 갱신하고, full-upgrade는 실제로 설치된 패키지를 업그레이드하면서 필요하면 의존성 때문에 패키지를 새로 설치하거나 제거하기도 합니다(upgrade보다 더 적극적으로 의존성을 해결합니다). 커널이나 드라이버가 업데이트됐을 수 있으니 재부팅까지 해주는 것이 좋습니다.

여기서 한 가지 주의할 점은 sudo do-release-upgrade입니다. 이 명령은 LTS 버전 자체를 올리는 명령이라(예: 22.04 → 24.04), 방금 설치를 마친 시스템에서는 실행할 필요가 없습니다. 설치 미디어가 오래돼서 이미 다음 LTS가 나온 상태라면 고려할 수 있지만, 설치 직후에는 full-upgrade로 충분합니다. 릴리스 업그레이드는 실패 시 시스템이 부팅 불가 상태가 되는 경우도 있어 신중하게 접근해야 합니다.

그래픽 드라이버

NVIDIA 그래픽카드가 있다면 오픈소스 nouveau 드라이버 대신 공식 드라이버를 설치하는 것이 대부분의 개발 작업(특히 CUDA, 여러 모니터, 외장 디스플레이)에 유리합니다.

ubuntu-drivers devices      # 인식된 그래픽카드와 권장 드라이버 확인
sudo ubuntu-drivers install # 권장 드라이버 자동 설치

ubuntu-drivers devices는 하드웨어를 스캔해서 어떤 드라이버가 권장(recommended)되는지 보여줍니다. 특정 버전을 지정하고 싶다면 sudo apt install nvidia-driver-550 식으로 버전을 명시할 수도 있습니다. 설치 후 재부팅하면 되는데, Secure Boot가 켜진 시스템에서는 재부팅 과정에서 MOK(Machine Owner Key) 등록 화면이 나타납니다. 이 화면에서 암호를 설정하고 재부팅 후 다시 같은 암호로 등록을 완료해야 커널 모듈이 정상적으로 로드됩니다. 이 단계를 무시하고 지나가면 로그인 화면 이후 검은 화면만 보이는 상황을 겪게 되는데, 이 부분은 씽크패드 우분투 개발 환경 가이드에서 좀 더 자세한 트러블슈팅을 다루고 있으니 증상을 겪었다면 참고하시기 바랍니다.

펌웨어 업데이트

노트북이라면 fwupd를 통해 BIOS/UEFI, 썬더볼트 컨트롤러 등의 펌웨어도 확인해두는 것이 좋습니다.

sudo fwupdmgr get-updates
sudo fwupdmgr update

펌웨어 업데이트는 전원이 안정적으로 연결된 상태에서 진행해야 하고, 업데이트 도중 전원이 끊기면 하드웨어가 먹통이 될 위험이 있으니 노트북이라면 반드시 충전기를 연결한 채로 실행하시기 바랍니다.

flowchart TD
    A["설치 완료 직후"] --> B["apt update / full-upgrade"]
    B --> C["재부팅"]
    C --> D["ubuntu-drivers devices로 확인"]
    D --> E{"NVIDIA GPU 있음?"}
    E -->|예| F["ubuntu-drivers install"]
    E -->|아니오| G["fwupdmgr로 펌웨어 확인"]
    F --> H{"Secure Boot 켜짐?"}
    H -->|예| I["재부팅 시 MOK 암호 등록"]
    H -->|아니오| G
    I --> G
    G --> J["다음 단계: 한글 입력 설정"]

2. 한글 입력기 설정

한국어로 개발하는 입장에서 한글 입력은 가장 먼저 막히는 지점 중 하나입니다. 우분투 24.04는 기본적으로 IBus를 쓰지만, 최근에는 fcitx5가 GNOME/Wayland 환경에서의 안정성과 한/영 전환 반응성 면에서 더 나은 평가를 받는 편입니다.

sudo apt install fcitx5 fcitx5-hangul
im-config -n fcitx5   # 입력기 프레임워크를 fcitx5로 지정

설치 후에는 로그아웃했다가 다시 로그인해야 반영됩니다. 로그인 후 fcitx5-configtool을 실행해 입력기 목록에 “Hangul”을 추가하고, 한/영 전환 키를 원하는 키(보통 한/영 키 또는 오른쪽 Alt)로 지정하면 됩니다. 노트북에 별도 한/영 키가 없다면 Super+Space 조합으로 대체하는 경우가 많습니다.

이 부분에 대한 좀 더 실전적인 트러블슈팅(특정 앱에서 입력 포커스가 안 잡히는 문제, 브라우저별 차이 등)은 윈도우에서 우분투로 넘어온 개발자를 위한 적응 가이드에서 클립보드·단축키와 함께 다루고 있으니 참고하시면 좋습니다.

3. 기본 개발 도구 설치

빌드 도구와 git

sudo apt install -y build-essential git curl wget unzip jq

build-essential은 gcc, g++, make 등 C/C++ 컴파일에 필요한 최소한의 도구 모음입니다. Node.js의 네이티브 애드온을 빌드하거나 Python 패키지 중 C 확장이 포함된 것을 설치할 때 이게 없으면 컴파일 단계에서 에러가 납니다. jq는 JSON을 다루는 CLI에서 필수적인데, API 응답을 터미널에서 바로 파싱하거나 CI 스크립트에서 값을 추출할 때 자주 쓰이므로 처음부터 같이 깔아두는 것을 권합니다.

git은 설치 직후 아래처럼 최소한의 설정을 해두어야 합니다.

git config --global user.name "홍길동"
git config --global user.email "[email protected]"
git config --global init.defaultBranch main
git config --global core.editor "vim"   # 또는 선호하는 에디터

init.defaultBranch를 설정해두지 않으면 새 저장소를 만들 때마다 git이 기본 브랜치 이름(master)에 대한 경고를 출력합니다. GitHub 등 대부분의 원격 저장소가 이미 main을 기본으로 쓰고 있으니 미리 맞춰두는 것이 편합니다.

SSH 키는 GitHub/GitLab 인증에 필요합니다.

ssh-keygen -t ed25519 -C "[email protected]"
cat ~/.ssh/id_ed25519.pub   # 이 내용을 GitHub Settings > SSH Keys에 등록

RSA 대신 ed25519를 권장하는 이유는 키 길이가 짧으면서도 보안 강도가 충분하고, 서명·검증 속도도 더 빠르기 때문입니다. 예전 문서에서 ssh-keygen -t rsa -b 4096을 보게 되는 경우가 있는데, 레거시 서버와의 호환성이 필요한 게 아니라면 ed25519가 현재 기준으로 더 합리적인 선택입니다.

터미널 생산성 도구

sudo apt install -y htop tree ripgrep fd-find bat fzf tmux

여기서 이름 함정이 두 가지 있습니다. Debian/Ubuntu 저장소에서는 다른 패키지와 이름이 충돌해서 fd-find는 실행 파일명이 fdfind이고, bat는 실행 파일명이 batcat입니다. 그래서 설치하고 바로 fd나 bat를 입력하면 command not found: fd 같은 에러를 만나게 됩니다. 아래처럼 심볼릭 링크를 걸어두면 다른 배포판이나 macOS 문서에 나온 명령어를 그대로 쓸 수 있어 편합니다.

mkdir -p ~/.local/bin
ln -s $(which fdfind) ~/.local/bin/fd
ln -s $(which batcat) ~/.local/bin/bat
# ~/.local/bin이 PATH에 없다면 ~/.bashrc나 ~/.zshrc에 추가
export PATH="$HOME/.local/bin:$PATH"

ripgrep(rg 명령)은 grep보다 기본적으로 .gitignore를 존중하면서 훨씬 빠르게 코드베이스를 검색해주고, fzf는 셸 히스토리나 파일 목록을 퍼지 검색으로 골라내는 데 유용해서 한 번 익숙해지면 손을 놓기 어렵습니다. htop이나 btop(스타일이 더 화려한 버전, 별도 설치 필요)은 프로세스 모니터링에, tmux는 SSH 세션이 끊겨도 작업을 유지하고 싶을 때 씁니다. apt에서 제공하는 명령어 전반에 대한 더 넓은 치트시트는 우분투 필수 명령어 가이드에서 다루고 있습니다.

4. 셸 선택: bash vs zsh

우분투 기본 셸은 bash입니다. zsh로 바꾸는 사람이 많은 이유는 자동완성, 테마, 플러그인 생태계가 더 풍부하기 때문인데, 그만큼 설정이 복잡해지고 셸 시작 속도가 느려질 수 있다는 트레이드오프도 있습니다.

sudo apt install zsh
chsh -s $(which zsh)   # 기본 셸 변경, 재로그인 후 적용

zsh 자체는 플러그인 없이도 bash보다 나은 자동완성을 제공하지만, 대부분의 사람들이 원하는 경험(테마, git 상태 표시, 자동 제안)은 프레임워크를 얹어야 나옵니다. 여기서 두 갈래로 나뉩니다. oh-my-zsh는 플러그인과 테마가 방대하고 설정이 쉽지만, 플러그인을 많이 켤수록 새 터미널을 열 때마다 체감되는 지연이 생깁니다. 반대로 starship 같은 가벼운 프롬프트 도구는 셸 자체는 그대로 두고 프롬프트만 예쁘고 정보가 풍부하게(git 브랜치, 언어 버전 등을 자동 표시) 바꿔주는 방식이라 시작 속도에 대한 부담이 적습니다.

curl -sS https://starship.rs/install.sh | sh
echo 'eval "$(starship init zsh)"' >> ~/.zshrc   # bash라면 bash로 교체

개인적으로는 터미널을 하루에도 수십 번 여닫는 개발 습관 때문에 프롬프트 렌더링 지연에 꽤 예민한 편이라, 무거운 oh-my-zsh 플러그인 세트를 켜뒀다가 새 탭을 열 때마다 눈에 띄게 느려지는 걸 체감하고 다시 가벼운 구성으로 돌아간 경험이 있습니다. 플러그인을 정말 많이 쓰지 않는다면 굳이 큰 프레임워크를 얹지 않아도 기본 zsh + starship 조합만으로 충분히 쾌적합니다. 터미널 에뮬레이터 자체의 설정 팁은 Kitty 터미널 사용 가이드에서 다룹니다.

5. 언어 런타임은 버전 관리자로

시스템 apt로 언어 런타임을 까는 것과, nvm/pyenv 같은 버전 관리자로 사용자 영역에 설치하는 것은 근본적으로 다른 선택입니다. apt로 설치한 런타임은 시스템의 다른 도구가 의존하고 있는 경우가 많아서, 전역으로 함부로 건드리면 예상치 못한 부작용이 생길 수 있습니다. 버전 관리자를 쓰면 프로젝트마다 다른 버전을 격리해서 쓸 수 있고, 시스템 패키지와 충돌할 일이 없습니다.

Node.js

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
# 셸 재시작 후
nvm install --lts
nvm use --lts

nvm 대신 fnm이나 mise(구 rtx)를 쓰면 셸 시작 속도가 더 빠릅니다(nvm은 셸 함수로 구현돼 있어 셸이 뜰 때마다 약간의 오버헤드가 있습니다). 여러 언어를 한 도구로 관리하고 싶다면 mise가 Node, Python, Ruby 등을 하나의 설정 파일(.mise.toml 또는 .tool-versions)로 관리할 수 있어 편리합니다.

Python

우분투 24.04부터는 시스템 Python에 pip로 직접 패키지를 설치하려고 하면 다음과 같은 에러를 만나게 됩니다.

error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you are trying to
    install.

이건 PEP 668이 도입되면서 생긴 보호 장치입니다. 우분투는 apt로 설치되는 파이썬 패키지와 pip로 설치되는 패키지가 같은 경로를 공유하면서 서로 덮어써서 시스템이 깨지는 사고가 반복되자, 시스템 Python 환경에 전역으로 pip install 하는 것 자체를 막아버렸습니다. 그래서 반드시 가상환경(venv)이나 pipx, 혹은 uv 같은 도구를 통해 격리된 환경에 설치해야 합니다.

# 프로젝트별 가상환경
python3 -m venv .venv && source .venv/bin/activate

# 전역 CLI 도구 설치용
sudo apt install pipx
pipx install black

# 훨씬 빠른 대안: uv (Rust로 작성된 패키지/버전 관리자)
curl -LsSf https://astral.sh/uv/install.sh | sh
uv venv && uv pip install requests

pyenv로 여러 Python 버전을 관리하는 방법도 여전히 유효하지만, 최근에는 uv가 Python 버전 설치(uv python install 3.12)와 패키지 관리를 하나로 묶어서 제공하고 속도도 훨씬 빨라 새로 세팅하는 입장이라면 uv부터 시도해보는 것을 권합니다.

Java, Go, Rust

# Java: SDKMAN으로 여러 버전 관리
curl -s "https://get.sdkman.io" | bash
sdk install java 21.0.4-tem

# Go: 공식 tarball 방식(버전 관리자 없이 단일 버전만 쓴다면)
# 여러 버전이 필요하면 g나 goenv 같은 버전 관리자를 고려

# Rust: rustup이 사실상 표준
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Go는 프로젝트마다 버전 차이로 골치 아픈 경우가 상대적으로 적은 편이라 시스템에 하나만 깔아두고 쓰는 사람도 많지만, 여러 버전을 오가야 한다면 g(가벼운 Go 버전 관리자)를 쓰는 편이 낫습니다.

6. Docker와 컨테이너 환경

apt 저장소의 docker.io 패키지와 Docker 공식 저장소의 docker-ce는 이름은 비슷해도 버전 최신성과 업데이트 주기가 다릅니다. docker.io는 우분투 저장소 정책에 따라 버전이 고정되고 업데이트가 느린 편이라, 최신 Compose V2 문법이나 buildx 기능을 온전히 쓰려면 Docker 공식 저장소를 추가하는 편이 낫습니다.

# 공식 저장소 추가 (Docker 공식 문서 절차 요약)
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

설치 후 docker run hello-world를 바로 실행하면 이런 에러를 만나게 됩니다.

permission denied while trying to connect to the Docker daemon socket at
unix:///var/run/docker.sock

Docker 데몬은 root 권한으로 동작하고 소켓 파일도 root 소유라서, 매번 sudo docker를 쓰지 않으려면 현재 사용자를 docker 그룹에 넣어야 합니다.

sudo usermod -aG docker $USER
newgrp docker   # 또는 로그아웃 후 재로그인

여기서 짚어야 할 보안적 의미가 있습니다. docker 그룹에 속한 사용자는 사실상 root 권한과 동등합니다. 볼륨 마운트로 호스트 파일시스템 전체에 접근하는 컨테이너를 손쉽게 띄울 수 있기 때문입니다. 개인 개발 머신에서는 편의를 위해 이렇게 쓰는 경우가 많지만, 이 권한 구조를 이해하지 못한 채로 무심코 넣어두면 나중에 “왜 이 사용자가 root 수준 권한을 가지고 있지”라는 보안 점검에서 걸리는 경우가 종종 있습니다. 신뢰할 수 없는 이미지를 자주 다뤄야 하거나 보안이 중요한 환경이라면 rootless Docker(dockerd-rootless-setuptool.sh install)를 고려할 수 있는데, 일부 네트워크 기능이나 볼륨 권한 처리 방식이 달라져서 기존 워크플로우를 그대로 옮기기 전에 한 번 테스트해보는 것이 안전합니다.

Docker Desktop for Linux도 존재하지만, 리눅스에서는 이미 네이티브로 Docker 엔진이 돌아가기 때문에 GUI 대시보드가 꼭 필요한 게 아니라면 CLI + Compose만으로 충분한 경우가 대부분입니다.

sequenceDiagram
    participant U as 사용자
    participant S as 셸
    participant D as Docker 데몬
    U->>S: docker run hello-world
    S->>D: /var/run/docker.sock 접근 시도
    D-->>S: permission denied
    U->>S: sudo usermod -aG docker $USER
    U->>S: newgrp docker (또는 재로그인)
    S->>D: /var/run/docker.sock 접근 시도
    D-->>S: 정상 응답
    S-->>U: hello-world 출력

7. 에디터와 IDE

VS Code는 세 가지 방식으로 설치할 수 있습니다. Microsoft 공식 apt 저장소를 추가하는 방식(.deb 기반), 직접 .deb 파일을 받아 설치하는 방식, 그리고 snap store의 code 패키지입니다. apt 저장소 방식이 업데이트 관리가 가장 깔끔하고, snap 버전은 자체 샌드박스 정책 때문에 확장 프로그램이 터미널 도구(예: 전역으로 설치한 CLI)에 접근하지 못하는 경우가 종종 보고되어, 개발용으로는 공식 apt 저장소 설치를 권합니다.

sudo apt install -y wget gpg
wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg
sudo install -D -o root -g root -m 644 packages.microsoft.gpg /etc/apt/keyrings/packages.microsoft.gpg
echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" | sudo tee /etc/apt/sources.list.d/vscode.list
sudo apt update && sudo apt install code

VS Code 확장, 원격 개발(Remote-SSH), 우분투에서 자주 겪는 GUI 세부 이슈는 우분투 VS Code 개발자 팁에서 별도로 다루고 있습니다. IntelliJ 계열을 쓴다면 개별 .tar.gz를 받는 것보다 JetBrains Toolbox를 설치해두면 여러 IDE와 버전을 한곳에서 관리할 수 있어 편합니다.

8. snap, apt, flatpak — 언제 무엇을 쓸까

우분투는 세 가지 패키지 방식이 공존합니다. 흥미로운 점은 우분투가 기본 제공하는 Firefox 자체가 이미 deb가 아니라 snap 패키지로 바뀌었다는 사실입니다. Canonical이 브라우저 업데이트 주기를 배포판 릴리스와 분리하기 위해 선택한 방식인데, 이 때문에 첫 실행 시 다른 배포판보다 로딩이 느리다고 느끼는 사람들이 많습니다.

  • apt: 시스템 핵심 도구, CLI, 서버 소프트웨어에 적합합니다. 의존성 해결이 안정적이고 부팅/실행 오버헤드가 없습니다.
  • snap: 배포판 버전에 관계없이 최신 버전을 배포하고 싶은 벤더가 선호합니다. 샌드박스 격리 덕분에 보안상 이점이 있지만, 콜드 스타트가 느리고 일부 파일 접근 권한 문제가 있을 수 있습니다.
  • flatpak: GUI 애플리케이션 배포에 특화되어 있고 Flathub이라는 큰 저장소를 갖고 있습니다. 우분투에는 기본 설치돼 있지 않아 직접 추가해야 합니다.
sudo apt install flatpak gnome-software-plugin-flatpak
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo

세 가지를 다 쓰는 게 이상해 보일 수 있지만, 실제로는 “시스템 도구는 apt, 브라우저나 오피스류는 flatpak, 어쩔 수 없이 snap으로만 배포되는 것은 snap” 식으로 자연스럽게 역할이 나뉘는 경우가 많습니다.

9. 데스크톱 편의 설정

GNOME이 기본 데스크톱이라면 gnome-tweaks와 Extension Manager를 설치해두면 창 관리, 폰트 렌더링, 최소화 버튼 노출 여부 같은 세부 설정에 접근할 수 있습니다.

sudo apt install gnome-tweaks
flatpak install flathub com.mattjakeman.ExtensionManager

클립보드 히스토리가 필요하다면 GNOME 확장(Clipboard Indicator 등)을 Extension Manager를 통해 설치하는 것이 가장 간단합니다. 멀티모니터 환경에서 프랙셔널 스케일링(125%, 150% 등)을 쓰면 일부 Xorg 전용 애플리케이션이 흐릿하게 렌더링되는 문제가 여전히 남아 있는데, 이건 Wayland 세션에서 더 잘 처리되는 편이라 로그인 화면에서 세션을 “Ubuntu”(Wayland)로 선택하는 것을 기본으로 권합니다. 다만 일부 화면 공유 소프트웨어나 오래된 원격 데스크톱 툴은 아직 Wayland 지원이 완전하지 않아서, 화면 공유가 자주 끊기거나 커서가 안 보이는 문제를 겪는다면 로그인 화면에서 톱니바퀴 아이콘을 눌러 “Ubuntu on Xorg” 세션으로 바꿔보는 것도 실전적인 우회책입니다.

스크린샷은 기본적으로 PrtScn(전체), Shift+PrtScn(영역 선택)으로 찍히고 클립보드로 바로 복사됩니다. 파일 관리자(Nautilus)에서 숨김 파일을 보려면 Ctrl+H를 누르면 되는데, .bashrc나 .ssh 디렉터리를 GUI로 찾아야 할 때 자주 쓰게 됩니다.

10. 보안과 안정성

방화벽

sudo ufw enable
sudo ufw allow OpenSSH

기본적으로 들어오는 연결을 막고 SSH만 허용하는 최소한의 구성입니다. 로컬 개발 서버(3000, 8080 포트 등)는 보통 localhost 바인딩이라 별도 규칙이 필요 없지만, 다른 기기에서 접근해야 한다면 그때그때 sudo ufw allow 3000/tcp 식으로 열어주면 됩니다. 세부 명령어는 우분투 필수 명령어 가이드의 ufw 절을 참고하시기 바랍니다.

자동 보안 업데이트

sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

이 패키지는 보안 패치만 골라서 백그라운드로 자동 적용해줍니다. 커널 전체 업그레이드까지 자동화하고 싶지는 않지만 중요한 보안 취약점은 놓치고 싶지 않을 때 적당한 절충안입니다.

백업과 스냅샷

Timeshift를 설치해두면 시스템 설정을 건드리기 전에 스냅샷을 찍어두고, 문제가 생기면 이전 상태로 되돌릴 수 있습니다.

sudo apt install timeshift

드라이버 설치나 커널 업그레이드처럼 위험도가 있는 작업 전에는 스냅샷을 하나 찍어두는 습관을 들이면 마음이 훨씬 편해집니다. 개인적으로 이 여유가 실제로 도움이 됐던 경우는, NVIDIA 드라이버 버전을 바꿔보다가 부팅 후 디스플레이 매니저가 아예 뜨지 않았을 때였는데, 복구 모드로 들어가서 Timeshift 스냅샷을 하나 되돌리는 것만으로 몇 시간을 절약한 경험이 있습니다.

inotify watch 한도

VS Code나 webpack 같은 빌드 도구를 여러 프로젝트에서 동시에 띄워두면 다음과 같은 에러를 만나기 쉽습니다.

Error: ENOSPC: System limit for number of file watchers reached

리눅스 커널은 파일 변경 감시(inotify)에 쓸 수 있는 watch 개수를 기본값으로 제한해두는데, 이 기본값이 최신 프론트엔드 프로젝트의 node_modules 규모에 비해 너무 작습니다. 아래처럼 한도를 늘려주면 해결됩니다.

echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

스왑과 시간 동기화

free -h로 스왑이 얼마나 잡혀 있는지 확인해보고, 메모리가 넉넉하지 않은 노트북이라면 스왑 파일을 추가로 만들어두는 것이 빌드 작업 중 OOM으로 프로세스가 죽는 것을 막는 데 도움이 됩니다. 윈도우와 듀얼 부팅 중이라면 시계가 몇 시간씩 어긋나는 문제를 겪을 수 있는데, 이는 윈도우가 하드웨어 RTC를 로컬 타임으로 쓰고 리눅스는 UTC로 쓰기 때문입니다. 이 문제와 듀얼 부팅 관련 세부 설정은 WSL2 vs 듀얼 부팅 비교 가이드에서 다루고 있습니다.

11. 한국 환경에서 놓치기 쉬운 것들

폰트는 한글 렌더링 품질에 직접 영향을 줍니다. 기본 폰트만으로도 쓸 수는 있지만, 코드 에디터에는 고정폭 한글 지원이 좋은 D2Coding을, 일반 UI에는 Noto Sans CJK KR이나 나눔고딕을 추가로 설치해두면 문서나 프레젠테이션 작업에서 체감 품질이 확실히 달라집니다.

sudo apt install fonts-noto-cjk fonts-nanum

카카오톡 PC 클라이언트나 공동인증서 기반 은행/공공기관 사이트는 리눅스를 공식 지원하지 않는 경우가 여전히 많습니다. 카카오톡은 웹 버전이나 안드로이드 에뮬레이터로 우회하는 정도가 현실적인 선택지이고, 공동인증서가 꼭 필요한 업무가 있다면 별도의 윈도우 VM을 하나 두는 것이 가장 스트레스가 적습니다. 이 주제는 개발자 운영체제 선택 가이드에서 조금 더 넓은 맥락으로 다루고 있습니다.

12. 반복되는 세팅을 스크립트로 묶기

지금까지의 과정을 새 머신마다 손으로 반복하는 것은 비효율적입니다. 자주 쓰는 설정을 dotfiles 저장소 하나로 묶어두면, 새 노트북을 받거나 시스템을 재설치할 때 한 번의 스크립트 실행으로 대부분을 복원할 수 있습니다. 핵심은 스크립트를 여러 번 실행해도 안전하도록(idempotent) 만드는 것입니다.

#!/usr/bin/env bash
set -euo pipefail

sudo apt update
sudo apt install -y build-essential git curl wget unzip jq \
  htop tree ripgrep fd-find bat fzf tmux zsh fonts-noto-cjk fonts-nanum

# 심볼릭 링크는 이미 있으면 건너뛰기
[ -L ~/.local/bin/fd ] || ln -s "$(which fdfind)" ~/.local/bin/fd
[ -L ~/.local/bin/bat ] || ln -s "$(which batcat)" ~/.local/bin/bat

# dotfiles 심볼릭 링크 (예: ~/.gitconfig, ~/.zshrc)
for f in gitconfig zshrc; do
  ln -sf "$HOME/dotfiles/$f" "$HOME/.$f"
done

set -euo pipefail은 스크립트 중간에 에러가 나면 즉시 멈추고(-e), 정의되지 않은 변수를 참조하면 에러를 내고(-u), 파이프라인 중 하나라도 실패하면 전체를 실패로 처리하도록(pipefail) 만들어 줍니다. 조건문으로 “이미 존재하면 건너뛰기”를 넣어두면 스크립트를 실수로 두 번 돌려도 문제가 생기지 않습니다. 처음에는 이 정도만 해두고, 시간이 지나며 자신만의 설정이 쌓이면 조금씩 다듬어 나가는 것으로 충분합니다.

마치며

우분투 초기 세팅은 한 번에 완벽하게 끝내야 하는 작업이 아닙니다. 드라이버와 한글 입력처럼 당장 막히는 것부터 해결하고, 개발 도구와 런타임은 실제로 필요해질 때 하나씩 버전 관리자로 설치해 나가도 충분합니다. 다만 각 단계에서 왜 이 방식을 택하는지(예: 시스템 Python에 직접 pip install 하지 않는 이유, docker 그룹에 넣는 것의 보안적 의미)를 이해하고 넘어가면, 나중에 비슷한 에러 메시지를 다시 만났을 때 검색 없이도 스스로 원인을 짚어낼 수 있게 됩니다. 이 글에서 다룬 각 항목은 개별적으로 훨씬 깊이 다룬 글들이 있으니, 특정 주제에서 막히면 연결된 글들을 참고하시기 바랍니다.