OpenFaaS es una plataforma de código abierto para ejecutar funciones serverless empaquetadas como contenedores, invocables por HTTP y de forma asíncrona. Su variante faasd ejecuta OpenFaaS sobre containerd en un único servidor, sin Kubernetes, lo que la hace ideal para un VPS. En esta guía instalarás faasd en Ubuntu 24.04, lo publicarás con HTTPS mediante Caddy y desplegarás una función en Python construida desde tu equipo de desarrollo.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 2 GB de RAM y 2 vCPU.
- Un usuario no root con privilegios
sudo. - Un dominio con un registro A apuntando a la IP del servidor. En esta guía se usa
faas.your_domain. - En tu equipo de desarrollo: Docker (con Buildx) y una cuenta en un registro de contenedores, por ejemplo Docker Hub o GitHub Container Registry. Las funciones se construyen ahí y el servidor las descarga del registro.
Notafaasd usa su propio containerd. No instales Docker Engine en el mismo servidor, porque ambos traen un servicio
containerdy entran en conflicto. Construye las imágenes en tu equipo o en tu sistema de CI.
Importanterevisa los términos de licencia de la edición Community (CE) en la web de OpenFaaS antes de usarla en producción comercial. faasd CE está orientado a uso personal y a pruebas; OpenFaaS ofrece ediciones de pago para uso comercial.
Paso 1: Instalar faasd
El proyecto proporciona un script de instalación que descarga containerd, los plugins CNI, faasd y la CLI faas-cli, y crea los servicios de systemd. Instala Git y clona el repositorio:
sudo apt update
sudo apt install git
git clone https://github.com/openfaas/faasd --depth=1
cd faasd
Antes de ejecutarlo, revisa el script para saber qué va a instalar:
less hack/install.sh
Ejecuta la instalación:
sudo ./hack/install.sh
Al terminar, faasd queda ejecutándose con dos servicios de systemd: faasd-provider, que gestiona los contenedores de las funciones, y faasd, que arranca los componentes principales (gateway, NATS, queue-worker y Prometheus). Comprueba que ambos están activos:
sudo systemctl status faasd faasd-provider --no-pager
● faasd.service - faasd
Loaded: loaded (/lib/systemd/system/faasd.service; enabled; preset: enabled)
Active: active (running) since ...
● faasd-provider.service - faasd-provider
Loaded: loaded (/lib/systemd/system/faasd-provider.service; enabled; preset: enabled)
Active: active (running) since ...
Verifica también que faas-cli está instalado:
faas-cli version
La primera vez faasd tarda uno o dos minutos en descargar las imágenes de sus componentes. Puedes seguir el proceso con sudo journalctl -u faasd -f.
Paso 2: Iniciar sesión en el gateway
El gateway de OpenFaaS escucha en el puerto 8080. Las rutas de administración (/system/...) están protegidas con autenticación básica; el usuario es admin y la contraseña generada durante la instalación está en /var/lib/faasd/secrets/basic-auth-password.
Inicia sesión desde el propio servidor pasando la contraseña por la entrada estándar, para que no quede en el historial de la shell:
sudo cat /var/lib/faasd/secrets/basic-auth-password | faas-cli login --password-stdin
Calling the OpenFaaS server to validate the credentials...
credentials saved for admin http://127.0.0.1:8080
Despliega una función de ejemplo del catálogo oficial para comprobar que todo funciona:
faas-cli store deploy figlet
faas-cli list
Function Invocations Replicas
figlet 0 1
Invócala:
echo "CubePath" | faas-cli invoke figlet
La salida es el texto "CubePath" dibujado en caracteres ASCII. Si la función aparece con 0 réplicas, espera unos segundos a que se descargue la imagen y repite faas-cli list.
Paso 3: Publicar el gateway con HTTPS
El puerto 8080 sirve HTTP sin cifrar, y por él viajan la contraseña de administración y los datos de tus funciones. En lugar de abrirlo, pon delante Caddy, que obtiene y renueva automáticamente un certificado de Let's Encrypt.
Configura el cortafuegos para permitir SSH, HTTP y HTTPS, dejando el 8080 cerrado:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Instala Caddy desde los repositorios de Ubuntu:
sudo apt install caddy
Sustituye el contenido del archivo de configuración:
sudo nano /etc/caddy/Caddyfile
faas.your_domain {
reverse_proxy 127.0.0.1:8080
}
Recarga Caddy y comprueba que ha obtenido el certificado:
sudo systemctl reload caddy
sudo journalctl -u caddy --since "5 minutes ago" | grep -i certificate
Desde cualquier equipo, el endpoint de salud del gateway debe responder por HTTPS:
curl -i https://faas.your_domain/healthz
HTTP/2 200
...
OK
La interfaz web de OpenFaaS está disponible en https://faas.your_domain/ui/ con el usuario admin y la misma contraseña.
Paso 4: Crear una función en Python
A partir de aquí trabajas en tu equipo de desarrollo. Instala faas-cli allí siguiendo las instrucciones de la documentación de OpenFaaS para tu sistema (en macOS, brew install faas-cli) e inicia sesión contra tu gateway. Copia la contraseña de forma segura desde el servidor y pásala por la entrada estándar:
export OPENFAAS_URL=https://faas.your_domain
faas-cli login --password-stdin < ~/openfaas-password.txt
Borra el archivo de la contraseña cuando hayas iniciado sesión. Inicia sesión también en tu registro de contenedores con docker login.
Descarga la plantilla python3-http, basada en Flask, que da acceso al método, las cabeceras y el cuerpo de la petición:
mkdir -p ~/funciones && cd ~/funciones
faas-cli template store pull python3-http
Crea la función. Con --prefix indicas tu usuario u organización en el registro, que se usará para nombrar la imagen:
faas-cli new saludo --lang python3-http --prefix your_registry_user
El comando crea el directorio saludo/ con handler.py y requirements.txt, y el archivo de despliegue stack.yaml (en versiones antiguas de faas-cli, saludo.yml). Edita el código de la función:
nano saludo/handler.py
import json
import os
def handle(event, context):
try:
datos = json.loads(event.body or b"{}")
except json.JSONDecodeError:
return {
"statusCode": 400,
"body": json.dumps({"detail": "El cuerpo debe ser JSON"}),
"headers": {"Content-Type": "application/json"},
}
nombre = datos.get("nombre", "mundo")
respuesta = {
"mensaje": f"Hola, {nombre}",
"metodo": event.method,
"entorno": os.getenv("ENTORNO", "desconocido"),
}
return {
"statusCode": 200,
"body": json.dumps(respuesta, ensure_ascii=False),
"headers": {"Content-Type": "application/json"},
}
Revisa stack.yaml y añade una variable de entorno y un límite de memoria:
nano stack.yaml
version: 1.0
provider:
name: openfaas
gateway: https://faas.your_domain
functions:
saludo:
lang: python3-http
handler: ./saludo
image: your_registry_user/saludo:latest
environment:
ENTORNO: produccion
limits:
memory: 128Mi
Paso 5: Construir y desplegar la función
faas-cli up construye la imagen, la sube al registro y la despliega en el gateway en un solo paso:
faas-cli up -f stack.yaml
Si tu equipo usa una arquitectura distinta a la del servidor (por ejemplo, un Mac con Apple Silicon y un VPS x86_64), construye la imagen para la plataforma del servidor con Buildx y despliega después:
faas-cli publish -f stack.yaml --platforms linux/amd64
faas-cli deploy -f stack.yaml
Cuando termine, faas-cli muestra la URL de la función. Pruébala:
curl -s https://faas.your_domain/function/saludo \
-H "Content-Type: application/json" \
-d '{"nombre": "CubePath"}'
{"mensaje": "Hola, CubePath", "metodo": "POST", "entorno": "produccion"}
Consulta sus logs, que en faasd se leen del journal del servidor:
faas-cli logs saludo
El comando sigue mostrando líneas nuevas durante un tiempo; interrúmpelo con Ctrl+C.
Notala invocación de funciones en
/function/<nombre>no requiere autenticación; la autenticación básica solo protege la API de administración. Si una función no debe ser pública, valida un token o una firma dentro de la propia función.
Si la imagen está en un registro privado, el servidor necesita credenciales para descargarla. faasd las lee de /var/lib/faasd/.docker/config.json; la documentación de faasd explica cómo generarlo con docker login en otra máquina y copiarlo.
Paso 6: Usar secretos
Las credenciales (claves de API, contraseñas de bases de datos) no deben ir en environment, porque quedan visibles en stack.yaml y en la descripción de la función. Crea un secreto en el gateway:
faas-cli secret create api-key --from-literal "your_api_key"
Referéncialo en stack.yaml, dentro de la definición de saludo:
secrets:
- api-key
OpenFaaS monta cada secreto como archivo en /var/openfaas/secrets/<nombre>. Léelo desde el código:
with open("/var/openfaas/secrets/api-key") as f:
api_key = f.read().strip()
Vuelve a desplegar con faas-cli up -f stack.yaml para aplicar el cambio.
Paso 7: Invocar funciones de forma asíncrona
Para trabajos que tardan (procesar un archivo, llamar a una API lenta), invoca la función por la ruta /async-function/. El gateway guarda la petición en la cola de NATS, responde de inmediato con 202 Accepted y el queue-worker la ejecuta en segundo plano:
curl -i https://faas.your_domain/async-function/saludo \
-H "Content-Type: application/json" \
-d '{"nombre": "cola"}'
HTTP/2 202
x-call-id: 6d2f0c8e-...
...
Si añades la cabecera X-Callback-Url: https://your_app/webhook, el queue-worker enviará el resultado a esa URL cuando termine. Puedes ver la ejecución en faas-cli logs saludo.
Limitaciones de faasd
faasd está pensado para un solo servidor y tiene diferencias importantes con OpenFaaS sobre Kubernetes:
- Cada función se ejecuta con una réplica; no hay autoescalado ni escalado a cero.
- No hay alta disponibilidad: si el servidor se reinicia, las funciones vuelven a arrancar con él, pero hay una interrupción.
- La actualización de faasd se hace volviendo a ejecutar el script de instalación de una versión nueva.
Si necesitas autoescalado o varios nodos, OpenFaaS se instala en Kubernetes con su chart de Helm, y las funciones y stack.yaml que has creado sirven sin cambios.
Solución de problemas
faas-cli login falla con connection refused. faasd todavía está arrancando o ha fallado. Revisa sudo journalctl -u faasd -n 50 y sudo journalctl -u faasd-provider -n 50; los errores de descarga de imágenes suelen deberse a DNS o a falta de espacio en disco.
La función se despliega pero faas-cli list muestra 0 réplicas. El servidor no ha podido descargar la imagen. Comprueba en sudo journalctl -u faasd-provider si el error es de autenticación (registro privado sin credenciales) o de arquitectura (exec format error, imagen construida para ARM en un servidor x86_64 o al revés).
Caddy no obtiene el certificado. El registro A aún no apunta al servidor o los puertos 80 y 443 están cerrados. Comprueba dig +short faas.your_domain, sudo ufw status y los logs con sudo journalctl -u caddy -n 50.
faas-cli up falla en el paso de push. No has iniciado sesión en el registro o el prefijo de la imagen no coincide con tu usuario. Ejecuta docker login y revisa el campo image de stack.yaml.
Conclusión
Tienes OpenFaaS funcionando con faasd en un VPS, publicado con HTTPS, y una función en Python desplegada desde tu equipo con secretos e invocación asíncrona. Como siguientes pasos, automatiza faas-cli publish y faas-cli deploy en tu pipeline de CI, añade funciones en otros lenguajes con faas-cli template store list y, si tu carga crece, migra las mismas funciones a OpenFaaS sobre Kubernetes para obtener autoescalado.
