Cómo instalar Actual Budget en un VPS con Docker
Instala Actual Budget en tu VPS con Docker Compose: configura el volumen de datos, HTTPS obligatorio para Web Crypto, el primer presupuesto, importaciones y copias de seguridad.
Qué va a configurar
Actual Budget es una aplicación de presupuestos por sobres autoalojada. Es la respuesta habitual cuando se busca una alternativa a YNAB que pueda alojarse en un servidor propio. El servidor consta de un contenedor, un volumen de datos y un nombre HTTPS. Todo lo necesario para un presupuesto normal funciona correctamente en el VPS más pequeño que pueda alquilar, porque el servidor principalmente almacena archivos y los sincroniza.
Conviene entender la arquitectura antes de ejecutar ningún comando. El presupuesto es una base de datos SQLite que reside en el navegador y en cada aplicación móvil. El servidor que va a instalar es un endpoint de sincronización: almacena la lista de cuentas, los archivos del presupuesto y el registro de cambios que permite que el teléfono y el portátil mantengan los mismos datos. Por eso la aplicación sigue funcionando cuando el servidor está caído. También por eso perder el servidor no implica perder el presupuesto, siempre que un cliente conserve una copia.
Por qué el servidor necesita HTTPS
Actual requiere HTTPS, y no es un trámite. Los navegadores sólo exponen la Web Crypto API, la interfaz que Actual usa para su cifrado de extremo a extremo, dentro de lo que la especificación denomina un contexto seguro. Un contexto seguro es https:// o http://localhost. Cargue la aplicación desde http://203.0.113.10:5006 en un navegador de otro equipo y esas funciones simplemente no estarán disponibles, porque el navegador nunca las proporcionó a la página. Las compilaciones móviles oficiales también rechazan una URL de servidor http:// sin cifrado.
Por tanto, hay dos configuraciones viables. Coloque un certificado válido para un nombre real delante del contenedor, que es lo que hace esta guía. O proporcione al servidor un certificado autofirmado con ACTUAL_HTTPS_KEY y ACTUAL_HTTPS_CERT, como documenta el proyecto, y acepte una advertencia del navegador en cada dispositivo. Un certificado gratuito de Let's Encrypt se obtiene en cinco minutos, así que elija la primera opción.
Instalar Actual Budget con Docker Compose
Instale Docker primero si el servidor está recién preparado. Si la sintaxis de los archivos de Compose es nueva para usted, la guía Conceptos básicos de Docker Compose para un VPS explica los campos que se usan a continuación.
sudo install -d -m 755 /opt/actual
sudo install -d -m 700 /opt/actual/dataEscriba /opt/actual/docker-compose.yml:
services:
actual:
image: actualbudget/actual-server:latest
container_name: actual
restart: unless-stopped
ports:
- '127.0.0.1:5006:5006'
volumes:
- ./data:/dataTres detalles de ese archivo son importantes.
La imagen es actualbudget/actual-server:latest, publicada por el proyecto en Docker Hub y replicada en ghcr.io/actualbudget/actual. Existe una etiqueta latest-alpine para equipos de bajo consumo.
El contenedor escribe todo en /data. Dentro encontrará server-files, que contiene account.sqlite con sus credenciales y tokens de sesión, y user-files, que contiene los archivos del presupuesto. Monte esa ruta o el siguiente docker compose pull eliminará su presupuesto. ACTUAL_DATA_DIR puede moverlo, pero el valor predeterminado es suficiente.
El puerto se publica sólo en 127.0.0.1. Un 5006:5006 sin una dirección específica publica el puerto en todas las interfaces, y Docker escribe sus propias reglas antes que ufw. Por tanto, la aplicación quedaría expuesta a Internet incluso con un firewall que deniega todo. Ese comportamiento inesperado se explica en por qué los puertos publicados por Docker omiten ufw. Enlazarlo con loopback significa que sólo el reverse proxy del mismo servidor puede acceder a él.
Inícielo:
cd /opt/actual
docker compose up --detach
docker compose logs -f actualEl registro se estabiliza cuando el servidor informa de que está escuchando en el puerto 5006. Compruébelo localmente antes de modificar el DNS:
curl -fsS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:5006/Un 200 significa que la aplicación está atendiendo solicitudes. curl: (7) Failed to connect significa que el contenedor no está en ejecución, y docker compose ps mostrará que terminó. La causa habitual es un problema de permisos en el volumen montado, visible como una línea EACCES en el registro.
Coloque un certificado y un nombre real delante
Apunte un registro A al VPS, budget.example.com, y espere a que se resuelva. Después, instale nginx y emita el certificado. La guía Certbot en Ubuntu 24.04 con nginx explica detalladamente la emisión y el temporizador de renovación.
El bloque del proxy:
server {
listen 443 ssl;
http2 on;
server_name budget.example.com;
ssl_certificate /etc/letsencrypt/live/budget.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/budget.example.com/privkey.pem;
client_max_body_size 100m;
location / {
proxy_pass http://127.0.0.1:5006;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}client_max_body_size es la línea que se suele olvidar. El archivo de presupuesto se carga completo durante una sincronización total. Nginx limita de forma predeterminada el cuerpo de la solicitud a 1 MB. Cuando el archivo supera ese tamaño, la sincronización falla y aparece 413 Request Entity Too Large en el registro de acceso de nginx, mientras que la aplicación sólo muestra un error de sincronización genérico. El servidor tiene sus propios límites independientes: ACTUAL_UPLOAD_FILE_SYNC_SIZE_LIMIT_MB tiene un valor predeterminado de 20 y ACTUAL_UPLOAD_SYNC_ENCRYPTED_FILE_SYNC_SIZE_LIMIT_MB tiene un valor predeterminado de 50. Por tanto, establezca el límite de nginx por encima del límite que corresponda en su caso.
Recargue y pruebe:
sudo nginx -t && sudo systemctl reload nginx
curl -fsS -o /dev/null -w '%{http_code}\n' https://budget.example.com/Primera ejecución: la contraseña y el primer archivo de presupuesto
Abra https://budget.example.com en un navegador. La primera pantalla le pide que establezca una contraseña para el servidor. Esa contraseña protege todo el servidor, así que genere una contraseña larga y aleatoria y guárdela en un lugar donde pueda encontrarla de nuevo, como un gestor de contraseñas Vaultwarden autoalojado. No es necesario crear cuentas de usuario. El servidor de Actual está diseñado para usar una sola contraseña, por lo que compartir un presupuesto implica compartir esa contraseña.
A continuación, cree un archivo de presupuesto. Actual le pregunta si quiere activar el cifrado de extremo a extremo. Responda que sí. El servidor almacenará sólo el texto cifrado, que es la opción adecuada para datos financieros en una máquina alquilada. El coste es real: la contraseña de cifrado nunca llega al servidor. Si la pierde, el archivo desaparece y no existe ningún mecanismo de restablecimiento. Anótela antes de continuar desde esa pantalla.
Establezca los saldos iniciales a partir de las cifras actuales de su banco en lugar de importar años de historial. El método de presupuesto por sobres parte del dinero que tiene ahora y avanza desde ahí, por lo que no tener un historial no supone ningún problema.
Importación de transacciones
Aquí la honestidad es más importante que el entusiasmo, porque la importación es la principal razón por la que muchas personas abandonan las aplicaciones de presupuestos autoalojadas.
La introducción manual es la base y siempre funciona. En un método de sobres, podría decirse que es el objetivo, porque escribir una compra hace que la tenga presente.
La importación de archivos gestiona la mayor parte del trabajo. Actual lee CSV, QIF, OFX y QFX, y todos los bancos permiten exportar al menos uno de esos formatos. Importe cada cuenta desde la pantalla de la cuenta, asigne las columnas una vez y Actual recordará esa configuración para la cuenta.
Existe la sincronización bancaria automática, pero necesita un servicio de terceros porque el servidor no puede comunicarse con los bancos por sí solo. Actual admite SimpleFIN Bridge para bancos de Norteamérica, Enable Banking para Europa, Akahu para Nueva Zelanda y Pluggy.ai para Brasil. GoCardless todavía es compatible, pero ya no acepta cuentas nuevas. Debe registrarse directamente con el proveedor, generar las credenciales y añadirlas al servidor. SimpleFIN Bridge cobra 15 dólares estadounidenses al año por hasta 25 instituciones a fecha de julio de 2026, y los demás servicios tienen precios distintos.
Hay dos límites que debe aceptar antes de depender de esta función. Las credenciales de la API se almacenan en el servidor y no están protegidas por cifrado de extremo a extremo, porque el servidor tiene que utilizarlas. Además, Actual no consulta los bancos periódicamente: la sincronización se inicia al pulsar un botón, no mediante una tarea en segundo plano.
Backups, porque sólo son archivos
Todo lo que importa está en /opt/actual/data. No hay ningún paso de exportación ni ningún volcado de base de datos que automatizar.
La única excepción es SQLite. Si copia account.sqlite mientras el servidor escribe en él, puede capturar una transacción incompleta. No lo descubrirá hasta que intente restaurarla. Detenga el contenedor durante los pocos segundos que tarda la copia:
cd /opt/actual
docker compose stop
restic -r sftp:backup@backup.example.com:/srv/restic backup /opt/actual/data
docker compose startPrograme esta tarea con el método descrito en copias de seguridad con restic en un VPS, que cubre la configuración del repositorio, la retención y la prueba de restauración. Ejecute la prueba de restauración. Una copia de seguridad que nunca se ha restaurado es sólo una suposición.
Las copias de seguridad del cliente de Actual son independientes y también conviene conocerlas. El navegador conserva copias recientes del archivo de presupuesto, accesibles desde el menú de archivos. Esto permite solucionar el caso de «he eliminado una categoría por error» sin tocar el servidor.
Actualizar el servidor
cd /opt/actual
docker compose pull
docker compose up --detachCompose recrea el contenedor a partir de la nueva imagen y vuelve a asociar el mismo volumen, por lo que los datos se conservan. Actualice también los clientes. Se espera que las versiones del servidor y de la aplicación se mantengan próximas, y un cliente mucho más antiguo que el servidor puede negarse a sincronizar y mostrar un mensaje de incompatibilidad de versiones. Haga una copia de seguridad antes de saltar a una versión principal, porque las migraciones se ejecutan durante el primer arranque y no existe una ruta de degradación. Actual tolera un `latest` flotante porque su estado es un directorio de archivos, pero no ocurre lo mismo con una aplicación que utiliza una base de datos real. Alojar Chatwoot por cuenta propia explica el uso de etiquetas fijadas y del volcado previo a la actualización que requiere ese enfoque.
Qué falla y qué verá
La aplicación carga, pero la sincronización nunca termina. Revise el registro de acceso de nginx para 413. Esto significa que client_max_body_size está configurado con un valor demasiado bajo. Un 502 indica, en cambio, que nginx está activo pero el contenedor no.
Faltan las opciones de cifrado o la aplicación móvil rechaza la URL. La página no está en un contexto seguro. La barra de direcciones mostrará http:// con una dirección IP o un nombre de host que no es localhost. Corrija el certificado en lugar de buscar una solución alternativa.
Aparece un mensaje que indica que el archivo de presupuesto no es compatible con esta versión. Las versiones del cliente y del servidor han quedado desincronizadas. Actualice ambos a la misma versión y vuelva a cargar la aplicación.
El contenedor se reinicia en un bucle. Lea docker compose logs actual. Un error de permisos en /data indica que el directorio montado no permite escrituras al usuario del contenedor. Un error de dirección en uso indica que otro proceso ya está usando 5006 en loopback.
La primera carga parece lenta. El archivo de presupuesto completo se descarga en el navegador al abrirlo. Es una transferencia grande seguida de lecturas locales. No es un problema de dimensionamiento del servidor y añadir RAM no lo cambiará.
FAQ
¿Actual Budget necesita HTTPS para funcionar?
Sí, en la práctica. El cifrado de extremo a extremo de Actual usa la API Web Crypto del navegador, que los navegadores sólo exponen en un contexto seguro, es decir, https:// o http://localhost. Si se accede mediante HTTP sin cifrar desde otra máquina, esas funciones no están disponibles y las aplicaciones móviles oficiales rechazan la URL del servidor HTTP sin cifrar. Use un certificado de Let's Encrypt en un nombre de host real, o un certificado autofirmado con ACTUAL_HTTPS_KEY y ACTUAL_HTTPS_CERT si sólo usa un navegador de escritorio.
¿Actual puede importar automáticamente las transacciones de mi banco?
Sólo mediante un servicio de terceros que debe contratar por su cuenta: SimpleFIN Bridge en Norteamérica, Enable Banking en Europa, Akahu en Nueva Zelanda o Pluggy.ai en Brasil. GoCardless es compatible, pero no acepta cuentas nuevas. Esas credenciales de API se almacenan en su servidor y no están cubiertas por el cifrado de extremo a extremo. La sincronización también es manual: debe pulsar un botón y no se consulta nada en segundo plano. La importación de CSV, QIF, OFX y QFX no necesita ningún tercero.
¿Qué tengo que incluir exactamente en las copias de seguridad?
El directorio de datos montado, que es /opt/actual/data en esta guía. Contiene server-files/account.sqlite, con los inicios de sesión y las sesiones, y user-files, con los archivos de presupuesto. Detenga el contenedor antes de copiarlo, porque copiar una base de datos SQLite activa puede capturar una escritura incompleta. Ningún otro elemento del servidor contiene datos persistentes.
¿Qué ocurre si pierdo la contraseña de cifrado?
El archivo no se puede recuperar. La contraseña nunca llega al servidor, que es precisamente el objetivo del cifrado de extremo a extremo. Por tanto, no existe ningún método de restablecimiento ni vía de asistencia. Guárdela en un gestor de contraseñas en cuanto cree el archivo y conserve una copia en un lugar que no dependa de este mismo servidor.
¿Cuántos recursos del servidor necesita Actual Budget?
Muy pocos. El contenedor sirve archivos estáticos y archivos de datos, y los cálculos del presupuesto se realizan en el navegador. Una vCPU compartida con 1 GB de RAM lo ejecuta sin problemas, y el directorio de datos de un presupuesto doméstico con varios años de historial suele ocupar unas decenas de megabytes. El consumo de disco procede de las copias de seguridad y de los demás contenedores, no de Actual. Si está dimensionando un equipo que también debe ejecutar algo más exigente, normalmente el servidor de fotos es el que determina el mínimo. Consulte cuánta RAM necesitan realmente PhotoPrism e Immich antes de elegir un plan. La misma lógica se aplica a una plataforma multimedia: la transcodificación determina el plan, mientras que una interfaz web como Halcyon, que convierte una biblioteca de Jellyfin en un videoclub de los años 90 por el que se puede navegar cuesta aproximadamente lo mismo que Actual.