[{"data":1,"prerenderedAt":156},["ShallowReactive",2],{"seo-verification":3,"blog-stack-de-ia-self-hosted-gitea-runners-y-ollama-en-un-vps-es":6},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-stack-de-ia-self-hosted-gitea-runners-y-ollama-en-un-vps-es",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":27,"featuredImage":29,"bgImage":30,"posterImage":31,"relatedSolution":32,"intro":35,"sections":36,"ctaTitle":97,"ctaBody":98,"ctaButton":99,"ctaUrl":100,"relatedPosts":101},335,"stack-de-ia-self-hosted-gitea-runners-y-ollama-en-un-vps",{"fr":12,"en":13,"ar":14,"es":10},"deployer-stack-ia-self-hosted-gitea-ollama-vps","self-hosted-ai-stack-gitea-runners-and-ollama-on-a-vps","مكدس-ذكاء-اصطناعي-ذاتي-gitea-وollama-على-خادم-vps","Stack de IA self-hosted: Gitea, runners y Ollama en un VPS","Despliega un pipeline de IA completo en tu VPS: forge Git con Gitea, runners de CI e inferencia LLM con Ollama. Ningún código ni prompt abandona tu servidor.",9,1,false,"2026-09-06T00:00:00+00:00","2026-09-07T11:26:10+00:00",{"id":18,"name":23,"slug":24,"color":25,"icon":26},"Inteligencia Artificial","intelligence-artificielle","bg-purple-500\u002F10 text-purple-400","ia",[28],{"id":18,"name":23,"slug":24,"color":25,"icon":26},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fdeployer-stack-ia-self-hosted-gitea-ollama-vps-poster.svg",{"categorySlug":33,"appSlug":34},"inteligencia-artificial","ollama","GitHub Actions factura el tiempo de cómputo, las API LLM en la nube envían tu código a los servidores del proveedor. Para un desarrollador que gestiona código confidencial de clientes, ambas dependencias externas son inaceptables. Esta guía explica cómo montar, en un único VPS, una forge Gitea con su motor de acciones, un runner en contenedor Docker y un servidor de inferencia Ollama — un pipeline completo donde ni una línea de código ni un prompt sale de tu infraestructura. Este enfoque reunió 119 puntos en Hacker News el 21 de agosto de 2026 (discusión: https:\u002F\u002Fnews.ycombinator.com\u002Fitem?id=49390463), señal de que el apetito por los pipelines de IA soberanos no decae.",[37,41,51,54,62,87,91,94],{"type":38,"title":39,"body":40},"h2","Por qué montar este stack en un VPS","GitHub Actions y las API LLM en la nube comparten el mismo defecto: externalizan el procesamiento. En el primer caso, tu código fuente se ejecuta en runners compartidos; en el segundo, el contexto de tus peticiones se envía a un tercero. Para una agencia o freelance que gestiona código de clientes bajo NDA, corregir uno sin el otro no es suficiente.\n\nGitea incorpora nativamente un motor de acciones compatible con GitHub Actions desde su versión 1.19. Ollama expone una API REST local en la red interna de Docker. Un contenedor `act_runner` lee tus workflows `.yml` exactamente como lo haría GitHub — y llama a Ollama en lugar de una API en la nube. Todo el stack funciona con `docker compose up -d` y no genera tráfico saliente hacia las API de grandes modelos.",{"type":42,"title":43,"items":44},"ul","Beneficios concretos de esta arquitectura",[45,46,47,48,49,50],"**Confidencialidad total del código**: los runners se ejecutan en tu VPS, el código clonado nunca sale de tu red interna de Docker.","**Cero tokens enviados al exterior**: Ollama sirve la inferencia localmente; ninguna petición llega a openai.com ni a anthropic.com.","**Coste fijo y predecible**: sin facturación por ejecución de workflow, sin facturación por token — una sola línea de presupuesto mensual, independientemente de la carga.","**Workflows de GitHub Actions reutilizables**: Gitea Actions es compatible con la sintaxis `.github\u002Fworkflows\u002F`; tus pipelines migran sin reescritura.","**Modelos intercambiables libremente**: Qwen2.5-Coder, DeepSeek-Coder, Llama 3.1 o Mistral — un comando `ollama pull` para cambiar de modelo sin tocar el pipeline.","**Auditoría y trazabilidad completas**: logs de runners, historial de modelos cargados y registros de nginx permanecen en tu infraestructura y te pertenecen.",{"type":38,"title":52,"body":53},"Requisitos previos de hardware y software","La restricción determinante es la memoria RAM: el modelo debe caber completamente en memoria para que la inferencia sea ágil. Un modelo 7B cuantizado en formato Q4_K_M requiere entre 5 y 6 GB de RAM; sumando Gitea (menos de 100 MB en reposo) y el runner, cuenta con **8 GB mínimo** para un modelo 7B y **16 GB recomendados** para un modelo 13B.\n\nPara CPU, dos vCPU son suficientes para Gitea y los runners; la inferencia solo CPU en un modelo 7B tarda unos pocos segundos por respuesta, aceptable para revisión de código automatizada. Una GPU dedicada reduce esto a menos de un segundo, pero no es necesaria para uso en pipelines CI.\n\nSoftware necesario en el VPS: **Docker Engine** y **Docker Compose v2**, un nombre de dominio apuntando a tu servidor (para los certificados TLS de Gitea), y los puertos 3000 (Gitea) y 11434 (Ollama, solo red interna) disponibles.",{"type":42,"title":55,"items":56},"Modelos recomendados según la RAM disponible",[57,58,59,60,61],"**Qwen2.5-Coder:7B** (formato Q4_K_M, ~5 GB de RAM) — relación calidad\u002Frecursos equilibrada para revisiones de código en 2026; comprende el contexto extendido y las convenciones de estilo.","**DeepSeek-Coder:6.7B** (formato Q4, ~4,5 GB de RAM) — alternativa compacta cuando la RAM es escasa; preciso en Python, JavaScript y diffs de menos de 200 líneas.","**Llama 3.1:8B** (formato Q4_K_M, ~5,5 GB de RAM) — generalista multilingüe, útil cuando los proyectos mezclan código y documentación en varios idiomas.","**Mistral:7B** (formato Q4_K_M, ~4,5 GB de RAM) — respuestas cortas y directas, ideal para un resumen del diff más que para un análisis detallado.","**Pasar a un modelo 13B** — en un VPS con 16 GB o más, `codellama:13b` o `qwen2.5-coder:14b` mejoran las revisiones en diffs grandes; el tiempo de inferencia CPU pasa de ~5 s a ~15 s por llamada.",{"type":63,"title":64,"steps":65},"steps","Desplegar el stack Gitea + Ollama + runner",[66,69,72,75,78,81,84],{"title":67,"body":68},"Crear la estructura de archivos","Crea un directorio de proyecto y un archivo `docker-compose.yml` que declare tres servicios: `gitea`, `ollama` y `runner`. Coloca todos los volúmenes en un subdirectorio `data\u002F` para simplificar las copias de seguridad.\n\n```bash\nmkdir -p ~\u002Fgitea-stack\u002Fdata\u002F{gitea,ollama,runner}\ncd ~\u002Fgitea-stack\n```",{"title":70,"body":71},"Escribir el docker-compose.yml","El archivo declara una red interna `ai-net` por la que se comunican los tres servicios. Ollama no se expone en el host: solo el runner puede acceder a él a través de la red Docker.\n\n```bash\ncat > docker-compose.yml \u003C\u003C 'EOF'\nversion: \"3.8\"\n\nnetworks:\n  ai-net:\n    driver: bridge\n\nvolumes:\n  gitea-data:\n  ollama-data:\n  runner-data:\n\nservices:\n  gitea:\n    image: gitea\u002Fgitea:latest\n    restart: unless-stopped\n    networks: [ai-net]\n    ports:\n      - \"3000:3000\"\n      - \"2222:22\"\n    volumes:\n      - gitea-data:\u002Fdata\n    environment:\n      - GITEA__server__DOMAIN=git.yourdomain.com\n      - GITEA__server__ROOT_URL=https:\u002F\u002Fgit.yourdomain.com\n      - GITEA__actions__ENABLED=true\n\n  ollama:\n    image: ollama\u002Follama:latest\n    restart: unless-stopped\n    networks: [ai-net]\n    volumes:\n      - ollama-data:\u002Froot\u002F.ollama\n\n  runner:\n    image: gitea\u002Fact_runner:latest\n    restart: unless-stopped\n    networks: [ai-net]\n    volumes:\n      - runner-data:\u002Fdata\n      - \u002Fvar\u002Frun\u002Fdocker.sock:\u002Fvar\u002Frun\u002Fdocker.sock\n    environment:\n      - GITEA_INSTANCE_URL=http:\u002F\u002Fgitea:3000\n      - GITEA_RUNNER_REGISTRATION_TOKEN=${RUNNER_TOKEN}\n      - GITEA_RUNNER_NAME=local-runner\n      - OLLAMA_URL=http:\u002F\u002Follama:11434\nEOF\n```",{"title":73,"body":74},"Arrancar Gitea y obtener el token del runner","Arranca solo Gitea primero para completar la instalación inicial y generar el token de registro del runner.\n\n```bash\ndocker compose up -d gitea\n```\n\nAbre `http:\u002F\u002F\u003Cip-del-vps>:3000` en tu navegador, completa el asistente de instalación, luego ve a **Administración del sitio → Acciones → Runners** para crear un token de registro. Anota este token — lo necesitarás en el siguiente paso.",{"title":76,"body":77},"Arrancar Ollama y descargar un modelo","Arranca Ollama y descarga tu modelo. Para un pipeline de revisión de código, `qwen2.5-coder:7b` o `deepseek-coder:6.7b` ofrecen una buena relación calidad\u002Frecursos.\n\n```bash\ndocker compose up -d ollama\n# descargar un modelo de código\ndocker exec gitea-stack-ollama-1 ollama pull qwen2.5-coder:7b\n# verificar que la API responde en la red interna\ndocker run --rm --network gitea-stack_ai-net curlimages\u002Fcurl \\\n  http:\u002F\u002Follama:11434\u002Fapi\u002Ftags\n```\n\nLa respuesta JSON lista los modelos disponibles — confirmación de que la API de Ollama es accesible desde la red interna de Docker.",{"title":79,"body":80},"Registrar el runner y arrancar el stack completo","Crea un archivo `.env` con el token obtenido en el paso 3, luego arranca el runner.\n\n```bash\necho \"RUNNER_TOKEN=tu_token_aqui\" > .env\ndocker compose up -d runner\n# verificar que el runner se registró correctamente\ndocker compose logs runner | tail -20\n```\n\nVerifica en **Administración del sitio → Acciones → Runners** que tu runner aparece con estado **Activo**.",{"title":82,"body":83},"Crear un workflow que llame a Ollama","En un repositorio de Gitea, crea `.gitea\u002Fworkflows\u002Freview.yml`. El workflow clona el código, llama al endpoint `\u002Fapi\u002Fchat` de Ollama mediante `curl` y publica el resultado como comentario en la pull request.\n\n```bash\ncat > .gitea\u002Fworkflows\u002Freview.yml \u003C\u003C 'EOF'\nname: AI Code Review\non:\n  pull_request:\n    types: [opened, synchronize]\n\njobs:\n  review:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - name: Revisión de código con Ollama\n        run: |\n          DIFF=$(git diff HEAD~1 --unified=5 | head -200)\n          curl -s ${OLLAMA_URL:-http:\u002F\u002Follama:11434}\u002Fapi\u002Fchat \\\n            -H 'Content-Type: application\u002Fjson' \\\n            -d \"{\\\"model\\\": \\\"qwen2.5-coder:7b\\\", \\\"stream\\\": false,\n                 \\\"messages\\\": [{\\\"role\\\": \\\"user\\\",\n                 \\\"content\\\": \\\"Revisa este diff de Git: $DIFF\\\"}]}\" \\\n            | jq -r '.message.content'\nEOF\n```\n\nSube este archivo a tu forge Gitea — el runner lo detecta y ejecuta el job en la red interna, sin ningún acceso a Internet.",{"title":85,"body":86},"Poner Gitea detrás de un proxy inverso HTTPS","Coloca Gitea detrás de nginx o Caddy con un certificado Let's Encrypt para exponer la forge en `git.yourdomain.com`. El puerto 3000 no debe ser accesible directamente desde el exterior.\n\n```bash\n# ejemplo nginx mínimo\ncat > \u002Fetc\u002Fnginx\u002Fsites-available\u002Fgitea.conf \u003C\u003C 'EOF'\nserver {\n    listen 443 ssl;\n    server_name git.yourdomain.com;\n    ssl_certificate \u002Fetc\u002Fletsencrypt\u002Flive\u002Fgit.yourdomain.com\u002Ffullchain.pem;\n    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fgit.yourdomain.com\u002Fprivkey.pem;\n\n    location \u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:3000;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n    }\n}\nEOF\nnginx -t && systemctl reload nginx\n```\n\nOllama permanece exclusivamente en la red interna de Docker y nunca se expone en Internet.",{"type":88,"title":89,"body":90},"tip","Verificar que ningún token sale de tu servidor","Para confirmar que las llamadas LLM permanecen en tu VPS, captura el tráfico de red saliente durante la ejecución de un workflow: `tcpdump -i eth0 -n 'dst port 443 and dst host openai.com'`. Cero paquetes capturados valida el aislamiento. También puedes inspeccionar los logs de Ollama (`docker compose logs ollama`): cada petición de inferencia se registra con su dirección de origen — siempre debe ser una IP de la red interna de Docker, nunca una IP externa.",{"type":38,"title":92,"body":93},"Comparativa de coste: VPS self-hosted vs API cloud","Un modelo 7B procesa entre 30 000 y 50 000 tokens por minuto con dos vCPU. Una revisión de diff de 150 líneas consume unos 800 tokens (prompt + respuesta). Con 1 000 revisiones mensuales — un volumen realista para un equipo de cinco desarrolladores — el total es 800 000 tokens.\n\nEn la nube, gpt-4o-mini factura 0,15 $ por millón de tokens de entrada y 0,60 $ por millón de salida (precios de OpenAI en septiembre de 2026). Para 800 000 tokens: aproximadamente 0,70 $ al mes. Claude Haiku está en el mismo rango. El argumento financiero es por tanto débil a volúmenes moderados.\n\nEl argumento que se sostiene es la **confidencialidad**: los diffs del código de clientes, las claves de API que aparecen en mensajes de error, los nombres de variables de negocio — todo ello sale de tu red con cada llamada a una API externa. En un VPS ServOrbit con 8 GB de RAM (unos 15 € al mes), la inferencia local no añade coste adicional y ningún token sale nunca de tu servidor.",{"type":38,"title":95,"body":96},"Ir más lejos: observar y enriquecer el pipeline","Una vez el stack base está en marcha, dos extensiones son naturales. La primera es añadir **Langfuse** como quinto servicio: rastrea cada llamada LLM (modelo, duración, tokens consumidos, resultado), permitiéndote medir la calidad de las revisiones, detectar regresiones de modelo y comparar resultados en tu corpus real antes de cambiar de versión. La segunda es paralelizar los runners: un segundo `act_runner` con una etiqueta diferente (por ejemplo `gpu`) puede apuntar a un nodo con acceso GPU para trabajos de inferencia pesada, mientras que los trabajos ligeros (lint, tests unitarios) continúan en el runner CPU base.\n\nPara las copias de seguridad, los volúmenes `gitea-data` y `ollama-data` contienen respectivamente los repositorios y los modelos descargados. Un snapshot diario de estos dos volúmenes es suficiente para restaurar el stack completo en menos de diez minutos. Como los modelos de Ollama pueden volver a descargarse bajo demanda desde el registro público, solo `gitea-data` es realmente crítico para la continuidad del servicio y la preservación del historial Git.","Tu VPS para este stack de IA","Un VPS ServOrbit con acceso root, Docker preinstalado e IPv4 dedicada es la base sobre la que Gitea, los runners y Ollama funcionan sin compartir recursos ni tráfico saliente impuesto.","Ver los VPS","\u002Fsolutions\u002Fdeveloppeurs",[102,126,141],{"id":103,"slug":104,"slugs":105,"title":109,"excerpt":110,"readTime":111,"views":112,"isPinned":19,"publishedAt":113,"updatedAt":21,"category":114,"categories":120,"featuredImage":29,"bgImage":30,"posterImage":122,"relatedSolution":123},74,"alojar-gitea-en-un-vps",{"fr":106,"en":107,"ar":108,"es":104},"heberger-gitea","host-gitea-on-your-own-vps","استضافة-gitea-على-خادم-vps-الخاص-بك","Alojar Gitea en su propio VPS en 2026","Despliegue Gitea en un VPS con Docker y SSL. Guía completa: instalación, migración a Forgejo v16 y comparativa de gobernanza.",8,0,"2026-04-07T00:00:00+00:00",{"id":115,"name":116,"slug":117,"color":118,"icon":119},7,"Autoalojamiento","self-hosting","bg-indigo-500\u002F10 text-indigo-400","cloud",[121],{"id":115,"name":116,"slug":117,"color":118,"icon":119},"\u002Fblog\u002Fcovers\u002Fheberger-gitea-poster.svg",{"categorySlug":124,"appSlug":125},"desarrollo","gitea",{"id":127,"slug":128,"slugs":129,"title":133,"excerpt":134,"readTime":17,"views":112,"isPinned":19,"publishedAt":135,"updatedAt":21,"category":136,"categories":137,"featuredImage":29,"bgImage":30,"posterImage":139,"relatedSolution":140},11,"como-alojar-ollama-en-un-vps",{"fr":130,"en":131,"ar":132,"es":128},"heberger-ollama-vps","how-to-host-ollama-on-a-vps","كيفية-استضافة-ollama-على-خادم-vps","Alojar Ollama en un VPS: guía operativa avanzada","Ollama avanzado en VPS: gestión de modelos, reverse proxy nginx, seguridad de la API, cuantización Q4_K_M\u002FQ8, CVE-2026-45672 en Open WebUI y acoplamiento seguro.","2026-06-09T00:00:00+00:00",{"id":18,"name":23,"slug":24,"color":25,"icon":26},[138],{"id":18,"name":23,"slug":24,"color":25,"icon":26},"\u002Fblog\u002Fcovers\u002Fheberger-ollama-vps-poster.svg",{"categorySlug":33,"appSlug":34},{"id":142,"slug":143,"slugs":144,"title":148,"excerpt":149,"readTime":111,"views":112,"isPinned":19,"publishedAt":150,"updatedAt":21,"category":151,"categories":152,"featuredImage":29,"bgImage":30,"posterImage":154,"relatedSolution":155},271,"github-copilot-ai-credits-recuperar-control-con-un-vps",{"fr":145,"en":146,"ar":147,"es":143},"github-copilot-ai-credits-alternative-vps","github-copilot-ai-credits-take-back-control-with-a-vps","github-copilot-ai-credits-استعد-السيطرة-مع-خادم-vps","GitHub Copilot AI Credits: recuperar el control en un VPS","Desde junio de 2026, Copilot factura en AI Credits y la previsibilidad desaparece. Aloje Ollama o Tabby en un VPS: costo fijo y prompts privados.","2026-08-16T00:00:00+00:00",{"id":18,"name":23,"slug":24,"color":25,"icon":26},[153],{"id":18,"name":23,"slug":24,"color":25,"icon":26},"\u002Fblog\u002Fcovers\u002Fgithub-copilot-ai-credits-alternative-vps-poster.svg",{"categorySlug":33,"appSlug":34},1789665034388]