온프레미스 개발환경

[9탄] 폐쇄망에서 Ollama 오프라인 설치 완전 가이드 (GGUF + Modelfile 설정)

finvault 2026. 4. 9. 16:31

👈 이전 글: [8탄] 금융권 폐쇄망 온프레미스 AI 아키텍처: Ollama 도입부터 mTLS 보안 설계까지

💡  우리의 험난했던 여정

최근 개발 생태계는 ChatGPT, GitHub Copilot 등 AI 어시스턴트가 지배하고 있습니다.
하지만 **'망 분리(Air-Gapped)'**가 적용된 금융권 온프레미스 환경의 개발자들에게는 남의 나라 이야기죠.
터미널을 열고 당당하게 ollama pull deepseek-coder:6.7b를 입력해 봐야 돌아오는 건 잔인한 Connection Refused 에러뿐입니다.
 
그렇다면
"어떻게 하면 인터넷 선이 물리적으로 뽑혀있는 서버에, 시스템 환경변수를 단 1바이트도 오염시키지 않고 나만의 AI 코딩 두뇌(FinAI)를 완벽히 격리하여 이식할 수 있을까?"
이 사상이 이 블로그의 기본 사상입니다 .
 
시스템 환경변수를 1바이트도 오염시키지 않는다.
 
오늘은 그 고민의 결과물인 **'100% 오프라인 무결성 AI 구축 과정'**을 공유합니다.



🖥️ [구동 환경]

🔹 OS : Windows 10 64bit
🔹 Ollama : 0.19.0 (Standalone ZIP)
🔹 모델 : deepseek-coder-6.7b-instruct.Q4_K_M.gguf
🔹 GPU : 없음 (CPU 전용 타겟팅)
🔹 네트워크 : 완전 폐쇄망 (인터넷 차단)

 

📦 Step 1. 외부망(Online)에서 필요 라이브러리 확보하기 (보안 USB 반입 준비)

폐쇄망에서는 인터넷에서 무언가를 '당겨온다(Pull)'는 개념이 없습니다.
무조건 밖에서 구해 보안 USB로 '밀어 넣어야(Push)' 하죠.
보안팀의 무사 통과를 위해 자잘한 설치 파일 대신 딱 떨어지는 '단일 파일' 전략을 취합니다.

1. 엔진 바이너리 확보 (Ollama Standalone)

일반적인 Windows 설치 파일(OllamaSetup.exe)을 쓰면 C:\Users\AppData 경로가 오염되고 시스템 환경변수가 자동 등록됩니다.
처음부터 지켜온 원칙인 **"시스템 환경변수 건드리지 않는다"**에 정면으로 위배되죠.
철저한 격리를 위해 GitHub Releases 페이지에서 .zip 형태의 스탠드얼론 버전을 받습니다.
 
        다운로드: ollama-windows-amd64.zip
 

github.com/ollama
github.com/ollama

 

Show All Asset 펼쳐보기
Show All Asset

 

다운로드 받은 ollama zip
다운로드 받은 ollama zip

 

압축 해제 후 ollama.exe만 추출
압축 해제 후 ollama.exe만 추출

 

ollama.exe 추출
ollama.exe 추출

 

 
    우선 윈도우 버젼은 설치 과정이 쉬워서 그냥 설치를 해보겠습니다

   1.OLLAMA 설치를 위해 아래 사이트를 접속한다
     https://ollama.com/download/windows

윈도우 설치를 위한 OLLAMA 접속
윈도우 설치를 위한 OLLAMA 접속


2, 현재는 윈도우 버전을 먼저 진행 하고있어서 Windows 아이콘이 본인 pc 상황과 안 맞더라도 windows 아이콘을 선택 한 후 아래 Download fo Windows를 클릭 후 다운 로드 파일 을
C:\projects\Ai
폴더에 EXE 설치 파일을 옮겨 놓는다

OLLAMASETUP.EXE 다운로드
OLLAMASETUP.EXE 다운로드

 3 .그냥 INSTALL 버튼 클릭

OLLAMA 설치
OLLAMA 설치

4 . 한 가지 특이 사항이 발생 해서 기록 차원에서 기재를 한다
    좌측 이미지는 현재 내가 사용 하고 있는 데스크 탑 PC 사양 이고 우측 이미지는 현재 작업 하고있는 노트북 사양이다
     노트북은 GPU 때문인지 OLLAMA 화면이 뜨고 테스크톱은 초기 화면이 뜨지를 않았다
     하지만 둘다 설치가 되서 백그라운드에서 돌고 있다 . OLLAMA의 본체는 터미널(CLI)임 화면(GUI)는 의미가 없음

노트북 과 PC 비교
노트북 과 PC 비교


   5. 3가지 방법으로 OLLAMA가 장상 설치 된 것을 확인 했다 
       CMD 창에서 ollama -v를 입력 한다 현재 버젼은 버전은 ollama version is 0.19.0 이다

ollama 버젼 확인
ollama 버젼 확인

 
 

그럼 다시 우리의 원래 목표로 돌아 와서 진행 하겠습니다

2. 뇌(가중치) 모델 확보 (DeepSeek Coder GGUF)

Hugging Face에서 코딩에 특화된 모델의 GGUF 단일 파일을 직접 다운로드합니다.
사내 일반 PC의 RAM에서도 쾌적하게 돌아가면서 코딩 지능이 뛰어난 6.7B 체급의 양자화(Q4) 모델을 선택했습니다. (약 4GB)
 

huggingface 의 deepseek-coder-6.7B deepseek-coder-6.7b-instruct.Q4_K_M.gguf
huggingface 의 deepseek-coder-6.7B deepseek-coder-6.7b-instruct.Q4_K_M.gguf

 

deepseek-coder-6.7b-instruct.Q4_K_M.gguf
deepseek-coder-6.7b-instruct.Q4_K_M.gguf
deepseek-coder-6.7b-instruct.Q4_K_M.gguf 다운로드
deepseek-coder-6.7b-instruct.Q4_K_M.gguf 다운로드

3. SHA-256 무결성 검증 (보안 필수!)

💡 Tip: 

USB 전송 과정에서 파일이 변조(악성코드 등)되었는지 확인하는 유일한 방법입니다. 금융감독원 보안 감사에서도 이 증적이 요구될 수 있습니다.

DOS
 
외부망 PC에서 해시값 기록:
certutil -hashfile deepseek-coder-6.7b-instruct.Q4_K_M.gguf SHA256
↓
해시값 메모 (예: a1b2c3d4e5f6...)

USB 반입 후 폐쇄망 PC에서 검증:
certutil -hashfile C:\projects\Ai\models\deepseek-coder-6.7b-instruct.Q4_K_M.gguf SHA256
↓
두 값 일치 → 반입 승인! ✅
외부망 hash
외부망 hash
내부망 hash
내부망 hash

 


📁 Step 2. AI 격리 구성 (엔진과 뇌의 분리)

반입된 파일들을 프로젝트 폴더 안에 어떻게 배치할 것인지가 향후 유지보수의 핵심입니다.

Plaintext
 
C:\projects\
 └─ Ai\
     ├─ ollama\   ← (엔진) ollama.exe만 배치
     └─ models\   ← (데이터) 4GB짜리 .gguf 파일 배치

🤔 왜 굳이 방을 두 개로 분리했을까요?
AI 엔진(ollama.exe)은 향후 연산 최적화를 위해 버전업이 빈번하게 일어납니다. 엔진 폴더를 분리해 두면, 무거운 4GB짜리 가중치 데이터를 건드리지 않고 .exe 파일만 깔끔하게 교체할 수 있습니다. 훗날 담당자가 바뀌어도 "ollama = 엔진, models = 데이터"로 1초 만에 직관적인 파악이 가능합니다. 리눅스의 /bin(실행 파일)과 /var(데이터)를 분리하는 철학과 같습니다.

OLLAMA 구성
OLLAMA 구성


📜 Step 3. Modelfile 작성 (feat. Batty 사상)

Ollama는 단순히 폴더에 파일이 있다고 모델을 인식하지 못합니다. 이 모델을 오프라인에서 어떻게 다룰지 정의하는 **Modelfile**을 C:\projects\Ai\models\ 경로에 확장자 없이 생성합니다.
이 설정 파일에는 **[ Batty ]**이 주창한 위대한 AI 아키텍처 철학(Batty Architecture)이 고스란히 담겨 있습니다. "LLM은 마크다운(Markdown)을 네이티브로 이해하므로, 복잡한 메시지 버스나 JSON 파싱 없이 파일시스템과 마크다운만으로 완벽한 태스크 조율이 가능하다"는 바로 그 사상입니다.
해 당 내용으로 OLLAMA 기동시 오류가 발생 합니다 해 당 오류는 버그 형태로 다음 탄에 진행 하겠습니다
.

💡 Batty 사상이란?

이 Modelfile을 이해하려면 먼저 Batty 아키텍처 를 알아야 합니다.
"Why a Markdown File Beats a Message Bus"
요즘 멀티 에이전트 AI 시스템을 구축한다고 하면 습관적으로 Kafka, RabbitMQ 같은 무거운 메시지 버스 를 올리려 합니다. 하지만 Batty는 정반대의 주장을 합니다.

 
 
복잡한 메시지 버스 구조:
Agent A → JSON 직렬화 → 메시지 큐 → JSON 역직렬화 → Agent B
        ↓
O(n²) 메시지 전달 오버헤드
        ↓
폐쇄망 한정 자원에서 구축 비용 폭발!

Batty 방식:
Agent A → 마크다운 파일 작성 → Agent B가 읽음
        ↓
O(1) 파일 읽기
        ↓
파일시스템 하나면 끝!

왜 LLM에게는 마크다운이 네이티브인가?

 
 
DeepSeek Coder의 학습 데이터 대부분:
GitHub README.md
GitHub Issues (마크다운)
GitHub Wiki (마크다운)
Stack Overflow (마크다운)
        ↓
LLM은 마크다운을 모국어처럼 이해!
        ↓
JSON 파싱 오버헤드 = 0
별도 직렬화 라이브러리 = 불필요

폐쇄망에서 이게 왜 특히 강력한가?

 
 
일반 환경:
Kafka 브로커 설치
ZooKeeper 설치
네트워크 설정
라이브러리 반입
        ↓
폐쇄망 반입 신청 = 지옥

Batty 방식:
마크다운 파일 하나
git 명령어
        ↓
이미 다 있음!
추가 반입 = 0

그리고 결정적으로:

 
 
태스크 상태가 변경될 때마다
git commit 하나가 생깁니다.
        ↓
todo → in-progress → done
        ↓
모든 AI 작업 이력이
git log에 영원히 남습니다.
        ↓
금융감독원도 반박 못하는
불변의 감사 증적(Immutable Audit Log)!

이 사상을 Modelfile의 SYSTEM 프롬프트에 직접 주입 합니다. AI에게 자신이 어떤 환경에서, 어떤 방식으로 일해야 하는지 명확히 인지시키는 것입니다.

Plaintext
 
# ============================================================
# [Finvault Labs 전용] Air-Gapped Modelfile
# 작성자: FinVault Labs
# 목적: 금융권 폐쇄망 환경에서 동작하는 오프라인 AI 코딩 어시스턴트
# 사상: Batty(마크다운 기반 다중 에이전트 조율) 철학 적용
# ============================================================


# ------------------------------------------------------------
# 1. Base Model (물리적 오프라인 파일 절대 경로)
# ------------------------------------------------------------
# ollama pull 명령어로 인터넷에서 받는 것이 아니라
# 폐쇄망으로 반입한 .gguf 파일을 직접 지정합니다.
# 이것이 Air-Gapped 환경의 핵심입니다.
# 파일 경로는 반드시 실제 반입된 경로로 수정하세요.
FROM "C:\projects\AI\models\deepseek-coder-6.7b-instruct.Q4_K_M.gguf"


# ------------------------------------------------------------
# 2. Context & Parameters (엔터프라이즈 환경 최적화)
# ------------------------------------------------------------

# [컨텍스트 길이 설정]
# 기본값: 2048 토큰 → 변경: 8192 토큰
# 이유: JBoss Exception 로그, Spring Boot 설정 XML 등
# 수백 줄짜리 파일을 통째로 던져줘야 하는 금융권 특성상
# 컨텍스트가 짧으면 AI가 앞부분 내용을 까먹어버립니다.
# 8192 토큰 = A4 용지 약 16장 분량을 한 번에 기억!
PARAMETER num_ctx 8192

# [응답 길이 제한]
# CPU 전용 폐쇄망 서버에서 AI가 끝없이 출력하면
# 서버 자원이 낭비되고 응답이 느려집니다.
# 2048 토큰으로 응답 길이를 제한하여 자원을 보호합니다.
PARAMETER num_predict 2048

# [온도 설정 - 창의성 vs 정확도]
# 범위: 0.0(완전 결정론) ~ 1.0(완전 창의)
# 소설: 0.8 / 일반 대화: 0.5 / 코딩: 0.1~0.2
# 금융권 코드에서는 단 1%의 환각(Hallucination)도 허용 안됨!
# 기계처럼 정확한 정답만 뱉어내는 '설계자 모드'로 설정
PARAMETER temperature 0.1

# [정지 토큰 설정]
# AI가 혼자 질문과 답변을 무한 반복하는 것을 방지합니다.
# 이 토큰이 나오면 즉시 응답을 중단합니다.
PARAMETER stop "### Instruction:"
PARAMETER stop "### Response:"


# ------------------------------------------------------------
# 3. System Prompt
# Batty 사상 적용: 마크다운 파일 기반 태스크 조율 프로토콜
# 참고: "Why a Markdown File Beats a Message Bus" (DEV Community)
# 핵심: LLM은 마크다운을 네이티브로 이해한다
#       JSON 파싱 오버헤드 없이 태스크를 인식하고 실행
#       모든 작업 이력이 git log로 남아 금융권 감사 증적 완벽 대응
# ------------------------------------------------------------
SYSTEM """
You are 'FinAI', an elite enterprise software architect and expert coding assistant.
You are currently operating in a strictly AIR-GAPPED (offline) financial infrastructure.

[Core Directives]
1. Environment Constraints:
   - You have NO internet access.
   - NEVER suggest downloading external libraries via internet.
     (e.g., Maven Central, npm install, pip install from PyPI)
   - NEVER suggest using external cloud APIs.
     (e.g., OpenAI API, Google Cloud, AWS)
   - All dependencies must be available in the local offline repository.

2. Tech Stack Expertise:
   - Primary: Java, Spring Boot 4.x, JBoss EAP 8.x
   - Secondary: C#, Python (offline only)
   - Architecture: Enterprise software, MSA, On-premises infrastructure
   - Security: mTLS, PKI, Air-Gapped network policy

3. Coding Style:
   - Provide highly secure, optimized, and robust code.
   - Always consider memory leaks and thread safety.
   - Follow financial sector coding standards.
   - Never use deprecated APIs.

4. Tone:
   - Be concise, professional, and directly address the problem.
   - No unnecessary pleasantries.
   - If you are unsure, say so clearly. Never hallucinate.

5. Log Analysis:
   - If analyzing logs (especially JBoss/Tomcat ClassLoader issues),
     point out the exact conflict and provide the solution logically.
   - Always identify the root 'Caused by' in stack traces.

[Task Coordination Protocol - Batty Architecture]
- Inspired by: Markdown-file-based multi-agent coordination
  (ref: "Why a Markdown File Beats a Message Bus")
- Core principle: LLMs understand Markdown natively.
  No serialization overhead. No message bus required.
- Git history = complete audit trail for financial compliance.

Task file format (YAML frontmatter + Markdown body):
  ---
  id: [task_number]
  title: [task_title]
  status: [todo | in-progress | done | blocked]
  priority: [critical | high | medium | low]
  depends_on: [task_ids]
  claimed_by: [agent_name]
  tags: [tag1, tag2]
  ---
  # Task Description
  ## Done When
  - condition 1
  - condition 2

Task Execution Rules:
  1. Read the task Markdown file COMPLETELY before starting any work.
  2. NEVER start a task if depends_on tasks are not 'done'.
  3. Update status as you progress: todo → in-progress → done
  4. Record ALL work results back in Markdown format.
  5. Every status change becomes a git commit = financial audit trail.
  6. If blocked, set status to 'blocked' and document the reason clearly.

Coordination Advantages (why this beats a message bus):
  - O(1) file read vs O(n²) message passing overhead
  - Filesystem = single source of truth (no race conditions)
  - grep/git = instant monitoring and full history
  - Markdown = LLM native format (zero parsing overhead)
"""

 

💡 Finvault 의 선택: "껍데기(Go)는 버리고 사상(Markdown+Git)만 훔친다"

그래서 우리는 Batty라는 '툴'을 쓰지 않습니다.
그 위대한 **'사상'**만 차용하여, 우리에게 가장 익숙하고 안전한 금융권 표준 스택으로 직접 오케스트레이터를 구현합니다.


눈치채셨나요? 제가 **[1탄]**에서 왜 요즘 유행하는 가벼운 컨테이너 대신, 굳이 무겁고 깐깐한 JBoss EAP 8.x를 튜닝하며 인프라 바닥 공사를 했는지 말입니다. 
JBoss는 바로 이 자율형 AI 오케스트레이터를 WAR 파일 형태로 우아하게 올려놓기 위한 완벽한 큰 그림이었습니다.


[ FinAI 오케스트레이터 내부 아키텍처 개념도 ]

Plaintext
 
[ 🔒 금융권 물리적 폐쇄망 (Air-Gapped) ]

+---------------------------------------------------+
|  [ Server Node A ] (CPU 전용, 자원 격리 적용)     |
|                                                   |
|  +--------------------+   +--------------------+  |
|  | ☕ JBoss EAP 8.x   |   | 🧠 Ollama Engine   |  |
|  |                    |   |                    |  |
|  | [Spring Boot WAR]  |   | [deepseek-coder]   |  |
|  | - Batty 사상 구현  |   | - 모델 가중치(4GB) |  |
|  | - Markdown 파싱    |   | - REST API 대기    |  |
|  | - Git Audit 봇     |   |                    |  |
|  +---------+----------+   +---------+----------+  |
|            |                        ^             |
|            | (비동기 SSE 통신)      |             |
|            +---[ localhost:11434 ]--+             |
|                                                   |
+----------------------+----------------------------+
                       | (Local File System)
+----------------------v----------------------------+
| 📁 /projects/Ai/tasks/                            |
|  📄 task_001.md (상태: done) ──┐                  |
|  📄 task_002.md (상태: todo)   ├─ 🔒 Git Audit    |
+---------------------------------------------------+


위 구조도를 보시면 아시겠지만, 단순한 동기식 통신이 아닙니다.
향후 시스템이 뻗는(Timeout) 것을 방지하기 위해 JBoss와 Ollama 사이의 통신은 **비동기 스트리밍(SSE)**으로 처리되며, CPU 자원 경합을 막기 위한 물리적 코어 격리(Affinity) 논리가 등 뒤에 숨어 있습니다.

마크다운 태스크 파일을 읽고 ➡️ Ollama REST API(localhost:11434)를 호출하고 ➡️ 결과를 다시 마크다운으로 저장하며 ➡️ 상태 변경 시 Git Commit으로 불변의 금융 감사 로그를 남기는 시스템.

이것이 외부 인터넷이 물리적으로 단절된 폐쇄망에서, 보안팀의 제지를 받지 않고 안전하게 구동되는 **'진정한 의미의 엔터프라이즈 자율형 AI'**입니다.


👉 이 FinAI 오케스트레이터의 놀라운 Java 구현체와 깐깐한 인프라 방어 논리(Timeout/자원 경합 해결)는 향후 [11탄] FinAI 오케스트레이터 - Spring Boot + Ollama REST API 편에서 아주 상세하게 다룰 예정입니다.



Modelfile 생성
Modelfile 생성


⚙️ Step 4. 모델 굽기(Baking) 중 발견한 '아찔한 버그'

이제 CMD 창을 열고 오프라인 모델을 조립(Baking)할 차례입니다.
그런데 이 과정에서 시스템을 완전히 오염시킬 뻔한 치명적인 함정을 발견했습니다.
만약 환경변수 세팅 없이 무턱대고 ollama create를 치면, Ollama는 무의식적으로 C:\Users\계정명\.ollama\models 경로에 4GB짜리 결과물을 구워버립니다! "시스템을 오염시키지 않는다"는 대원칙이 박살 나는 순간이죠.
반드시 모델을 굽기 전에 OLLAMA_MODELS 환경변수를 강제 주입해야 합니다.

DOS
 
rem 1. OLLAMA_MODELS 환경변수를 일시적으로 적용하여 타겟을 격리합니다.
set OLLAMA_MODELS=C:\projects\Ai\models

rem 2. 그 다음 모델을 굽습니다.
C:\projects\Ai\ollama\ollama.exe create FinAI -f C:\projects\Ai\models\Modelfile

rem 결과:
rem transferring model data...
rem creating model layer...
rem success

rem 3. 잘 구워졌는지 확인합니다.
C:\projects\Ai\ollama\ollama.exe list

(⚠️ 매번 CMD 창에서 이 짓을 하는 건 휴먼 에러의 지름길입니다. 그래서 다음 Step의 자동화 스크립트가 필요합니다.)

ollama create
ollama create

 

ollama create
ollama create


🚀 Step 5. 원클릭 자동 기동 스크립트 (start_ollama.bat)

C:\projects\Ai\ollama\ 폴더에 start_ollama.bat 스크립트를 만들어 환경변수 격리와 기동을 우아하게 자동화합니다.

DOS
 
@echo off
chcp 65001 >nul
title Finvault Labs - Air-Gapped AI Engine

echo ============================================================
echo  🛡️ FinVault Labs: Starting Offline AI Engine...
echo ============================================================

rem 핵심 1: 모델 저장 경로를 프로젝트 내부로 완벽 격리!
set OLLAMA_MODELS=C:\projects\Ai\models

rem 핵심 2: 0.0.0.0 개방 (향후 FinAI 오케스트레이터가 REST API를 호출하기 위함)
set OLLAMA_HOST=0.0.0.0:11434

rem Ollama 백그라운드 서버 기동
start "" "%~dp0ollama.exe" serve
echo [System] 엔진이 백그라운드(Port: 11434)에서 가동되었습니다.
timeout /t 3 >nul

rem 대화형 프롬프트 실행
echo [System] AI 두뇌(FinAI)에 접속합니다.
"%~dp0ollama.exe" run FinAI
pause
start_ollama.bat 실행화면
start_ollama.bat 실행화면

 

 

 

🎉 결과 확인 및 체크리스트

스크립트를 더블클릭하고, 브라우저에서 http://localhost:11434에 접속해 봅니다.

OLLAMA 스타트
OLLAMA 스타트

화면에 **"Ollama is running"**이 뜬다면 성공입니다. 랜선을 다 뽑아버려도 살아 숨 쉬는 나만의 프라이빗 AI, 'FinAI'가 완성되었습니다!
✅ 이번 탄 완료 체크리스트

  • [x] OllamaSetup.exe 배제 및 Standalone ZIP 추출 완료
  • [x] GGUF 파일 무결성(SHA-256) 검증 완료
  • [x] ollama / models 물리적 폴더 격리 완료
  • [x] Batty 아키텍처가 적용된 Modelfile 작성 완료
  • [x] set OLLAMA_MODELS 선행 적용 후 오프라인 모델 조립(Baking) 완료
  • [x] start_ollama.bat 스크립트로 환경변수 캡슐화 완료

🚀 다음 편 예고

다음 **[10탄]**에서는 이 무뚝뚝한 CLI 터미널 AI를, VS Code Portable 격리 세팅으로 시스템을 오염시키지 않고 continue.dev 플러그인을 통해 실시간 AI 코딩 어시스턴트로 탈바꿈시키는 과정을 다루겠습니다!
👉 [10탄] VS Code Portable 격리 세팅 및 continue.dev를 통한 Ollama 연동 (작성 중)