Hola mundo: el viaje de una petición
Escribimos una app de FastAPI que responde "Hola mundo" y seguimos su petición desde el navegador hasta una mini PC en una casa, y de regreso. Al final, el mismo viaje hasta un datacenter.
Escribes una dirección, das Enter y en menos de lo que tardas en parpadear aparece “Hola mundo”. En este artículo vamos a abrir ese parpadeo y a ver por dónde pasa la petición. Lo vamos a hacer tres veces: primero en tu propia computadora, luego hasta una mini PC en una casa y al final hasta un datacenter.
El programa
Es lo más pequeño que podemos escribir con FastAPI: una sola
ruta que responde HTML plano. Lo guardamos como main.py:
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.get("/", response_class=HTMLResponse)
def hola() -> str:
return "<!doctype html><html><body><h1>Hola mundo</h1></body></html>"
Para correrlo usamos uv, que se encarga de Python y de las dependencias:
uv run --with fastapi --with uvicorn uvicorn main:app --port 8000
Primer viaje: localhost:8000
Abres el navegador, escribes http://localhost:8000 y das Enter. Pasan cuatro cosas:
- El navegador busca qué IP es
localhost. No le pregunta a nadie en internet: la respuesta ya está en tu propia máquina y siempre es127.0.0.1. - Abre una conexión TCP al puerto 8000 de esa dirección. El kernel ve que es la interfaz de loopback y se la entrega directo a uvicorn, que está escuchando ahí.
- El navegador manda la petición. Es texto plano, así:
GET / HTTP/1.1
Host: localhost:8000
Accept: text/html
- Uvicorn se la pasa a FastAPI, FastAPI ve
GET /, ejecutahola()y devuelve esto:
HTTP/1.1 200 OK
server: uvicorn
content-length: 60
content-type: text/html; charset=utf-8
<!doctype html><html><body><h1>Hola mundo</h1></body></html>
Son 60 bytes de HTML. El navegador los lee y pinta un título.
Ojo: en este viaje la petición nunca salió de tu computadora. No tocó tu tarjeta de red, ni tu módem, ni internet.
localhostsiempre eres tú mismo.
Por eso este primer viaje toma menos de un milisegundo, y por eso nadie más puede ver tu “Hola mundo”. Para que alguien más lo vea, la petición tiene que salir de casa.
Segundo viaje: hasta una casa en Monterrey
Ahora el mismo programa vive en una mini PC en una casa en Monterrey, y lo publicamos en
https://hola.fierrosybits.com. Tú lo abres desde Guadalajara.
Lo que hay en la casa
- Una mini PC con procesador Intel N100: cuatro núcleos, consume menos que un foco y cabe en la palma de la mano.
- Ubuntu 26.04 LTS con Docker.
- Dos contenedores: la app y
cloudflared, el programa que abre un túnel de Cloudflare.
Las dependencias van en un pyproject.toml, y uv lock genera el uv.lock que fija sus
versiones exactas:
[project]
name = "hola"
version = "0.1.0"
requires-python = ">=3.13"
dependencies = ["fastapi", "uvicorn"]
La app se empaqueta con este Dockerfile:
FROM python:3.13-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN uv sync --locked --no-dev
COPY main.py .
CMD ["/app/.venv/bin/uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Fíjate en --host 0.0.0.0. Adentro de un contenedor, localhost es el propio contenedor. Si
uvicorn solo escuchara ahí, nadie de afuera del contenedor podría hablarle, ni siquiera
cloudflared.
Y los dos contenedores se levantan juntos con compose.yaml:
services:
app:
build: .
cloudflared:
image: cloudflare/cloudflared:latest
command: tunnel run
environment:
- TUNNEL_TOKEN=${TUNNEL_TOKEN}
depends_on:
- app
En el panel de Cloudflare le decimos al túnel que hola.fierrosybits.com se atiende en
http://app:8000. Y nota lo que no está: no hay ports:. La app no está expuesta ni en la mini
PC ni en el módem.
Lo raro del túnel
Normalmente, para que alguien de afuera llegue a una computadora de tu casa, tendrías que abrir un puerto en el módem. Muchos proveedores en México ni siquiera te dan una IP propia (usan algo llamado CGNAT), así que ni abriendo puertos podrías.
El túnel le da la vuelta al problema: cloudflared es el que llama hacia afuera. Al arrancar,
abre varias conexiones (por defecto cuatro) hacia al menos dos centros de datos de Cloudflare, y
las deja abiertas. Para tu módem son conexiones que salieron de casa, como cualquier página que
visitas. Cuando llega una petición, Cloudflare la manda de regreso por una de esas conexiones.
Paso a paso
- Tu navegador pregunta por DNS qué IP tiene
hola.fierrosybits.com. La respuesta es una IP de Cloudflare, no de la casa. - Tu proveedor de internet lleva la petición al centro de datos de Cloudflare más cercano a ti. Ahí se termina el cifrado HTTPS.
- Cloudflare revisa sus reglas, ve que ese nombre lo atiende un túnel y busca una de las
conexiones que abrió
cloudflared. - El túnel lleva la petición, otra vez cifrada, hasta Monterrey.
- El módem de la casa la deja pasar sin preguntar: para él es la respuesta de una conexión que la mini PC abrió.
- La mini PC la recibe en su tarjeta de red y de ahí sube hasta el código. Lo vemos abajo.
Listo para enviar la petición.
0 ms
Adentro de la mini PC
La petición entra como pulsos eléctricos por el cable de red. La tarjeta de red los convierte en
paquetes y avisa al procesador. El kernel de Linux arma la conexión TCP y le entrega los datos a
cloudflared, que corre en su contenedor.
cloudflared ve que la petición es para http://app:8000. Docker resuelve el nombre app a la
IP del otro contenedor, y la petición cruza la red bridge de Docker: un cable virtual entre los
dos contenedores que nunca sale de la mini PC.
En el contenedor de la app, uvicorn recibe exactamente el mismo texto que en el primer viaje:
GET /. FastAPI ejecuta hola(). Al código le da lo mismo si la petición vino de Guadalajara o
de la misma computadora.
El regreso, rapidísimo
La respuesta hace el camino al revés y no se detiene en ningún lado. La conexión del túnel ya
estaba abierta, así que no hay que saludar a nadie: los 60 bytes bajan por la red bridge,
cloudflared los mete al túnel, Cloudflare los cifra para tu navegador y tu proveedor te los
entrega. El navegador pinta el título.
| Tramo | Tiempo aproximado |
|---|---|
| De tu navegador al borde de Cloudflare | 18 ms |
| Del borde a la mini PC, por el túnel | 12 ms |
| Dentro de la mini PC: kernel, Docker, app | 2 ms |
| Todo el regreso | 30 ms |
| Total | 62 ms |
Son estimaciones típicas con la conexión ya abierta; la primera visita suma la consulta DNS y el saludo de HTTPS. En el video lo medimos de verdad.
Fíjate en el renglón de la mini PC: el código es la parte más rápida de todo el viaje. Casi todo el tiempo se va en la distancia.
Tercer viaje: el mismo hola mundo en un datacenter
Ahora llevemos la app a un datacenter corporativo. Lo interesante es lo poco que cambia por
dentro: el mismo main.py, la misma imagen de Docker y, si quieres, hasta el mismo túnel de
Cloudflare. La petición hace casi el mismo recorrido: borde, túnel, tarjeta de red, kernel,
contenedor, hola().
Lo que cambia es todo lo que rodea al código.
| Capa | En casa | En un datacenter |
|---|---|---|
| Código | main.py, igual en los dos | |
| Contenedor | La misma imagen de Docker, igual en los dos | |
| Sistema operativo | Ubuntu 26.04 LTS | Ubuntu 26.04 LTS, casi siempre en una VM |
| Servidor | Mini PC N100: una fuente de poder, RAM sin ECC | Servidor de rack: dos fuentes de poder, RAM ECC y una tarjeta de administración remota (BMC) |
| Red | El módem del proveedor y una IP que cambia, o ni siquiera propia (CGNAT) | Varios proveedores, IPs propias, BGP, switches y firewalls en pares |
| Energía y clima | Un contacto de pared, con suerte un no-break, y el aire del cuarto | Dos alimentaciones (A y B), UPS, plantas de emergencia y aire de precisión |
| Edificio y seguridad | La puerta de tu casa | Control de acceso, biometría, cámaras y guardia 24/7 |
En casa, si se va la luz, se cae tu “Hola mundo”. En un datacenter, si se va la luz, entran las baterías y después las plantas de emergencia, y nadie se entera. Si se cae un proveedor de internet, el tráfico se va por otro. Si falla una fuente de poder, el servidor sigue con la otra.
Casi nada de eso hace más rápido el viaje. Lo que compras en un datacenter no es velocidad, es que el viaje siga funcionando cuando algo falla.
Lo que viene
Esto fue el “Hola mundo” de fierrosybits. En la serie Del comando al fierro hacemos lo mismo con algo más grande: crear una máquina virtual, desde cómo se hacía antes hasta una nube privada.