 {"id":520200,"date":"2025-03-15T21:55:00","date_gmt":"2025-03-16T04:55:00","guid":{"rendered":"https:\/\/jorgep.com\/blog\/?p=520200"},"modified":"2026-04-15T14:29:06","modified_gmt":"2026-04-15T21:29:06","slug":"building-your-local-ai-lab-single-docker-image","status":"publish","type":"post","link":"https:\/\/jorgep.com\/blog\/building-your-local-ai-lab-single-docker-image\/","title":{"rendered":"Building Your Local AI Lab: Single Docker Image"},"content":{"rendered":"\n<h3 class=\"wp-block-heading\">Ollama, Open WebUI and n8n on Windows<\/h3>\n\n\n\n<p>Hosting your own AI models is no longer just for Linux gurus. With Docker Desktop on Windows, you can run a professional-grade automation and chat suite\u2014<strong>n8n<\/strong>, <strong>Ollama<\/strong>, and <strong>Open WebUI<\/strong>\u2014all on your own hardware.<\/p>\n\n\n\n<p>In this guide, we will set up a &#8220;Generic&#8221; configuration that makes it easy to handle changing IP addresses and specific hardware tweaks for <strong>NVIDIA<\/strong> or <strong>AMD<\/strong> GPUs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Docker Desktop:<\/strong> Installed and running with the <strong>WSL2 backend<\/strong>.<\/li>\n\n\n\n<li><strong>GPU Drivers:<\/strong> Ensure your NVIDIA (Adrenalin) or AMD (GeForce) drivers are up to date.<\/li>\n\n\n\n<li><strong>Local IP:<\/strong> Find your computer&#8217;s IP (open PowerShell and type <code>ipconfig<\/code>). We&#8217;ll assume it&#8217;s <code>192.168.x.x<\/code>.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: The Secret Sauce \u2013 The <code>.env<\/code> File<\/h2>\n\n\n\n<p>To prevent &#8220;Hardcoding Horror&#8221; (where you have to change your IP address in ten different places), we use a <code>.env<\/code> file. Create a folder named <code>ai-lab<\/code> and create a file inside it named <code>.env<\/code>:<\/p>\n\n\n\n<p>powerShell<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># .env file - Update LOCAL_IP if your router changes your address\nLOCAL_IP=192.168.4.24\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: The Universal <code>docker-compose.yml<\/code><\/h2>\n\n\n\n<p>This file is the &#8220;blueprint&#8221; for your lab. I have included commented-out sections for both <strong>NVIDIA<\/strong> and <strong>AMD<\/strong> users.<\/p>\n\n\n\n<p><strong>Note:<\/strong> By default, this script is set for <strong>AMD (ROCm)<\/strong>. If you have NVIDIA, simply follow the comments to swap the image and resource tags.<\/p>\n\n\n\n<p>YAML<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>services:\n  # --- OLLAMA (The AI Engine) ---\n  ollama:\n    # FOR AMD: Use ollama\/ollama:rocm\n    # FOR NVIDIA: Use ollama\/ollama:latest\n    image: ollama\/ollama:rocm \n    container_name: ollama\n    \n    # AMD SETTINGS: Un-comment the 'devices' section below\n    devices:\n      - \"\/dev\/kfd:\/dev\/kfd\"\n      - \"\/dev\/dri:\/dev\/dri\"\n\n    # NVIDIA SETTINGS: Un-comment the 'deploy' section below and comment out 'devices'\n    # deploy:\n    #   resources:\n    #     reservations:\n    #       devices:\n    #         - driver: nvidia\n    #           count: 1\n    #           capabilities: &#91;gpu]\n\n    volumes:\n      - ollama_data:\/root\/.ollama\n    ports:\n      - \"11434:11434\"\n    environment:\n      - OLLAMA_HOST=0.0.0.0\n    networks:\n      - ai-network\n    restart: unless-stopped\n\n  # --- OPEN WEBUI (The Interface) ---\n  open-webui:\n    image: ghcr.io\/open-webui\/open-webui:main\n    container_name: open-webui\n    ports:\n      - \"3000:8080\"\n    environment:\n      - OLLAMA_BASE_URL=http:\/\/ollama:11434\n    volumes:\n      - open_webui_data:\/app\/backend\/data\n    networks:\n      - ai-network\n    restart: unless-stopped\n\n  # --- n8n (The Automation Hub) ---\n  n8n:\n    image: n8nio\/n8n:latest\n    container_name: n8n\n    ports:\n      - \"5678:5678\"\n    environment:\n      - N8N_HOST=${LOCAL_IP}\n      - WEBHOOK_URL=http:\/\/${LOCAL_IP}:5678\/\n      - N8N_SECURE_COOKIE=false\n    volumes:\n      - n8n_data:\/home\/node\/.n8n\n      - .\/data:\/home\/node\/data\n    networks:\n      - ai-network\n    restart: unless-stopped\n\nnetworks:\n  ai-network:\n\nvolumes:\n  ollama_data:\n  n8n_data:\n  open_webui_data:\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Launching the Lab<\/h2>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li>Open <strong>PowerShell<\/strong> in your <code>ai-lab<\/code> folder.<\/li>\n\n\n\n<li>Run the command:PowerShell   <strong><em>docker compose up -d           <\/em><\/strong><\/li>\n\n\n\n<li>Wait a minute for the containers to pull. Docker will automatically read your <code>.env<\/code> file and &#8220;inject&#8221; your IP address into the n8n settings.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Windows Firewall (Crucial!)<\/h2>\n\n\n\n<p>Windows is protective. If you want to access your AI from a tablet or another laptop on your WiFi, you must allow these ports through the Firewall:<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li>Search for <strong>&#8220;Windows Defender Firewall with Advanced Security.&#8221;<\/strong><\/li>\n\n\n\n<li>Click <strong>Inbound Rules<\/strong> > <strong>New Rule<\/strong>.<\/li>\n\n\n\n<li>Select <strong>Port<\/strong> > <strong>TCP<\/strong> > Specific local ports: <code>3000, 5678, 11434<\/code>.<\/li>\n\n\n\n<li>Select <strong>Allow the connection<\/strong> and apply it to &#8220;Private&#8221; networks.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">How to Access Your New Lab<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Chat with AI:<\/strong> <code>http:\/\/[YOUR-IP]:3000<\/code> (Open WebUI)<\/li>\n\n\n\n<li><strong>Create Automations:<\/strong> <code>http:\/\/[YOUR-IP]:5678<\/code> (n8n)<\/li>\n\n\n\n<li><strong>API Access:<\/strong> <code>http:\/\/[YOUR-IP]:11434<\/code> (Ollama)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Pro-Tip: Hardware Verification<\/h3>\n\n\n\n<p>To ensure your <strong>AMD<\/strong> or <strong>NVIDIA<\/strong> card is actually doing the work:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Open <strong>Task Manager<\/strong> > <strong>Performance<\/strong> > <strong>GPU<\/strong>.<\/li>\n\n\n\n<li>In Open WebUI, ask the AI to &#8220;Write a 500-word essay on the future of robotics.&#8221;<\/li>\n\n\n\n<li>If you see the <strong>GPU Memory<\/strong> or <strong>Dedicated GPU Memory<\/strong> usage climb, your hardware acceleration is working!<\/li>\n<\/ul>\n\n\n\n<p>Next Download the Models into Ollama!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Command to Pull Gemma 4<\/h3>\n\n\n\n<p>Open your Windows terminal and run this command:<\/p>\n\n\n\n<p>Bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker exec -it ollama ollama pull gemma4:4b\n<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p><em>Happy Self-Hosting! By running this locally, your data never leaves your network, and you have no monthly subscription fees.<\/em><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>If you run into problems: <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Cleanup and Restart<\/h3>\n\n\n\n<p>To prevent port conflicts and get a clean start, run these in your terminal:<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Remove the failed containers:<\/strong>\n<ul class=\"wp-block-list\">\n<li>PowerShell\n<ul class=\"wp-block-list\">\n<li><code>docker compose down <\/code><\/li>\n\n\n\n<li><code>docker rm -f ollama open-webui n8n<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Start the new setup:<\/strong>\n<ul class=\"wp-block-list\">\n<li>PowerShell\n<ul class=\"wp-block-list\">\n<li><code>docker compose up -d<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>services:\n  # --- OPEN WEBUI ---\n  open-webui:\n    image: ghcr.io\/open-webui\/open-webui:main\n    container_name: open-webui\n    ports:\n      - \"3000:8080\"\n    environment:\n      # Use the IP from your .env file\n      - OLLAMA_BASE_URL=http:\/\/${LOCAL_IP}:11434\n    volumes:\n      - open_webui_data:\/app\/backend\/data\n    networks:\n      - ai-network\n    restart: unless-stopped\n\n  # --- n8n ---\n  n8n:\n    image: n8nio\/n8n:latest\n    container_name: n8n\n    ports:\n      - \"5678:5678\"\n    environment:\n      - N8N_HOST=${LOCAL_IP}\n      - WEBHOOK_URL=http:\/\/${LOCAL_IP}:5678\/\n      - N8N_SECURE_COOKIE=false\n    volumes:\n      - n8n_data:\/home\/node\/.n8n\n      - .\/data:\/home\/node\/data\n    networks:\n      - ai-network\n    restart: unless-stopped\n\nnetworks:\n  ai-network:\n\nvolumes:\n  n8n_data:\n  open_webui_data:<\/code><\/pre>\n\n\n\n<p>Update: <\/p>\n\n\n\n<p>As of April 2026, <strong>Docker Desktop on Windows does not support passing AMD GPUs to containers.<\/strong> While NVIDIA users can use &#8220;GPU-PV,&#8221; AMD support is currently limited to the Linux version of Docker or the native Windows app.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Trade-off<\/h3>\n\n\n\n<p>If you insist on 100% Docker on Windows:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>The Good:<\/strong> Your setup is perfectly clean and contained.<\/li>\n\n\n\n<li><strong>The Bad:<\/strong> Ollama will run on your <strong>CPU<\/strong>, not your Radeon card. This means Gemma 4 will be about <strong>10-20x slower<\/strong> (it will feel like it&#8217;s &#8220;stuttering&#8221; while typing).<\/li>\n<\/ul>\n\n\n\n<p>If you are okay with that, here is your 100% Docker &#8220;CPU-Only&#8221; YAML file.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1. The 100% Docker <code>docker-compose.yml<\/code><\/h3>\n\n\n\n<p>YAML<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>services:\n  ollama:\n    image: ollama\/ollama:latest\n    container_name: ollama\n    volumes:\n      - ollama_data:\/root\/.ollama\n    ports:\n      - \"11434:11434\"\n    environment:\n      - OLLAMA_HOST=0.0.0.0\n    networks:\n      - ai-network\n    restart: unless-stopped\n\n  open-webui:\n    image: ghcr.io\/open-webui\/open-webui:main\n    container_name: open-webui\n    ports:\n      - \"3000:8080\"\n    environment:\n      - OLLAMA_BASE_URL=http:\/\/ollama:11434\n    volumes:\n      - open_webui_data:\/app\/backend\/data\n    networks:\n      - ai-network\n    restart: unless-stopped\n\n  n8n:\n    image: n8nio\/n8n:latest\n    container_name: n8n\n    ports:\n      - \"5678:5678\"\n    environment:\n      - N8N_HOST=${LOCAL_IP}\n      - WEBHOOK_URL=http:\/\/${LOCAL_IP}:5678\/\n      - N8N_SECURE_COOKIE=false\n    volumes:\n      - n8n_data:\/home\/node\/.n8n\n      - .\/data:\/home\/node\/data\n    networks:\n      - ai-network\n    restart: unless-stopped\n\nnetworks:\n  ai-network:\n\nvolumes:\n  ollama_data:\n  n8n_data:\n  open_webui_data:\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">2. How to Pull Gemma 4 inside the Container<\/h3>\n\n\n\n<p>Once you run <code>docker compose up -d<\/code>, you have to tell the Docker container to download the model:<\/p>\n\n\n\n<p>PowerShell<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker exec -it ollama ollama pull gemma4:e2b\n<\/code><\/pre>\n\n\n\n<p><em>(<strong>Note:<\/strong> I chose <code>e2b<\/code> for the CPU setup. Since CPUs are slower than GPUs, the 2.5B parameter &#8220;Edge&#8221; version of Gemma 4 will give you a much more usable speed than the larger versions.)<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">3. Summary of your &#8220;All-In-Docker&#8221; Lab<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><td><strong>Feature<\/strong><\/td><td><strong>All-In-Docker (Current)<\/strong><\/td><td><strong>Hybrid (Native Ollama)<\/strong><\/td><\/tr><\/thead><tbody><tr><td><strong>Location<\/strong><\/td><td>100% inside Docker<\/td><td>Mixed (App + Docker)<\/td><\/tr><tr><td><strong>GPU Usage<\/strong><\/td><td><strong>CPU Only<\/strong> (Slow)<\/td><td><strong>AMD GPU<\/strong> (Fast)<\/td><\/tr><tr><td><strong>Setup Difficulty<\/strong><\/td><td>Easy<\/td><td>Medium<\/td><\/tr><tr><td><strong>Maintenance<\/strong><\/td><td>Low<\/td><td>Low<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Choosing the Right Version of Gemma 4 for your AMD GPU<\/h3>\n\n\n\n<p>Since Gemma 4 was released recently (April 2026), it comes in several &#8220;flavors.&#8221; Depending on how much <strong>VRAM<\/strong> your Radeon card has, you might want to pull a different version:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><td><strong>Command<\/strong><\/td><td><strong>Best For&#8230;<\/strong><\/td><td><strong>VRAM Needed<\/strong><\/td><\/tr><\/thead><tbody><tr><td><code>docker exec -it ollama ollama pull gemma4:2b<\/code><\/td><td><strong>Ultra Fast.<\/strong> Great for basic n8n automations.<\/td><td>~2GB<\/td><\/tr><tr><td><code>docker exec -it ollama ollama pull gemma4:4b<\/code><\/td><td><strong>The Standard.<\/strong> Best balance of speed and logic.<\/td><td>~4-6GB<\/td><\/tr><tr><td><code>docker exec -it ollama ollama pull gemma4:26b<\/code><\/td><td><strong>High Intelligence.<\/strong> Use this for complex coding\/logic.<\/td><td>~16GB+<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>3. Verify in Open WebUI<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ollama, Open WebUI and n8n on Windows Hosting your own AI models is no longer just for Linux gurus. With Docker Desktop on Windows, you can run a professional-grade automation and chat suite\u2014n8n, Ollama, and Open WebUI\u2014all on your own hardware. In this guide, we will set up a &#8220;Generic&#8221; configuration that makes it easy&#8230;<\/p>\n","protected":false},"author":2,"featured_media":427863,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_kad_blocks_custom_css":"","_kad_blocks_head_custom_js":"","_kad_blocks_body_custom_js":"","_kad_blocks_footer_custom_js":"","ngg_post_thumbnail":0,"episode_type":"","audio_file":"","podmotor_file_id":"","podmotor_episode_id":"","cover_image":"","cover_image_id":"","duration":"","filesize":"","filesize_raw":"","date_recorded":"","explicit":"","block":"","itunes_episode_number":"","itunes_title":"","itunes_season_number":"","itunes_episode_type":"","_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"categories":[1031,441,446],"tags":[930,919,871,986,326],"class_list":["post-520200","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai-learnings-series","category-tech-talk","category-tips-tools-resources","tag-ai-series","tag-docker","tag-genai","tag-local-ai","tag-windows"],"taxonomy_info":{"category":[{"value":1031,"label":"AI Learnings Series"},{"value":441,"label":"Tech Talk"},{"value":446,"label":"Tips, Tools &amp; Resources"}],"post_tag":[{"value":930,"label":"AI Series"},{"value":919,"label":"Docker"},{"value":871,"label":"GenAi"},{"value":986,"label":"Local AI"},{"value":326,"label":"Windows"}]},"featured_image_src_large":["https:\/\/jorgep.com\/blog\/wp-content\/uploads\/Topic-ArtificialIntelligence-1024x512.png",1024,512,true],"author_info":{"display_name":"Jorge Pereira","author_link":"https:\/\/jorgep.com\/blog\/author\/jorge\/"},"comment_info":0,"category_info":[{"term_id":1031,"name":"AI Learnings Series","slug":"ai-learnings-series","term_group":0,"term_taxonomy_id":1041,"taxonomy":"category","description":"","parent":0,"count":8,"filter":"raw","cat_ID":1031,"category_count":8,"category_description":"","cat_name":"AI Learnings Series","category_nicename":"ai-learnings-series","category_parent":0},{"term_id":441,"name":"Tech Talk","slug":"tech-talk","term_group":0,"term_taxonomy_id":451,"taxonomy":"category","description":"","parent":0,"count":677,"filter":"raw","cat_ID":441,"category_count":677,"category_description":"","cat_name":"Tech Talk","category_nicename":"tech-talk","category_parent":0},{"term_id":446,"name":"Tips, Tools &amp; Resources","slug":"tips-tools-resources","term_group":0,"term_taxonomy_id":456,"taxonomy":"category","description":"","parent":0,"count":83,"filter":"raw","cat_ID":446,"category_count":83,"category_description":"","cat_name":"Tips, Tools &amp; Resources","category_nicename":"tips-tools-resources","category_parent":0}],"tag_info":[{"term_id":930,"name":"AI Series","slug":"ai-series","term_group":0,"term_taxonomy_id":940,"taxonomy":"post_tag","description":"","parent":0,"count":151,"filter":"raw"},{"term_id":919,"name":"Docker","slug":"docker","term_group":0,"term_taxonomy_id":929,"taxonomy":"post_tag","description":"","parent":0,"count":12,"filter":"raw"},{"term_id":871,"name":"GenAi","slug":"genai","term_group":0,"term_taxonomy_id":881,"taxonomy":"post_tag","description":"","parent":0,"count":83,"filter":"raw"},{"term_id":986,"name":"Local AI","slug":"local-ai","term_group":0,"term_taxonomy_id":996,"taxonomy":"post_tag","description":"","parent":0,"count":29,"filter":"raw"},{"term_id":326,"name":"Windows","slug":"windows","term_group":0,"term_taxonomy_id":336,"taxonomy":"post_tag","description":"","parent":0,"count":93,"filter":"raw"}],"_links":{"self":[{"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/posts\/520200","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/comments?post=520200"}],"version-history":[{"count":5,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/posts\/520200\/revisions"}],"predecessor-version":[{"id":520207,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/posts\/520200\/revisions\/520207"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/media\/427863"}],"wp:attachment":[{"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/media?parent=520200"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/categories?post=520200"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/tags?post=520200"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}