---
title: "Despliega un proyecto Python con uv, Git y Railpack en Dokploy"
description: "Despliega un proyecto Python con uv en Dokploy con Railpack: guía paso a paso basada en Git para apps FastHTML, con configuración del puerto, tipos de build y solución de errores 502."
date: 2025-03-12
categories: ["self-hosting"]
tags: ["dokploy","uv","railpack"]
---

import Button from "@components/widgets/Button.astro";
import Notice from "@components/widgets/Notice.astro";
import ListCheck from "@components/widgets/ListCheck.astro";
import Accordion from "@components/widgets/Accordion.astro";
import Tabs from "@components/widgets/Tabs.astro";
import Tab from "@components/widgets/Tab.astro";

Puedes desplegar un proyecto Python con uv en Dokploy usando Railpack como proveedor de build. Sin Dockerfile. Haz push a Git y Dokploy compila y sirve tu app automáticamente con Docker y Traefik.

Esta guía cubre una app FastHTML desde la inicialización del proyecto con uv, pasando por la detección sin configuración de Railpack, hasta la configuración del puerto (la parte en la que casi todo el mundo se equivoca) y los modos de fallo que te vas a encontrar. Si eres nuevo con uv, consulta la guía [Getting Started with uv](/es/empezar-uv/). Para lo básico de FastHTML, mira [FastHTML for Beginners](/es/empezar-fasthtml/). Si aún no tienes Dokploy instalado, sigue primero la [guía de instalación de Dokploy](https://www.bitdoze.com/dokploy-install/).

El núcleo de Dokploy es Apache-2.0 (gratis para autoalojar). Existe una opción gestionada, Dokploy Cloud, desde $4.50/mes por servidor si prefieres no mantenerlo tú mismo.

## ¿Qué son Dokploy, Railpack y uv?

**uv** es un gestor de paquetes de Python basado en Rust, desarrollado por Astral. Es entre 10 y 100 veces más rápido que pip resolviendo e instalando dependencias, y reemplaza a pip, Poetry, pyenv y virtualenv. Usa `pyproject.toml` para la configuración y `uv.lock` para instalaciones reproducibles. Si estás eligiendo entre los [mejores frameworks web de Python](https://www.bitdoze.com/best-python-web-frameworks/), uv funciona con todos ellos.



<YouTubeEmbed
  url="https://www.youtube.com/embed/652DqHl7Ppo"
  label="Despliegue de un proyecto Python con uv, Git y Railpack en Dokploy"
/>
**Railpack** es un proveedor de build del equipo de Railway. Detecta automáticamente el tipo de proyecto, instala las dependencias y produce un contenedor desplegable. Para Python, Railpack reconoce proyectos cuando existen archivos como `main.py`, `app.py`, `pyproject.toml` o `requirements.txt` en la raíz del repositorio. Cuando encuentra tanto `pyproject.toml` como `uv.lock`, usa uv como gestor de paquetes automáticamente.

**Dokploy** es una plataforma de despliegue autoalojada (alrededor de 36.7k estrellas en GitHub) que orquesta contenedores Docker con Traefik para el enrutado. Soporta despliegues basados en Git y varios tipos de build: Railpack, Nixpacks y Dockerfile. Es uno de los [mejores paneles de servidores autoalojados](https://www.bitdoze.com/best-self-hosted-panels/) si quieres la comodidad de un PaaS sin renunciar al control. El núcleo es Apache-2.0; las futuras funciones de pago serán source-available. Dokploy Cloud empieza en $4.50/mes/servidor (plan Hobby).

## Paso a paso: despliega un proyecto Python con uv y Railpack en Dokploy

Despliega una app FastHTML desde cero. El flujo es: crear el proyecto, hacer push a Git, configurar Dokploy y desplegar.

### Requisitos previos

<ListCheck>
<ul>
<li>Dokploy instalado en un VPS (sigue la <a href="https://www.bitdoze.com/dokploy-install/">guía de instalación de Dokploy</a>)</li>
<li>uv instalado en local, versión ≥0.12.0 (<code>curl -LsSf https://astral.sh/uv/install.sh | sh</code>)</li>
<li>Git instalado en local y un repositorio (GitHub, GitLab, Gitea, etc.)</li>
<li>Un VPS donde ejecutar Dokploy. <a href="https://go.bitdoze.com/hetzner">Hetzner Cloud</a> empieza en ~€4.50/mes y es una opción sólida para self-hosting. <a href="https://go.bitdoze.com/hostinger-vps">Hostinger VPS</a> es otra opción económica.</li>
<li>Acceso a tu panel de Dokploy (p. ej., <code>http://your-server-ip:3000</code>)</li>
</ul>
</ListCheck>

_Los precios de los VPS subieron en todos los proveedores en 2026. Si estás replanteándote una máquina alquilada, mira [qué cambió y cuándo gana un mini PC](/es/subidas-precios-vps/)._

> **Nota sobre las versiones de uv:** A partir de uv 0.12.0 (julio de 2026), `uv init` crea por defecto una estructura de proyecto empaquetado (código bajo `src/`, un sistema de build, puntos de entrada). Usaremos `uv init --no-package` para obtener la estructura plana que Railpack espera en la raíz del repo.

### Paso 1: prepara tu proyecto Python gestionado con uv

Inicializa un proyecto con la estructura plana (sin empaquetar) y luego añade FastHTML:

```bash
uv init --no-package my-fasthtml-app
cd my-fasthtml-app
uv add python-fasthtml
```

Esto te da:

```
my-fasthtml-app/
├── .python-version  # e.g., "3.12"
├── main.py          # Entry point
├── pyproject.toml   # Project config
├── uv.lock          # Locked dependencies
└── README.md
```

Nota: no necesitas crear un virtualenv manualmente ni ejecutar `source .venv/bin/activate`. uv se encarga de esto automáticamente cuando usas `uv add` o `uv run`.

Escribe una app FastHTML mínima en `main.py`:

```python
from fasthtml.common import *

app, rt = fast_app()

@rt("/")
def get():
    return Div(P("Hello from uv and Dokploy!"))

serve()
```

Prueba en local:

```bash
uv run main.py
```

Visita `http://localhost:5001` para verificar que funciona. La función `serve()` escucha en el puerto 5001 en local. Esto es solo para desarrollo. En producción, Railpack usa un comando de arranque distinto (lo veremos en el paso 2).

Sube el código a Git:

```bash
git init
git add .
git commit -m "initial commit"
git branch -M main
git remote add origin git@github.com:user/my-fasthtml-app.git
git push -u origin main
```

### Paso 2: entiende la autodetección de Railpack

Para un proyecto básico de uv + FastHTML no necesitas un `railpack.json`. Cero configuración. Esto es lo que Railpack hace automáticamente:

**Detección:** Railpack reconoce proyectos Python cuando existe cualquiera de estos archivos en la raíz del repo: `main.py`, `app.py`, `start.py`, `bot.py`, `hello.py`, `server.py`, `requirements.txt`, `pyproject.toml` o `Pipfile`.

**Selección del gestor de paquetes:** cuando están presentes tanto `pyproject.toml` como `uv.lock`, Railpack usa uv para instalar las dependencias.

**Resolución de la versión de Python** (en orden de prioridad):
1. Variable de entorno `RAILPACK_PYTHON_VERSION`
2. `.python-version`, `.tool-versions` o `mise.toml`
3. `runtime.txt`
4. `Pipfile`
5. Por defecto: **3.13.2**

**Comando de arranque de FastHTML:** cuando Railpack detecta `python-fasthtml` como dependencia y `uvicorn` está disponible (lo está, FastHTML depende de él), arranca la app con:

```bash
uvicorn main:app --host 0.0.0.0 --port ${PORT:-8000}
```

<Notice type="info" title="Comando de arranque de FastHTML">
Railpack arranca automáticamente las apps FastHTML con uvicorn en el puerto 8000, no con <code>python main.py</code>. Esto significa que la llamada a <code>serve()</code> de tu <code>main.py</code> solo se usa en desarrollo local. En producción, uvicorn importa el módulo directamente. <code>serve()</code> nunca se ejecuta.
</Notice>

**Variables de runtime que Railpack define automáticamente:** `PYTHONUNBUFFERED=1`, `PYTHONFAULTHANDLER=1`, `PYTHONHASHSEED=random`, `PYTHONDONTWRITEBYTECODE=1`, `PIP_DISABLE_PIP_VERSION_CHECK=1`, `PIP_DEFAULT_TIMEOUT=100`.

#### Opcional: railpack.json personalizado

Si necesitas sobrescribir el comando de arranque o añadir paquetes en tiempo de build, crea un `railpack.json` en la raíz del repo:

```json
{
  "$schema": "https://schema.railpack.com",
  "provider": "python",
  "deploy": {
    "startCommand": "uvicorn main:app --host 0.0.0.0 --port 8000"
  }
}
```

Para la mayoría de proyectos de uv + FastHTML, omite este archivo por completo.

### Paso 3: configura Dokploy con Git (puerto = 8000)

Despliega usando la integración Git de Dokploy con Railpack como tipo de build.

1. **Inicia sesión en Dokploy.** Abre tu panel (p. ej., `http://your-server-ip:3000`).

2. **Crea un proyecto nuevo.** Ve a **Projects** > **New Project**, llámalo `my-uv-app` y guarda.

3. **Añade una aplicación.** Dentro del proyecto verás un entorno `production` por defecto (Dokploy introdujo los Environments en v0.25.0). Añade una nueva aplicación:
   - **Name:** `my-uv-app`
   - **Git Repository:** `https://github.com/yourusername/my-fasthtml-app.git`
   - **Branch:** `main`
   - **Build Type:** **Railpack**
   - Guarda.

![Pantalla de proyecto de Dokploy mostrando el entorno production y la lista de aplicaciones](@assets/images/25/03/dokploy-project.png)

4. **Fija el puerto en 8000.** En los ajustes de la aplicación, pon el campo de puerto en **8000**. Coincide con el `${PORT:-8000}` por defecto de Railpack para apps FastHTML. Dokploy usa [Traefik como proxy inverso](/es/traefik-proxy-docker/) para enrutar el tráfico. Si el puerto no coincide con el que escucha el contenedor, obtendrás errores 502.

<Notice type="warning" title="Un puerto mal configurado es el fallo nº 1 de los despliegues">
Railpack arranca FastHTML en el puerto 8000. Si tu dominio en Dokploy está configurado para otro puerto (o el valor por defecto), obtendrás errores 502/504. Fija siempre el puerto en 8000 para apps FastHTML.
</Notice>

5. **Configura un dominio.** En la pestaña **Domains**, añade tu dominio personalizado (p. ej., `my-uv-app.yourdomain.com`). Asegúrate de que el puerto coincida (8000). Activa HTTPS. Dokploy gestiona el enrutado de Traefik y la generación del certificado automáticamente.

![Configuración de dominio en Dokploy mostrando el puerto 8000 y el toggle de HTTPS](@assets/images/25/03/dokploy-domain.png)

6. **Añade variables de entorno** (opcional). En la pestaña **Environment**, añade las variables de entorno que tu proyecto necesite.

7. **Despliega.** Haz clic en **Deploy**. Dokploy clona el repo, Railpack compila la imagen y el contenedor arranca.

### Paso 4: verifica el despliegue

1. **Revisa los logs del build.** En la pestaña **Logs**, busca `uv sync` (paso de instalación) seguido de `Uvicorn running on http://0.0.0.0:8000`.

2. **Prueba la app.** Visita tu URL (p. ej., `https://my-uv-app.yourdomain.com`). Deberías ver la respuesta de FastHTML: `<div><p>Hello from uv and Dokploy!</p></div>`.

3. **Si obtienes un 502/504**, casi seguro el puerto está mal. Vuelve al paso 3 y verifica que el puerto está fijado en 8000. Consulta la [sección de solución de problemas](#solución-de-problemas-en-despliegues-de-dokploy--railpack) más abajo para más modos de fallo.

### Paso 5: automatiza los próximos despliegues

1. **Activa el despliegue automático.** En los ajustes de la aplicación, habilita **Auto Deploy** para la rama `main`.
2. **Sube un cambio.** Edita `main.py`:

```python
@rt("/")
def get():
    return Div(P("Updated: Hello from uv and Dokploy!"))
```

```bash
git add main.py
git commit -m "update greeting"
git push origin main
```

Dokploy detecta el push y redespliega automáticamente.

## Railpack vs Nixpacks vs Dockerfile: ¿qué tipo de build elegir?

Dokploy soporta cinco tipos de build. Así se elige para un proyecto Python:

<Tabs>
<Tab name="Railpack">
**Railpack** es el tipo de build recomendado para proyectos uv. Detecta automáticamente el tipo de proyecto, selecciona uv como gestor de paquetes cuando `pyproject.toml` + `uv.lock` están presentes y gestiona el comando de arranque de FastHTML automáticamente. Cero configuración en la mayoría de casos.

Elige Railpack cuando quieras el camino de despliegue más simple y no necesites un control fino sobre la imagen de build.

Puedes fijar la versión de Railpack en Dokploy (p. ej., `0.37.0`) para evitar desviaciones en los builds a medida que Railpack publica actualizaciones.

Para más detalles sobre cómo se compara Railpack con el antiguo Nixpacks, mira [Railpack vs. Nixpacks](https://www.bitdoze.com/es/railpack-vs-nixpacks/).
</Tab>
<Tab name="Nixpacks">
**Nixpacks** era el tipo de build por defecto original en Dokploy. Sigue disponible y funciona para proyectos Python, pero Railpack lo ha superado en gran medida con mejor soporte de uv y builds más rápidos.

Elige Nixpacks si tienes un proyecto existente configurado con él y no quieres cambiar. Para proyectos nuevos, empieza con Railpack.
</Tab>
<Tab name="Dockerfile">
**Dockerfile** te da el máximo control. Defines cada capa, cada dependencia, cada optimización. Para apps Python en producción, un Dockerfile multi-etapa con `uv sync --frozen` es la opción más reproducible.

Elige Dockerfile cuando necesites dependencias de sistema personalizadas, imágenes base específicas o builds multi-etapa para imágenes más pequeñas. Mira cómo [desplegar una app de Docker Compose en Dokploy](/es/dokploy-app-docker-compose/) para el flujo completo basado en Docker.

```dockerfile
FROM python:3.12-slim AS builder
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev
COPY . .
CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```
</Tab>
</Tabs>

Para una comparativa de Dokploy con otras plataformas, mira [Coolify vs Dokploy vs Kamal 2](https://www.bitdoze.com/es/coolify-vs-dokploy-vs-kamal-2/).

## Notas de despliegue de FastHTML: puertos y comando de arranque

La diferencia de puertos entre local y producción es la fuente de confusión más común:

- **En local:** `serve()` en `main.py` escucha en el puerto **5001**. Es para desarrollo.
- **En producción:** Railpack detecta FastHTML y ejecuta `uvicorn main:app --host 0.0.0.0 --port ${PORT:-8000}`. La llamada a `serve()` nunca se ejecuta porque uvicorn importa el módulo directamente. El puerto **8000** es el valor por defecto en producción.

<Notice type="info" title="Puertos en local vs producción">
En local tu app corre en el puerto 5001 vía <code>serve()</code>. En producción Railpack usa uvicorn en el puerto 8000. Son distintos — no los confundas al configurar los dominios de Dokploy. Fija el puerto de Dokploy en 8000.
</Notice>

Si necesitas un puerto de producción distinto, define la variable de entorno `PORT` en la pestaña Environment de Dokploy, o sobrescribe el comando de arranque en `railpack.json`.

`uvicorn` está disponible en runtime porque `python-fasthtml` depende de él — no necesitas añadirlo aparte.

## Solución de problemas en despliegues de Dokploy + Railpack

<Accordion label="502/504 tras el despliegue" group="troubleshooting" expanded="true">

**Causa:** puerto mal configurado. FastHTML/uvicorn escucha en el puerto 8000, pero el dominio de Dokploy está configurado para otro puerto (o el valor por defecto).

**Solución:** ve a la pestaña **Domains** de la aplicación y verifica que el campo de puerto está fijado en **8000**. Guarda y redespliega.

</Accordion>

<Accordion label="uv: command not found durante el build" group="troubleshooting">

**Causa:** Railpack no detectó un proyecto uv. Ocurre cuando `uv.lock` falta o no tiene commit.

**Solución:** asegúrate de haber hecho commit tanto de `pyproject.toml` COMO de `uv.lock` en el repo, y de que existe un archivo de detección (`main.py`, `app.py`, `pyproject.toml`, etc.) en la raíz del repo. Ejecuta `uv lock` en local si falta `uv.lock`, luego haz commit y push.

</Accordion>

<Accordion label="Versión de Python demasiado nueva / el build falla" group="troubleshooting">

**Causa:** Railpack instala CPython precompilado vía Mise. Las versiones de Python muy recientes puede que aún no tengan un binario precompilado, y el build falla.

**Solución:** fija una versión de Python soportada en `.python-version` (p. ej., `3.12` o `3.13`). Como alternativa, define la variable de entorno `MISE_PYTHON_COMPILE=1` en Dokploy para compilar Python desde el código fuente (builds más lentos, pero funciona con cualquier versión).

</Accordion>

<Accordion label="Faltan dependencias de sistema/nativas" group="troubleshooting">

**Causa:** tu paquete Python necesita una librería de sistema (p. ej., `libpq` para PostgreSQL, `opencv` necesita `libgl`). Railpack auto-instala algunas comunes (`libpq`, `ffmpeg`), pero no todas.

**Solución:** define `RAILPACK_BUILD_APT_PACKAGES` (para dependencias en tiempo de build) o `RAILPACK_DEPLOY_APT_PACKAGES` (para dependencias de runtime) como variables de entorno en Dokploy. Ejemplo: `RAILPACK_DEPLOY_APT_PACKAGES=libpq-dev`.

</Accordion>

<Accordion label="Fallan los tests de navegador con Playwright" group="troubleshooting">

**Causa:** los binarios del navegador no se instalan por defecto (para no inflar las imágenes). Esto cambió en Railpack v0.35.0.

**Solución:** define la variable de entorno `RAILPACK_PYTHON_PLAYWRIGHT_INSTALL=1` en Dokploy y redespliega.

</Accordion>

<Notice type="info" title="Backups y seguridad de los datos">
Si tu app persiste datos, configura backups. Mira <a href="https://www.bitdoze.com/es/backups-dokploy-cloudflare-r2/">backups de Dokploy con Cloudflare R2</a> para una guía de backups automatizados a almacenamiento compatible con S3.
</Notice>

## ¿Por qué usar Dokploy con uv y Railpack?

<ListCheck>
<ul>
<li><strong>Control autoalojado.</strong> Tu VPS, tus datos, tus reglas. Núcleo Apache-2.0, sin vendor lock-in.</li>
<li><strong>Velocidad.</strong> La resolución de dependencias de uv es entre 10 y 100 veces más rápida que la de pip. Los builds de Railpack son rápidos. Push para desplegar en segundos, no minutos.</li>
<li><strong>Automatización.</strong> El push a Git dispara el despliegue automático. Sin pipeline CI/CD manual que mantener.</li>
<li><strong>Reproducibilidad.</strong> <code>uv.lock</code> + <code>.python-version</code> + la versión de Railpack fijada = builds consistentes entre entornos.</li>
<li><strong>Coste.</strong> Dokploy autoalojado cuesta $0 más allá del coste de tu VPS. Un VPS básico en <a href="https://go.bitdoze.com/hetzner">Hetzner Cloud</a> cuesta ~€4.50/mes. Ese es todo tu coste de infraestructura. Dokploy Cloud gestionado cuesta $4.50/mes/servidor si prefieres no autoalojar.</li>
<li><strong>Rollback.</strong> Redespliega un commit Git anterior, o cambia de tipo de build si algo se rompe. Sin migraciones irreversibles.</li>
</ul>
</ListCheck>

Para actualizar tus apps desplegadas, mira [cómo actualizar stacks de Docker Compose en Dokploy](https://www.bitdoze.com/es/actualizar-docker-compose-dokploy/).

## Conclusión

Despliega un proyecto Python con uv en Dokploy con Railpack y el flujo es: `uv init --no-package` → añade tu framework → push a Git → Dokploy + Railpack compilan y despliegan automáticamente. Fija el puerto 8000 en la configuración del dominio y ya estás en producción. Sin Dockerfile.

Este es un camino sin configuración para self-hosting de Python. Para más control sobre las capas del build, las imágenes base o las dependencias de sistema, un Dockerfile o Docker Compose es el siguiente paso — mira [cómo actualizar stacks de Docker Compose en Dokploy](https://www.bitdoze.com/es/actualizar-docker-compose-dokploy/) para ese flujo.

Fija tu versión de Railpack, haz commit de tu `uv.lock` y verifica el puerto. Esas tres cosas evitan el 90% de los fallos de despliegue.