
NixOS에서 OpenClaw를 설정하는 방법
요약
NixOS 환경에서 OpenClaw를 사용하여 AI 어시스턴트의 장기 기억과 선언적 설정을 구축하는 방법을 설명합니다. QMD를 통한 벡터 검색과 Telegram 연동을 통해 재현 가능한 AI 워크플로우를 구성하는 과정을 다룹니다.
핵심 포인트
- NixOS의 선언적 설정을 통한 AI 환경의 재현성 확보
- QMD를 활용한 AI 어시스턴트의 장기 기억(Long-term memory) 구현
- Telegram 봇과 LLM을 결합한 모듈형 아키텍처 구축
- flake.nix를 이용한 의존성 관리 및 시스템 롤백 용이성
서론 (Introduction)
어시스턴트와의 모든 새로운 대화는 백지 상태에서 시작됩니다. 어시스턴트는 이전 세션에서 우리가 어떤 대화를 나누었는지 기억하지 못합니다. 저는 이 점이 마음에 들지 않았습니다. 그래서 해결책을 찾기 시작했고 OpenClaw로 결정했습니다. 선언적 설정 (declarative configuration), QMD를 통한 장기 기억 (long-term memory), Telegram 봇, GLM-4.7-flash — 이 모든 것들이 단 하나의 명령어로 어떤 머신에서든 재현 가능합니다.
아키텍처 (Architecture)
OpenClaw Gateway가 존재합니다. 여기에 Telegram (통신 채널), Workspace (어시스턴트의 성격을 정의하는 파일들), LLM (응답을 생성하는 모델), 그리고 QMD (벡터 검색을 통한 장기 기억)가 연결되어 있습니다. 모든 것은 Nix로 기술됩니다.
NixOS를 사용하기 전에는 Arch를 사용했습니다. 업데이트가 정기적으로 시스템을 망가뜨렸습니다. 패키지 버전이 어긋나고 의존성 (dependencies)이 일치하지 않았습니다. 게다가 롤백 (rollbacks)을 수동으로 처리해야 했습니다. NixOS를 사용하면, 설정하고 잊어버리면 됩니다. 무언가 잘못되면 커밋 (commit)으로 롤백하거나 이전 세대 (generation)로 부팅하면 됩니다.
flake.nix 분석 (Breaking down flake.nix)
{
description = "NixOS configuration with Hyprland";
...
- nix-openclaw:
github:openclaw/nix-openclaw로부터 가져온 flake입니다. Home Manager 모듈, 패키지 오버레이 (package overlay), 그리고cache.garnix.io의 바이너리 캐시 (binary cache)를 가져옵니다. Garnix가 유용한 이유는 OpenClaw를 빌드할 때 의존성을 처음부터 다시 빌드하지 않기 때문입니다. - openclaw-workspace: 단순한 경로이며, flake가 아닙니다. 어시스턴트가 어떻게 행동할지를 정의하는 파일들이 담긴 디렉토리입니다.
- specialArgs: 외부 입력을 Nix 모듈 시스템 (module system)으로 전달합니다. 이것이 없으면 모듈들이
openclaw-workspace를 볼 수 없습니다.
저는 호스트 (host)가 하나뿐이지만, 만약 서버나 노트북을 추가하더라도 설정은 동일하게 유지될 것입니다.
모듈형 아키텍처 (Modular architecture)
설정은 두 가지 수준으로 나뉩니다.
시스템 모듈 (System modules)
modules/nixos/default.nix에 위치합니다. 여기에는 base.nix (부트로더 (bootloader), 커널 (kernel)), networking.nix (NetworkManager), services.nix (저의 경우 Hyprland 및 AmneziaWG), security.nix (Polkit을 통한 전원 종료 시 비밀번호 비활성화), 그리고 users.nix (vokrob, agenix, zsh)가 포함됩니다.
base.nix에 다음과 같이 오버레이 (overlay)를 추가합니다:
nixpkgs.overlays = [
nix-openclaw.overlays.default
(import ../../overlays)
...
이 오버레이는 openclaw-gateway를 포함하여 OpenClaw 패키지들을 pkgs에 추가합니다.
사용자 모듈 (User modules)
modules/home/default.nix를 통해 임포트 (import)됩니다. 주요 모듈은 features/openclaw.nix입니다.
또한 hosts/nixos/default.nix에 다음을 추가했습니다:
home-manager.sharedModules = [nix-openclaw.homeManagerModules.openclaw];
sharedModules를 사용하면 모든 Home Manager 설정에서 OpenClaw 모듈을 사용할 수 있습니다. 두 번째 호스트가 추가되더라도 모듈이 이미 준비되어 있게 됩니다.
openclaw.nix 분석
주요 설정은 modules/home/features/openclaw.nix에 기술되어 있습니다.
워크스페이스 (Workspace)
programs.openclaw.workspace.bootstrapFiles = {
agents = "${openclaw-workspace}/AGENTS.md";
soul = "${openclaw-workspace}/SOUL.md";
...
이 다섯 가지 파일이 어시스턴트의 성격을 형성합니다: AGENTS.md는 에이전트 역할과 라우팅 (routing)을 정의하고, SOUL.md는 기본 지침 (base instruction)이며, TOOLS.md는 도구 (tools)를 설명하고, IDENTITY.md는 통신 스타일을 설정하며, USER.md는 저의 데이터를 담고 있습니다.
파일들은 ~/.config/openclaw/에 위치하며, 시스템을 재빌드 (rebuild)하지 않고도 변경할 수 있습니다. 단순히 SOUL.md를 편집하면 어시스턴트의 행동이 달라지기 시작할 것입니다.
비밀 정보 (Secrets)
programs.openclaw.environment = {
ZHIPU_API_KEY = "/run/agenix/openclaw-zhipu-key";
OPENCLAW_GATEWAY_TOKEN = "/run/agenix/openclaw-gateway-token";
...
값은 키 그 자체가 아니라 파일로 향하는 경로 (path)입니다. OpenClaw는 파일로부터 비밀 정보를 읽어옵니다. Nix는 빌드 타임 (build time)에 경로를 치환하며, agenix는 설정 활성화 중에 비밀 정보를 복호화하여 /run/agenix/에 배치합니다. 이 정보들은 절대 /nix/store/에 저장되지 않습니다.
Telegram 토큰은 별도로 전달됩니다:
channels.telegram.tokenFile = "/run/agenix/openclaw-telegram-token";
Integrations (통합)
config = {
gateway.mode = "local";
...
local 모드는 게이트웨이가 OpenClaw Cloud에 종속되지 않고 실행됨을 의미합니다. 모든 것이 제 기기 내에서 이루어집니다. 게이트웨이는 로컬 포트에서 대기하며, /run/agenix/openclaw-gateway-token에 있는 토큰을 통해 요청을 승인합니다. 오직 저만이 Telegram 봇에 접근할 수 있습니다 (allowFrom 목록).
GLM-4.7-flash
models.providers.openai = {
baseUrl = "https://open.bigmodel.cn/api/paas/v4";
apiKey = {
...
프로바이더(provider) 이름은 openai이지만, baseUrl은 Z.ai를 가리킵니다. Z.ai는 OpenAI 호환 엔드포인트(endpoint)를 제공합니다. OpenClaw는 api = "openai-completions"를 통해 표준 OpenAI SDK를 사용합니다. glm-4.7-flash 모델은 무료이며, 200K 토큰의 컨텍스트 윈도우 (context window)를 제공합니다.
QMD — 장기 기억 (long-term memory)
memory.backend = "qmd";
QMD는 별도의 서버가 필요 없는 Qdrant 기반의 사이드카 (sidecar)입니다.
각 메시지와 응답은 벡터화 (vectorized)되며, 임베딩 (embeddings)은 메타데이터와 함께 QMD로 들어갑니다. 제가 새로운 내용을 작성하면, 시맨틱 검색 (semantic search)이 과거의 파편들을 찾아내어 프롬프트 (prompt)에 섞어 넣습니다. 어시스턴트는 우리가 이전 세션에서 대화했던 내용을 기억합니다.
제가 직접 테스트해 보았는데, 정말 기억합니다:
"remember" 및 "forget" 명령은 MEMORY.md를 통해 작동합니다. QMD는 그 위에 전체 히스토리에 대한 시맨틱 검색 기능을 추가할 뿐입니다.
Elevated privileges (권한 상승)
tools.elevated = {
enabled = true;
allowFrom = {
...
이 섹션은 Telegram 봇을 통해 위험한 도구들에 대한 접근 권한을 부여합니다: 호스트에서 명령 실행, 패키지 설치, 프로세스 관리 등입니다.
Additional options (추가 옵션)
agents.defaults = {
model.primary = "openai/glm-4.7-flash";
thinkingDefault = "low";
...
thinkingDefault: 추론 깊이 (reasoning depth).low로 설정 — 일상적인 명령에는 깊은 사고가 필요하지 않습니다;compaction.reserveTokensFloor: 메모리와 시스템 프롬프트(system prompt)를 위해 20K 토큰을 예약합니다. 이를 예약하지 않았을 때는 컨텍스트(context)가 모두 소모되어 어시스턴트가 어처구니없는 실수를 하기 시작했습니다;reloadScript: 게이트웨이(gateway)를 재시작하지 않고도 설정 재로드 스크립트를 생성합니다;bundledPlugins.summarize: 채팅으로 전송된 URL과 PDF를 자동으로 요약합니다.
게이트웨이는 systemd 사용자 서비스(user service)로 실행됩니다. 즉, 제가 로그인할 때 시작되며 충돌 시 재시작됩니다. 로그는 journalctl --user -u openclaw-gateway -f를 통해 확인합니다. 문제가 발생하면 systemctl --user restart openclaw-gateway를 실행합니다.
Secrets (비밀 정보)
secrets/ 디렉토리에는 세 개의 암호화된 파일이 있습니다:
openclaw-telegram-token.age;openclaw-zhipu-key.age;openclaw-gateway-token.age.
설정 파일에서는 다음과 같이 보입니다:
age.secrets = {
"openclaw-telegram-token" = {
file = ../../secrets/openclaw-telegram-token.age;
...
Agenix는 age를 사용하여 파일을 암호화합니다. 키는 ~/.config/agenix/age-key.txt에 로컬로 저장됩니다. 복호화는 시스템 활성화(system activation) 중에만 발생합니다. 비밀 정보는 /nix/store/에 절대 저장되지 않으므로, 실수로 커밋되거나 바이너리 캐시(binary cache)에 노출될 위험이 없습니다. 누군가 스토어(store)에 접근하더라도 API 키를 볼 수 없습니다.
Message lifecycle (메시지 생명주기)
제가 텔레그램(Telegram) 봇으로 메시지를 보냅니다. 텔레그램 봇은 이를 게이트웨이로 전달합니다. 게이트웨이는 먼저 allowFrom을 확인하여 제가 목록에 있으면 진행합니다. 그 다음 게이트웨이는 QMD에 쿼리하여 과거 대화의 컨텍스트(context)를 가져옵니다. 게이트웨이는 시스템 지침(system instructions) + 메모리 컨텍스트(memory context) + 제 메시지를 결합하여 프롬프트(prompt)를 구성합니다. 이를 GLM-4.7-flash로 전송합니다. 모델의 응답은 게이트웨이에 의해 새로운 메모리 파편(memory fragment)으로 저장된 후 텔레그램으로 다시 전송됩니다.
무료 모델 대기열 때문에 이 체인(chain)은 몇 초에서 몇 분 정도 소요됩니다.
문제점 (Problems)
서비스가 시작되지 않음 (Service won't start)
가장 먼저 맞닥뜨린 문제는 게이트웨이(gateway)가 시작되지 않는 것이었습니다. 원인은 agenix가 활성화 스크립트(activation script)를 적용하지 않았기 때문입니다. sudo nixos-rebuild switch를 실행한 후 /run/agenix/를 확인하여 해결했습니다:
ls -la /run/agenix/
만약 파일이 없다면 age.secrets 정의에 오류가 있는 것입니다. 저의 경우, owner와 mode를 지정하는 것을 잊어버려서 agenix가 파일을 생성하지 못했습니다.
텔레그램 봇이 응답하지 않음 (Telegram bot doesn't respond)
두 가지 가능한 원인이 있습니다: allowFrom 설정이 잘못되었거나, 토큰(token)이 유효하지 않은 경우입니다. @userinfobot을 통해 자신의 텔레그램 ID를 확인할 수 있습니다. 저는 실수로 사용자 ID(user ID) 대신 채팅 ID(chat ID)를 입력했습니다.
토큰을 확인하려면:
journalctl --user -u openclaw-gateway | grep -i telegram
QMD가 컨텍스트를 반환하지 않음 (QMD doesn't return context)
설정 직후에는 QMD가 비어 있으며, 어시스턴트(assistant)가 마치 기억이 없는 것처럼 응답합니다. 이는 정상입니다. 임베딩(Embeddings)은 상호작용을 함에 따라 축적됩니다. 그저 계속 대화를 이어가기만 하면 됩니다.
게이트웨이 토큰 불일치 (Gateway token mismatch)
게이트웨이가 알지 못하는 상태에서 토큰을 재생성할 경우 발생할 수 있습니다:
agenix -e secrets/openclaw-gateway-token.age
systemctl --user restart openclaw-gateway
결론 (Conclusion)
저녁 한나절이 걸렸지만, 그만한 가치가 있었습니다. 이제 저는 우리가 대화한 내용을 기억하고 단 한 번의 명령으로 배포할 수 있는 재현 가능한(reproducible) AI 어시스턴트를 갖게 되었습니다. 설정은 어떤 머신에서도 동일합니다: 리포지토리(repo)를 클론(clone)하고, nixos-rebuild를 실행하면 끝입니다.
코드는 GitHub에서 확인할 수 있습니다. 시크릿(secrets)을 자신의 것으로 교체하고 빌드하세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기

