새로운 기술은 언제나 환영이야! 👋

Java Spring 10년, DevOps 5년 경력의 소프트웨어 엔지니어입니다. 호치민에서 새로운 기회를 찾으며 기술적인 인사이트를 기록합니다.

Mac Studio M1 DFU Restore Log

Device: Mac Studio M1 (Mac13,1) ECID: 0x1249E03685801 Host: Mac Mini M4 (macOS 26.4.1) Tool: Apple Configurator 2 / cfgutil 2.19 Date: 2026-04-17 Issue Asahi Linux 설치 후 iBoot 손상. 주황색 점멸등 (DFU Mode) 상태. Symptom 전원 버튼 시 흰색 LED 0.5초 ON → 1초 OFF 반복 (부팅 루프) 1TR (One True Recovery) 진입 불가 모니터 화면 무반응 (Apple 로고 미표시) Attempts # Method Result 1 Apple Configurator → Revive Device Error 2006 (66%) 2 Apple Configurator → Restore Device Error 2006 (66%) 3 cfgutil -f revive Error 2006 (66%, step 4/4) 4 cfgutil -f restore (포트 변경) Error 2006 (66%) 5 Mac Mini 재부팅 + 포트 변경 후 cfgutil -f restore Error 2006 (50%) 6 cfgutil -f restore -I <IPSW> --ignore-boot-transition-timeout Error 2006 (50%, step 2/2) 7 USB-C Hub 경유 연결 DFU 디바이스 미인식 8 cfgutil --verbose -f restore Error 2006 (66%, verbose 로그 수집) Key Finding Error 2006 발생 원인: DFU → Recovery Mode 전환 시 USB 재연결(reenumeration) 실패. ...

2026년 4월 17일 · 3 min · Crong

Cloudflare AI Gateway 사용 예제

Cloudflare AI Gateway란? Cloudflare AI Gateway는 여러 AI 제공자(OpenAI, Anthropic, Google AI Studio 등)의 API를 단일 엔드포인트로 통합 관리할 수 있는 프록시 서비스다. 사용량 모니터링, 캐싱, 속도 제한, 로깅 등의 기능을 제공한다. 사전 준비 다음 환경 변수들이 필요하다: 변수명 설명 CLOUDFLARE_ACCOUNT_ID Cloudflare 계정 ID CLOUDFLARE_AI_GATEWAY_NAME AI Gateway 이름 CF_AIG_TOKEN Cloudflare AI Gateway 토큰 참고: Cloudflare AI Gateway 대시보드에서 Provider를 등록하고 API 키를 미리 설정하면, CLI 요청 시 Authorization이나 x-goog-api-key 헤더를 별도로 추가하지 않아도 Cloudflare가 자동으로 인증을 처리한다. ...

2026년 3월 30일 · 2 min · Crong

Tailscale + Caddy로 HTTPS 리버스 프록시 구성하기

제목 Tailscale + Caddy로 HTTPS 리버스 프록시 구성하기 개용 내부 네트워크의 레거시 서비스를 안전하게 외부에서 접근해야 할 때가 많습니다. 일반적으로는 VPN을 통해 직접 접근하거나, 공개 IP와 도메인을 할당받아 Nginx/Traefik 같은 리버스 프록시를 구성합니다. 하지만 이 방식은 방화벽 규칙 관리, SSL 인증서 갱신, 보안 노출 등 여러 가지 복잡성을 수반합니다. Tailscale Serve와 Caddy를 조합하면 이 문제를 매우 간단하게 해결할 수 있습니다. Tailscale이 HTTPS 종료(Termination)를 담당하고, Caddy가 경로 기반 라우팅을 처리하는 아키텍처입니다. ...

2026년 2월 26일 · 6 min · Crong

OpenCode vs ClaudeCode vs OpenClaw vs Mods vs Cline vs Zed vs Typing Mind

제목 OpenCode vs ClaudeCode vs OpenClaw vs Mods vs Cline vs Zed vs Typing Mind 내용 코딩을 정액제 Z.ai Coding Plan PRO 를 구매후 이런 저런 툴들을 테스트해봄. Coding Plan 이기는 하지만 MCP 를 연결해서 쓰니깐 일반적인 질문을 해도 생각보다 잘 응답해줌. 요약 툴 유형 장점 단점 사용 OpenCode 터미널 기반 다양한 모델 선택이 가능 특별한 단점 없음 계속 사용할거 같음 다만 Plan B ClaudeCode 터미널 기반 똑똑함 타사 모델 사용 불편 이제 니가 Plan A OpenClaw AI 비서 기능 많음 개발용으로 쓰기에는 비적합 좋은 장남감 Mods Pipeline 기반 CLI Pipeline 사용 가능 오로지 CLI로만 동작함 1가지 장점이 돋보임 Cline VS Code 확장 다양한 모델 선택 가능, 쉬운 사용 멍첨함 안써 Zed Text Editor 깔끔하고 빠른 UI VSCode와 다름 지금 이걸로 글쓰고 있음 Typing Mind Web 기반 복수 모델 동시 테스트 가능,설치 불필요, 클라우드 저장 Local LLM 테스트시 CORS, Mixed Context 이슈 복수 모델 테스트용으로 장점이 확실함 OpenCode 장점: ...

2026년 2월 11일 · 2 min · Crong

OpenCode, Cline, Mods 에 MCP Setup

제목 MCP 설정하기 내용 OpenCode, Cline, Mods 에 MCP 설정하기 OpenCode # ~/.config/opencode/opencode.json { "$schema": "https://opencode.ai/config.json", "permission": { "read": { "*.env": "deny", "*": "allow" }, "glob": "allow", "grep": "allow", "list": "allow", "task": "allow", "external_directory": "allow", "todoread": "allow", "webfetch": "allow", "websearch": "allow", "codesearch": "allow", "lsp": "allow", "doom_loop": "allow", "skill": "allow", "edit": "deny", "question": "allow", "bash": { "rm *": "deny", "git rm *": "deny", "cp *": "ask", "mv *": "ask", "git status": "allow", "git log": "allow", "git diff": "allow", "git pull*": "ask", "git reset*": "ask", "git checkout*": "ask", "git *": "ask", "ls *": "allow", "cat *": "allow", "head *": "allow", "tail *": "allow", "grep *": "allow", "mkfs*": "deny", "shred *": "deny", "dd *": "deny", "| xargs rm": "deny", "-delete": "deny", "-exec delete": "deny", "-exec rm *": "deny", "find *": "ask", "*": "ask" } }, "mode": { "plan": { "permission": { "question": "allow", "bash": { "git commit *": "ask", "git rm *": "deny", "git push *": "deny", "git *": "allow", "*": "ask" } } }, "build": { "permission": { "bash": { "rm *": "ask", "cp *": "ask", "mv *": "ask", "find *": "ask", "git rm *": "ask", "git push *": "ask", "git reset *": "ask", "git *": "allow", "*": "allow" }, "edit": { "*.env": "deny", "*": "allow" }, "todowrite": "allow" } } }, "provider": { "zai-coding-plan": { "options": { "apiKey": "{{ZAI_API_KEY}}", "timeout": 900000, "setCacheKey": true } }, "mcp": { "github": { "type": "local", "command": ["mcp-server-github"], "environment": { "GITHUB_PERSONAL_ACCESS_TOKEN": "{{GITHUB_PERSONAL_ACCESS_TOKEN}}" } }, "📅⏰": { "type": "local", "command": ["mcp-server-time", "--local-timezone=Asia/Ho_Chi_Minh"] }, "🖥️📂": { "type": "local", "command": [ "mcp-server-filesystem", "/Users/crong" ] }, "🖥️🐏": { "type": "local", "command": ["mcp-server-memory"] }, "🤔💭": { "type": "local", "command": [ "mcp-server-sequential-thinking" ] }, "Ⓜ️🎭": { "type": "local", "command": ["npx", "-y", "@playwright/mcp@latest"] }, "whistle-mcp": { "type": "local", "command": ["whistle-mcp", "--host=127.0.0.1", "--port=8888"] }, "Z.ai🖼️": { "type": "local", "command": ["npx", "-y", "@z_ai/mcp-server"], "environment": { "Z_AI_API_KEY": "{{ZAI_API_KEY}}", "Z_AI_MODE": "ZAI" } }, "Z.ai🌿": { "type": "remote", "url": "https://api.z.ai/api/mcp/zread/mcp", "headers": { "Authorization": "Bearer {{ZAI_API_KEY}}" } }, "Z.ai🔎": { "type": "remote", "url": "https://api.z.ai/api/mcp/web_search_prime/mcp", "headers": { "Authorization": "Bearer {{ZAI_API_KEY}}" } }, "Z.ai🤲": { "type": "remote", "url": "https://api.z.ai/api/mcp/web_reader/mcp", "headers": { "Authorization": "Bearer {{ZAI_API_KEY}}" } } }, "plugin": ["opencode-ignore", "opencode-wakatime"] } Cline # ~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json { "mcpServers": { "github": { "command": "mcp-server-github" }, "💻📂": { "command": "mcp-server-filesystem", "args": ["/Users/crong"] }, "💻🐏": { "command": "mcp-server-memory" }, "📅⏰": { "command": "mcp-server-time" }, "🤔💭": { "command": "mcp-server-sequential-thinking" }, "Ⓜ️🎭": { "type": "stdio", "command": "npx", "timeout": 30, "args": [ "-y", "@playwright/mcp@latest" ], "disabled": false }, "Z.ai🖼️": { "type": "stdio", "command": "npx", "args": ["-y", "@z_ai/mcp-server"], "env": { "Z_AI_API_KEY": "{{ZAI_API_KEY}}", "Z_AI_MODE": "ZAI" }, "autoApprove": [ "ui_to_artifact", "extract_text_from_screenshot", "diagnose_error_screenshot", "understand_technical_diagram", "analyze_data_visualization", "ui_diff_check", "analyze_image", "analyze_video" ] }, "Z.ai🔎": { "type": "streamableHttp", "url": "https://api.z.ai/api/mcp/web_search_prime/mcp", "headers": { "Authorization": "Bearer {{ZAI_API_KEY}}" } }, "Z.ai🤲": { "type": "streamableHttp", "url": "https://api.z.ai/api/mcp/web_reader/mcp", "headers": { "Authorization": "Bearer {{ZAI_API_KEY}}" } }, "Z.ai🌿": { "type": "streamableHttp", "url": "https://api.z.ai/api/mcp/zread/mcp", "headers": { "Authorization": "Bearer {{ZAI_API_KEY}}" } } } } Mods # ~/Library/Application Support/mods/mods.yml default-api: z-ai default-model: glm-4.7 format-text: markdown: 'Format the response as markdown without enclosing backticks.' json: 'Format the response as json without enclosing backticks.' mcp-servers: github: command: "mcp-server-github" env: - "GITHUB_PERSONAL_ACCESS_TOKEN={{GITHUB_PERSONAL_ACCESS_TOKEN}}" 🖥️📂: command: "mcp-server-filesystem" args: - "/Users/crong" 🖥️🐏: command: "mcp-server-memory" 📅⏰: command: "mcp-server-time" args: - "--local-timezone=Asia/Ho_Chi_Minh" 🤔💭: command: "mcp-server-sequential-thinking" Ⓜ️🎭: command: "npx" args: - "@playwright/mcp@latest" Z.ai🖼️: command: "zai-mcp-server" env: - "Z_AI_API_KEY={{ZAI_API_KEY}}" - "Z_AI_MODE=ZAI" Z.ai🔎: command: "mcp-remote" args: - "https://api.z.ai/api/mcp/web_search_prime/mcp" - "--header" - "Authorization: Bearer {{ZAI_API_KEY}}" Z.ai🤲: command: "mcp-remote" args: - "https://api.z.ai/api/mcp/web_reader/mcp" - "--header" - "Authorization: Bearer {{ZAI_API_KEY}}" Z.ai🕎: command: "mcp-remote" args: - "https://api.z.ai/api/mcp/zread/mcp" - "--header" - "Authorization: Bearer {{ZAI_API_KEY}}" mcp-timeout: 60s roles: "default": [] "empty": [] "engineer": - "당신은 시니어 엔지니어(Java Spring, DevOps) 이자 기술 아키텍트인 'StackOverflow'입니다." - "모든 답변은 다음 'Verification Protocol'을 강제로 준수해야 합니다:" - "1. [부정적 전제] 무조건 '예'라고 하지 마십시오. OS별(Windows/macOS/Linux) 기능 제약이나 삭제된 버전의 가능성을 먼저 언급하십시오." - "2. [팩트 체크] UI 메뉴 경로는 환각이 심하므로, 설정 파일(Plist, JSON, Config)의 키 이름이나 필드명을 우선적으로 제공하십시오." - "3. [실시간 검색] 추측하지 마십시오. 공식 문서(Changelog)나 이슈 트래커를 검색한 결과만 요약하여 제공하십시오." - "4. [3-Strike Rule] 동일한 잘못된 정보를 2회 반복하면 즉시 한계를 인정하고 대화를 중단하거나 접근 방식을 변경하십시오." - "5. [응답 형식] 반드시 '🔍 상황 분석', '🏗️ 해결 방안', '🛡️ 검증 프로토콜', '💡 전문가적 견해' 순으로 답변하고, 최소 3가지 옵션을 시각화하여 제시하십시오." format: false role: "engineer" raw: false quiet: false temp: 1.0 topp: 1.0 topk: 50 no-limit: false word-wrap: 80 include-prompt-args: false include-prompt: 0 max-retries: 5 fanciness: 10 status-text: Loading theme: catppuccin max-input-chars: 12250 max-completion-tokens: 100 apis: google-gemma: base-url: https://generativelanguage.googleapis.com/v1beta/openai/ api-key: "" api-key-env: GOOGLE_API_KEY_MODS models: gemma-3-27b-it: aliases: ["g3-27b", "g3l"] max-input-chars: 392000 gemma-3-12b-it: aliases: ["g3-12b", "g3m"] max-tokens: 2048 max-input-chars: 392000 gemma-3-4b-it: aliases: ["g3-4b", "g3s"] max-input-chars: 392000 # Gemma 3n (모바일/온디바이스 최적화 모델) gemma-3n-e2b-it: aliases: ["g3-2b", "g3o"] max-input-chars: 131000 # Gemma 3 초경량 모델 gemma-3-1b-it: aliases: ["g3-1b", "g3n"] max-input-chars: 98000 z-ai: base-url: https://api.z.ai/api/coding/paas/v4 api-key: api-key-env: ZAI_API_KEY_MODS models: glm-4.7: aliases: ["glm-4.7","glm"] max-input-chars: 200000

2026년 2월 9일 · 4 min · Crong

AI 와 함께하는 2026년 1월 여행기: 호치민 → 인천 → 선전 → 광저우 -> 호치민

제목 AI 와 함께하는 2026년 1월 여행기: 호치민 → 인천 → 선전 → 광저우 -> 호치민 내용 2026년 1월, 호치민에서 출발하여 인천 → 선전 → 광저우를 거쳐 다시 호치민으로 돌아오는 여행을 다녀옴. 왜? 가깝고도 먼나라 🇯🇵 인데 요즘은 🇨🇳 인거 같음 그렇게 생각 만 하고 있다가. 🇻🇳 비자 만료 기간도 있고, 아산병원도 가야하고, 🇨🇳 무비자때 한번 가보고 싶기도 해서 가봄. 예전에 무비자 안될때 환승으로 선전에 온적 있지만 그건🙅. 선전 (深セン)에서의 해보고 싶었던거 교통·결제·식사 등 일상 생활 경험 화창베이 (华强北)에서 장비 주변기기 구매 소유한 하드웨어의 활용성을 올릴 수 있는 액세서리 소유한 소프트웨어의 생산성을 올릴 수 있는 하드웨어 광저우 (広州)에서의 해보고 싶었던거 전통적이고 북적이는 현지 풍경 관찰 지역 특유의 문화와 분위기 체험 여행 일정 Day 1: 호치민 → 인천 (2026-01-20) 항목 상세 출발 2026-01-20 02:40 탄손누트국제공항 T2 항공편 VJ862 (예약번호 47RW2F) 도착 2026-01-20 09:50 인천국제공항 T1 숙소 잠실역 인근 모텔 Day 2: 인천 → 선전 (2026-01-21) 항목 상세 출발 2026-01-21 13:55 인천국제공항 T1 항공편 CZ3090 (예약번호 PG0E6Q) 도착 2026-01-21 17:15 바오안국제공항 T3 숙소 한팅 호텔 (선전 화창 중앙공원) 공항 이동: ...

2026년 2월 4일 · 3 min · Crong

id_ed25519 와 passphrase 로 시작하는 보안강호하

제목 id_ed25519 와 passphrase 로 시작하는 보안 강호화 내용 이때 까지는 id_rsa 에 passphrase 없이 사용을 했는데, 요즘은 보안이 중요한 시대니깐 나도 보안을 한단계 레벨을 올려야 겠다. id_ed25519 를 사용하고 passphrase 를 등록해서 써보자, 불편하겠지 라고 생각했는데 결론은 사용자 OS 의 Client 장비에서 부팅후 1번만 입력 하면 된다. Linux ssh-agent 와 keychain 을 이용한 관리 eval $(keychain --eval id_rsa id_ed25519) Host * ForwardAgent yes # 내가 클라이언트일 때 에이전트를 넘겨줌 AddKeysToAgent yes # 키 사용 시 로컬 에이전트에 등록 IdentityFile ~/.ssh/id_ed25519 macOS 자체 암호화 앱 과 연동 해서 관리 ...

2026년 1월 17일 · 2 min · Crong

Vietnam Pharmacy Shopping List

제목 Vietnam Pharmacy Shopping List 내용 1 월에 한국 잠시 들어가는데 친구가 약을 사달라고함. 베트남 약국의 장점은 금액 도 있지만 의사처방이 필요한 약들도 처방전 없이도 구매가 가능하다. 품목명 (한국어) 개수 베트남어 명칭 (현지 구매용) 제조사 단위/용량 예상 가격 (VND) 한화 환산 (약) 비판텐 로션 1 개 Bepanthen Derma SensiDaily Bayer 200ml 450,000 ~ 520,000 약 24,700 ~ 28,600원 스트렙실 레몬 2 박스 Strepsils Honey & Lemon Reckitt 1박스 (100정) 220,000 ~ 250,000 약 12,100 ~ 13,800원 카타플람 50mg 2 개 Cataflam 50mg Novartis 1 vỉ (10정) 38,000 ~ 45,000 약 2,100 ~ 2,500원 디페린 0.1% 1 개 Differin 0.1% Adapalene Galderma 30g 튜브 260,000 ~ 360,000 약 14,300 ~ 19,800원 레모스 IB 1 개 Mentholatum Remos IB Rohto 10g 튜브 42,000 ~ 55,000 약 2,300 ~ 3,000원 디쪼 (소화제) 3 박스 Viên sủi Dizzo ICPA 1박스 (48정) 160,000 ~ 175,000 약 8,800 ~ 9,600원 베로카 10 개 Berocca Performance Bayer 1튜브 (10정) 75,000 ~ 95,000 약 4,100 ~ 5,200원 한국의 의료 시스템에 종사하는 모든분들께 감사 합니다.

2026년 1월 12일 · 1 min · Crong

MLX with OpenCode

제목 MLX 와 OpenCode 연동 하기: 10k 토큰은 버텨야 한다 내용 결론은 10k 토큰은 버텨야한다. 맥미니 M4 에서 MLX 로 mlx-community/Meta-Llama-3.1-8B-Instruct-8bit 올려서 OpenCode 로 연동 해봄. # Mac Mini 에서 돌릴수 있는 크고 아름다운 Model mlx_lm.server \ --model mlx-community/Meta-Llama-3.1-8B-Instruct-8bit \ --max-tokens 4096 \ --log-level DEBUG \ --host 0.0.0.0 \ --port 8080 OpenCode 와 MLX 연동 api-key 값은 아무거나 dumy 값 으로 아무거나 # ~/.config/opencode/config.json { "$schema": "https://opencode.ai/config.json", "provider": { "mlx": { "npm": "@ai-sdk/openai-compatible", "name": "MLX (local)", "options": { "baseURL": "http://127.0.0.1:8080/v1" }, "models": { "mlx-community/Meta-Llama-3.1-8B-Instruct-8bit": { "name": "MLX Llama" } } } } } 첫 Prompt 를 날려 테스트 하니깐 처음 명령어 Hi 날리때 10,000 토큰 넘개 날아감 와…. local 이라서 다행이다. 아무튼 10k 토큰 처리 하는데만 56초 걸림 M4 Mac mini는 초당 약 200250 토큰을 처리한다고함, 산술적으로 10,601 / 200 ≈ 50초 그래도 초당 190 정도 나오냉. 두번째 날리까 빨라짐 물론 두번째는 15 토큰만 날림, 캐시된 10,600 토큰 재사용 + 신규 15 토큰 연산 (약 23초 소요). 하지만 세번째 날리니깐 터짐. ...

2026년 1월 11일 · 2 min · Crong

Stow

제목 DotFile 을 관리 하자 내용 Linux 나 Mac 재설치 하거나 그러면 할게 너무 많아… 이거 좀 줄여보자 라고 젬미니 한테 물어보니, Stow 로 가보자. 구분 GNU Stow Chezmoi Yadm Home-manager 방식 Symlink Copy/Template Symlink/Copy Nix Store OS별 분기 어려움 (수동) 매우 강력 (템플릿) 쉬움 (파일명 매칭) 강력 (Nix 언어) 비밀값 관리 불가 지원 (연동 가능) 지원 (자체 암호화) 지원 (sops 연동) 난이도 매우 쉬움 보통 매우 쉬움 매우 높음 추천 대상 미니멀리스트 멀티 OS 사용자 Git 헤비 유저 IaC 전문가ㄷ 우선 잼미니 Gem 만들어야지 사고 모드 로 대화를 해서 이름, 설명, 요청 사항을 생성함. ...

2026년 1월 9일 · 6 min · Crong