DISABLE_REGISTRATION = true. Tú creas las cuentas; nadie se autoatiende. Si necesitas altas ocasionales, usa el flujo de invitación en lugar de abrir la puerta.

Tu propio servidor Git.
El repositorio es el organigrama.
Un repositorio privado es un registro fechado de lo que estás construyendo, con quién lo estás construyendo, y hasta dónde has llegado — y en una plataforma, ese registro lo tiene una empresa en la jurisdicción de otro. Seis pasos para trasladarlo a una máquina que alquilas de forma anónima: Forgejo detrás de Caddy, PostgreSQL debajo, push por SSH en un puerto propio, un ejecutor de Actions que nunca ve tus secretos de producción, y una copia de seguridad que de verdad has restaurado. La máquina cuesta $3.90 al mes. Probado en Debian 12.
- 01
Elegir
Repo desnudo, Forgejo, GitLab
- 02
Aprovisionar
Puertos decididos antes de arrancar
- 03
Desplegar
Forgejo, Postgres, Caddy
- 04
Subir
SSH, claves de despliegue, firmas
- 05
Construir
Un ejecutor, mantenido a distancia
- 06
Mantener
Espejos, copias de seguridad, actualizaciones
El código es la parte menos interesante. El activo son los metadatos.
Casi todos los argumentos sobre el autoalojamiento de Git giran en torno al código fuente, y el código fuente es la parte que menos importa. La mayor parte es poco destacable, buena parte de él es una capa fina sobre bibliotecas de código abierto, y si se filtrara mañana el daño práctico normalmente sería vergüenza más que perjuicio real. Por eso «mi código no es secreto» suena como una respuesta completa, y por eso no lo es.
Lo que rodea al código es la parte interesante. Un repositorio es un registro de trabajo fechado, atribuido y de alta resolución: las marcas de tiempo de los commits describen cuándo duermes, las líneas de coautoría describen con quién trabajas, los nombres de las ramas describen productos que nadie ha anunciado, un gestor de incidencias describe qué está roto y hasta qué punto, y un primer commit fecha el proyecto entero. Lee cien repositorios así y ya no estás leyendo software — estás leyendo una empresa, su hoja de ruta, su plantilla y sus problemas.
En una plataforma, ese registro no es tuyo en ningún sentido relevante. Reside en una infraestructura que no controlas, bajo una cuenta ligada a una identidad que verificaste, en una jurisdicción cuyo proceso legal puede alcanzarlo, escaneado por sistemas cuyo alcance fija un documento que se puede modificar. Nada de esto exige mala fe por parte de nadie: es simplemente lo que significa alquilar el gestor de seguimiento. Cuatro configuraciones, y lo que cada una revela en realidad:
| Dónde vive el repositorio | Quién tiene el historial | Ligado a tu identidad legal | Cómo sale mal |
|---|---|---|---|
| Una plataforma, cuenta personal | La plataforma, en su propia jurisdicción | Sí — correo electrónico, facturación, a menudo un número de teléfono | Una suspensión se lleva por delante todos los remotos |
| Una plataforma, cuenta de organización | La plataforma, más quien administre la organización | Sí, y también a tu empleador | La baja te quita el acceso a tu propio trabajo |
| Autoalojado, en un hiperescalador | Tú, en la capa de aplicación | Sí — la cuenta de facturación es la identidad | La instantánea vive en la cuenta que se puede cerrar |
| Autoalojado, en un VPS sin KYC | Tú, y solo tú | No — sin identificación, sin tarjeta, pago en criptomoneda | Ahora el sysadmin eres tú. Una mala copia de seguridad es definitiva |
La tercera fila es la que atrapa a los equipos que creen que ya han resuelto esto. Una forja que has instalado tú mismo, en una máquina alquilada con una tarjeta corporativa bajo una cuenta de empresa verificada, ha sacado la aplicación de la plataforma y ha dejado la identidad exactamente donde estaba. Eso es una ganancia real en control y ninguna ganancia en exposición.
Y la cuarta fila expone su propio coste sin rodeos, porque el resto de esta guía trata sobre todo de pagarlo. El modo de fallo del autoalojamiento no es la vigilancia, es la pérdida. Una plataforma guarda copias de seguridad en las que nunca piensas. Tu servidor guarda las copias de seguridad que tú configuraste. El paso 06 no es el acabado opcional del final — es el paso que hace seguros a los otros cinco.
¿Cuánta forja necesitas? La respuesta honesta suele ser «ninguna».
Empieza por lo más pequeño que resuelva tu problema, porque cada capa por encima de eso es un servicio que tienes que operar. Un repositorio desnudo por SSH es un solo comando en un servidor que ya tienes, y te da un remoto Git real con autenticación, historial y acceso de push. Sin aplicación web, sin base de datos, sin la rueda de hámster de las actualizaciones, nada que parchear más allá de sshd. Si eres una sola persona que quiere sacar sus commits de un portátil y de una plataforma, esta es una respuesta completa y puedes dejar de leer después del paso 02.
# On the server, as an unprivileged user:
mkdir -p ~/git/project.git && cd ~/git/project.git
git init --bare
# On your laptop:
git remote add origin ssh://user@git.example.com/~/git/project.git
git push -u origin main
Necesitas una forja cuando interviene una segunda persona, o cuando quieres cualquiera de las cuatro cosas que un directorio de repositorios desnudos no puede hacer: navegar el historial en un navegador, revisar cambios como pull requests, seguir incidencias junto al código, y dar acceso a una persona sobre un repositorio. Eso es un salto genuino en capacidad y un salto genuino en peso operativo. Elige con criterio:
| Propiedad | Repo desnudo por SSH | Forgejo | Gitea | GitLab CE |
|---|---|---|---|---|
| Interfaz web, pull requests, incidencias | Ninguno | Sí | Sí | Sí, y mucho más |
| Memoria en reposo | Prácticamente cero | Unos pocos cientos de MB | Unos pocos cientos de MB | Varios GB, antes de la CI |
| CI integrada | hooks de git, si los escribes tú | Forgejo Actions | Gitea Actions | GitLab CI, la madura |
| Quién dirige el proyecto | El proyecto Git | Codeberg e.V., sin ánimo de lucro | Una empresa con fines de lucro, open core | Una empresa que cotiza en bolsa, open core |
| Licencia | GPLv2 | GPLv3+ desde v9.0 (MIT antes) | MIT, con complementos propietarios | Núcleo MIT, niveles propietarios |
| Elíjalo cuando | Estás solo y quieres cero mantenimiento | Quieres una forja de verdad en una máquina pequeña | Ya lo usas y te funciona | Necesitas el conjunto de funciones empresariales |
Forgejo y Gitea comparten un antepasado y siguen viéndose casi idénticos en el uso diario. Forgejo se convirtió en una bifurcación completa a principios de 2024 y está en manos de Codeberg e.V., una asociación registrada sin ánimo de lucro en Berlin; Gitea lo desarrolla una empresa con fines de lucro que posee su marca y pide a los colaboradores la cesión de derechos de autor. Ambos son buen software. Solo uno de los dos tiene un custodio cuyos incentivos coinciden con el motivo por el que estás leyendo esta página.
El resto de esta guía usa Forgejo. Todo lo de los pasos 02 a 06 se aplica casi al pie de la letra a Gitea — cambian el nombre del contenedor y algunas variables de entorno, pero la forma no cambia.
Decide los puertos antes de que la forja los decida por ti. Dos de ellos son SSH.
Pide primero la máquina. En el panel: Order → VPS → Sentinel, imagen Debian 12, en el bastión en el que quieras que viva el historial — Helsinki, Stockholm, Oslo o Reykjavík. No hace falta ninguna dirección de correo para abrir la cuenta, y la factura se salda en Monero, Bitcoin, Lightning o cualquier otro activo admitido. Esto importa aquí más que en la mayoría de las cargas de trabajo: una forja es el único servicio cuya propuesta de valor entera consiste en que el registro de tu trabajo no esté ligado a un nombre.
Después ejecuta la lista de verificación de endurecimiento de la primera hora — SSH solo con clave en un puerto distinto del habitual, actualizaciones desatendidas, un cortafuegos que deniega por defecto — porque todo lo que sigue asume una máquina que todavía no es de otra persona.
Una forja no es un sitio estático con inicio de sesión. Es una aplicación web pública con un motor de ejecución de código atornillado a ella. Dos valores por defecto, si se dejan tal cual, la convierten en un servicio gratuito para desconocidos: el registro abierto, que llena la instancia de cuentas de spam a los pocos días de que el certificado aparezca en los registros de transparencia, y una CI que ejecuta flujos de trabajo de cualquiera que pueda abrir un pull request, que es como un ejecutor autoalojado acaba minando criptomonedas para otra persona. Ninguno de los dos es un ataque sutil, y ninguno de los dos es raro. Ambos se cierran con un solo ajuste cada uno, en el paso 03 y el paso 05 — pero decide ya que vas a cerrarlos, porque la ventana entre «funciona» y «lo están usando» se mide en días.
Apunta un nombre de host hacia la máquina — un registro A, y un AAAA si quieres que sea accesible por IPv6 — y deja que se propague antes de empezar, porque el proxy inverso intentará obtener un certificado para ese nombre la primera vez que arranque, y un desafío fallido es una forma confusa de empezar. Luego escribe las reglas del cortafuegos mientras todavía no hay nada escuchando.
El problema de los dos SSH. Una forja habla SSH para Git, y tu servidor ya habla SSH para la administración. Los dos no pueden ser dueños del puerto 22, y mezclarlos es como la gente acaba con un demonio administrativo que también tiene que entender Git. Mantenlos separados: la administración en el puerto cambiado de la guía de endurecimiento, Git en un puerto público dedicado que se redirige al contenedor. El 2222 es la elección convencional y no tiene nada de sagrado.
ufw default deny incoming
ufw allow 47222/tcp # administrative SSH, moved
ufw allow 80/tcp # ACME HTTP-01 challenge
ufw allow 443/tcp # the web interface
ufw allow 2222/tcp # git over SSH, into the container
ufw enable
ufw status numbered
# Nothing else is open. In particular: PostgreSQL stays on the Docker
# network and is never published to the host, let alone the internet.
Instala Docker desde el repositorio oficial en lugar del paquete de la distribución, para que Compose v2 esté presente y la versión sea actual. Luego crea un directorio para la pila y conviértelo en el único lugar de la máquina que retiene estado — es el directorio que respalda el paso 06.
curl -fsSL https://get.docker.com | sh
docker compose version
install -d -m 0750 /srv/forgejo
cd /srv/forgejo
Tres contenedores. Uno de ellos no debe ser accesible jamás.
Forgejo, PostgreSQL y Caddy. Forgejo guarda los repositorios y sirve la interfaz, PostgreSQL guarda todo lo que no es un objeto de Git, y Caddy termina el TLS y obtiene el certificado sin que se le pida dos veces. PostgreSQL deliberadamente no se publica al host: solo es accesible a través de la red de Compose, por nombre, desde el único contenedor que lo necesita.
/srv/forgejo/.env
FORGEJO_DOMAIN=git.example.com
FORGEJO_VERSION=15 # the LTS line; 16 is current stable
POSTGRES_PASSWORD=$(openssl rand -base64 32) # paste the value, do not leave the $( )
/srv/forgejo/docker-compose.yml
services:
forgejo:
image: codeberg.org/forgejo/forgejo:${FORGEJO_VERSION}
container_name: forgejo
environment:
USER_UID: 1000
USER_GID: 1000
FORGEJO__database__DB_TYPE: postgres
FORGEJO__database__HOST: db:5432
FORGEJO__database__NAME: forgejo
FORGEJO__database__USER: forgejo
FORGEJO__database__PASSWD: ${POSTGRES_PASSWORD}
FORGEJO__server__DOMAIN: ${FORGEJO_DOMAIN}
FORGEJO__server__ROOT_URL: https://${FORGEJO_DOMAIN}/
FORGEJO__server__SSH_DOMAIN: ${FORGEJO_DOMAIN}
FORGEJO__server__SSH_PORT: "2222" # what clones will say
FORGEJO__server__SSH_LISTEN_PORT: "22" # what the container listens on
FORGEJO__service__DISABLE_REGISTRATION: "true"
FORGEJO__repository__DEFAULT_PRIVATE: private
FORGEJO__security__INSTALL_LOCK: "true"
restart: unless-stopped
volumes:
- ./data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "127.0.0.1:3000:3000" # web, reached only by Caddy
- "2222:22" # git over SSH, public
depends_on:
- db
db:
image: postgres:16-alpine
container_name: forgejo-db
environment:
POSTGRES_USER: forgejo
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: forgejo
restart: unless-stopped
volumes:
- ./postgres:/var/lib/postgresql/data
# No ports: block. This is the point.
caddy:
image: caddy:2-alpine
container_name: forgejo-caddy
restart: unless-stopped
network_mode: host
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./caddy-data:/data
- ./caddy-config:/config
/srv/forgejo/Caddyfile
git.example.com {
encode zstd gzip
request_body {
max_size 512MB # raise it if you push large repositories
}
reverse_proxy 127.0.0.1:3000
}
Las dos líneas de SSH son las que la gente suele equivocar, así que merece la pena leerlas dos veces. SSH_LISTEN_PORT es el puerto de dentro del contenedor, donde se vincula el servidor SSH integrado de Forgejo. SSH_PORT es el puerto que Forgejo imprime en las URL de clonado que te muestra — tiene que coincidir con el lado público del mapeo de puertos. Desincronízalos y todo funciona salvo la única cosa que los usuarios copian y pegan.
Levántalo, y luego crea el administrador desde la línea de comandos. No uses el instalador web. En una instancia recién creada, es accesible para cualquiera que encuentre el nombre de host, y la primera cuenta creada a través de él se convierte en el administrador — una carrera en la que no necesitas participar. INSTALL_LOCK, en el archivo de arriba, lo cierra antes de que el contenedor llegue siquiera a arrancar.
docker compose up -d
docker compose logs -f forgejo # wait for "Starting new Web server"
docker compose exec -u git forgejo forgejo admin user create \
--admin --username you --email you@example.com --random-password
Abre el nombre de host en un navegador, inicia sesión con la contraseña impresa y cámbiala. Luego repasa los ajustes que convierten una instancia funcional en una cerrada — la mayoría ya están fijados por el bloque de entorno de arriba, y merece la pena confirmar cada uno en lugar de darlo por hecho:
DEFAULT_PRIVATE = private. Los repositorios nuevos empiezan cerrados. Publicar es entonces un acto deliberado y no la consecuencia de un valor por defecto.
REQUIRE_SIGNIN_VIEW = true oculta incluso los repositorios públicos a los visitantes sin sesión iniciada. Correcto para una forja de equipo privada; incorrecto si quieres publicar algo.
Actívalo en la cuenta de administrador antes de hacer cualquier otra cosa. La forja es ahora la máquina que puede reescribir todas tus ramas.
Una ruta que merece la pena memorizar: la configuración activa está en ./data/gitea/conf/app.ini, en el host. Forgejo conservó el nombre de directorio gitea por compatibilidad con las instalaciones existentes, algo que sorprende a todo el mundo exactamente una vez. Las variables de entorno con la forma FORGEJO__section__KEY se escriben en ese archivo al arrancar, así que puedes gestionar toda la configuración desde el archivo de Compose — pero si editas app.ini a mano, una variable de entorno para la misma clave sobrescribirá tu edición en el siguiente reinicio. Elige una de las dos formas y sé consistente.
Sube por SSH. Luego fírmalo, para que el historial no dependa del servidor.
Pega tu clave pública en los ajustes del perfil, y luego enséñale a tu cliente dónde vive la forja. Como Git está en un puerto no estándar, una entrada en tu configuración de SSH vale los treinta segundos que cuesta — mantiene el puerto fuera de cada URL que vayas a escribir, y hace que los remotos sean portables.
# ~/.ssh/config
Host git.example.com
Port 2222
User git
IdentityFile ~/.ssh/id_ed25519
# Then, in any repository:
git remote set-url origin git@git.example.com:you/project.git
git push -u origin main
ssh -T git@git.example.com # expect a greeting, not a shell
Ese último comando es el que te dice si el mapeo de puertos, el servidor SSH del contenedor y tu clave están todos de acuerdo. Un saludo de Forgejo significa que toda la cadena funciona. Una solicitud de contraseña significa que en realidad has llegado al sshd administrativo del host, y que el mapeo de puertos está mal.
Ahora firma tus commits. Este es el paso que se saltan la mayoría de las guías de autoalojamiento, y en una forja autoalojada importa más que en una plataforma. El campo de autor de un commit es texto libre — cualquiera que pueda hacer push puede escribir tu nombre en él. Una firma es la prueba de que una clave concreta hizo un commit concreto, y sigue siendo prueba después de que el servidor al que se subió haya sido comprometido, migrado o desechado. Git puede firmar con la clave SSH que ya tienes, así que ya no hace falta ningún rodeo por PGP:
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
git config --global tag.gpgsign true
git commit --allow-empty -m "signed"
git log --show-signature -1
Luego añade la misma clave pública una segunda vez en la forja, como clave de firma en lugar de clave de autenticación. Forgejo verifica la firma en el servidor y muestra el commit como verificado; sin esa segunda entrada no tiene forma de conectar la firma con tu cuenta, y cada commit aparece como no verificado aunque esté firmado correctamente.
Claves de despliegue, para las máquinas que solo leen. Un servidor de producción, una máquina de compilación o un espejo no necesitan una cuenta de usuario en la forja. Dales en su lugar una clave de despliegue: un par de claves añadido a un repositorio, de solo lectura salvo que concedas escritura explícitamente, que no da acceso a nada más en la instancia. Revocarla es borrar una entrada. Este es, con diferencia, el hábito más eficaz para mantener ordenada una forja autoalojada, porque las cuentas de usuario acumulan permisos y las claves de despliegue no pueden hacerlo.
Migrar desde una plataforma es un buen momento para hacer todo esto como es debido. El flujo New Migration de Forgejo toma una URL de repositorio y un token de acceso, y trae consigo ramas, etiquetas, incidencias, comentarios, etiquetas, hitos, lanzamientos y pull requests. Ejecuta primero un repositorio para ver la forma del resultado, cuenta con que los límites de tasa de la API frenen los lotes grandes, y mantén el origen en solo lectura durante unas semanas en lugar de borrarlo el mismo día.
Un ejecutor de CI es una máquina que ejecuta código de desconocidos. Colócalo en consecuencia.
Forgejo Actions lee archivos de flujo de trabajo con el mismo formato que GitHub Actions, desde .forgejo/workflows/, y se los entrega a un programa separado llamado Forgejo Runner. El ejecutor no forma parte de la forja y no tiene por qué vivir en la misma máquina — que es todo el diseño, y la razón por la que este paso viene con una advertencia y no con un encogimiento de hombros.
Activa Actions en la instancia, y luego consigue un token de registro desde el panel de administración — para toda la instancia, o limitado a una organización o un repositorio, que es la opción por defecto más prudente cuando no estás seguro. El ejecutor se conecta hacia fuera, hacia la forja, así que no necesita ningún puerto de entrada y puede quedarse detrás de cualquier cortafuegos que quieras, incluso en una máquina sin dirección pública.
# In the Compose environment of the forge, or app.ini:
# FORGEJO__actions__ENABLED: "true"
# Then: Site administration -> Actions -> Runners -> Create new runner
# On the runner machine:
forgejo-runner generate-config > config.yml
forgejo-runner register --no-interactive \
--instance https://git.example.com \
--token <REGISTRATION_TOKEN> \
--name runner-01 \
--labels docker:docker://node:22-bookworm,debian:docker://debian:12
forgejo-runner --config config.yml daemon
Las etiquetas son el contrato entre el flujo de trabajo y el ejecutor: un trabajo que pide runs-on: docker obtiene un contenedor construido a partir de la imagen del lado derecho. Declara solo las etiquetas que de verdad estás dispuesto a servir, porque un trabajo que pide una etiqueta que nadie ofrece espera para siempre en lugar de fallar, algo confuso de depurar al final de un día largo.
.forgejo/workflows/ci.yml
on: [push, pull_request]
jobs:
test:
runs-on: docker
container:
image: node:22-bookworm
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
Un ejecutor ejecuta lo que sea que diga el archivo de flujo de trabajo, y el archivo de flujo de trabajo llega en un pull request. Si alguien de fuera de tu equipo puede abrir uno, el ejecutor pertenece a una máquina distinta de la forja — un segundo Sentinel a $3.90 al mes, sin acceso al directorio de datos de la forja, sin credenciales de base de datos y sin nada en su entorno que te importara ver en un registro de compilación. En la propia forja, exige aprobación antes de ejecutar flujos de trabajo de quienes contribuyen por primera vez. Los dos fallos habituales son a la vez aburridos y costosos: una carga de minado escondida en un pull request, y un secreto impreso por un paso que alguien añadió deliberadamente.
Limita el alcance de los secretos de la misma manera. Forgejo los guarda a nivel de repositorio, de organización y de instancia; una clave de despliegue que solo necesita un repositorio debería existir solo en ese repositorio, para que un flujo de trabajo comprometido en un proyecto no relacionado no pueda leerla. Prefiere tokens de corta duración sobre los de larga duración siempre que el destino lo admita, y nunca pongas un secreto en un archivo de flujo de trabajo — el archivo de flujo de trabajo está en el repositorio, y el repositorio tiene un historial.
Si tus compilaciones descargan las mismas imágenes base en cada ejecución, cachéalas. Un espejo de registro local o una caché persistente del ejecutor convierten una descarga de imagen de dos minutos en una de dos segundos, y es de buena educación con los registros externos a los que estás machacando a peticiones. Y fíjate en el patrón que invita todo este diseño, que es la razón por la que esta guía está junto a la guía de tiempo de ejecución de agentes: el ejecutor es un trabajador de propósito general que toma trabajos de tu forja, así que también es donde encajan el mantenimiento programado, los pipelines de datos y las cargas de trabajo de agentes.
Cada clon es una copia de seguridad del código. Nada es una copia de seguridad de la conversación.
Git es inusualmente indulgente aquí, y merece la pena precisar por qué. Cada clon es una copia completa del historial, así que mientras un desarrollador tenga una copia de trabajo actualizada, el código sobrevive al servidor. Eso es genuinamente tranquilizador, y cubre exactamente una de las dos cosas que retiene tu forja. La otra — incidencias, discusiones de pull requests, hilos de revisión, lanzamientos, páginas de wiki, usuarios, equipos, permisos, historial de CI — solo existe en la base de datos, nadie tiene un clon de ella, y suele ser la parte que ha tardado tres años en acumularse.
Primero, un espejo push. Es gratis y se ejecuta solo. En un repositorio: Settings → Mirror settings → añade un espejo push con la URL y un token de acceso para el destino. Forgejo replica entonces cada rama y etiqueta después de cada push, hacia un segundo Forgejo, hacia Codeberg, o hacia una plataforma que hayas decidido conservar como escaparate en lugar de como hogar. Una advertencia que conviene decir sin rodeos: un espejo push vuelve a publicar el historial fielmente, incluido un secreto que querías eliminar.
Luego una copia de seguridad real, que no es el archivo integrado. Forgejo incluye un comando forgejo dump que empaqueta la configuración, los repositorios, los datos y un volcado de la base de datos en un único zip. Es algo genuinamente útil que entregarle a quien mantiene el proyecto al reportar un fallo. No es aquello en lo que deberías confiar para resucitar de entre los muertos: el SQL que produce tiene problemas conocidos y de larga data al reimportarlo, y el archivo reescribe todo el conjunto de repositorios en cada ejecución, lo que en una instancia real significa un archivo grande escrito desde cero cada noche. Usa en su lugar la vía aburrida y verificable — vuelca la base de datos con la propia herramienta de la base de datos, y respalda el directorio de datos como archivos:
#!/bin/sh
# /usr/local/bin/forgejo-backup — run from a systemd timer, nightly
set -eu
cd /srv/forgejo
# 1. Consistent database dump, written next to the data.
docker compose exec -T db pg_dump -U forgejo -Fc forgejo > ./db.dump
# 2. Everything that matters, to an encrypted offsite repository.
restic backup ./data ./db.dump ./docker-compose.yml ./.env ./Caddyfile
# 3. Retention, then prove the repository is still readable.
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune
restic check
Envíala a una máquina en una jurisdicción distinta de la forja, a través de un repositorio de solo anexado para que un compromiso de la forja no pueda borrar su propio historial — la guía de copias de seguridad cifradas es la versión larga de las tres líneas de arriba, incluyendo el temporizador de systemd y la restricción de clave de solo anexado.
Luego restáurala una vez, a propósito. Pide un VPS de prueba, restaura la instantánea en él, levanta el mismo archivo de Compose contra el directorio de datos restaurado, carga el volcado de la base de datos, apunta una entrada del archivo hosts hacia él e inicia sesión. Cronometra todo el proceso. Ese número — no la mera existencia de la tarea de copia de seguridad — es tu posición real de recuperación, y todo el que ha hecho este ejercicio se ha encontrado al menos una cosa que faltaba en la lista de inclusión la primera vez.
# restic keeps absolute paths, so the stack reappears under the target.
restic restore latest --target /srv/restore
cd /srv/restore/srv/forgejo
docker compose up -d db # empty volume: the entrypoint creates the database
docker compose exec -T db pg_restore -U forgejo -d forgejo \
--clean --if-exists --no-owner < db.dump
docker compose up -d # then sign in and walk the issue tracker
Actualizaciones, brevemente. Fija la imagen a una versión mayor en lugar de :latest, para que una descarga desatendida no te haga cruzar un cambio incompatible mientras duermes. Lee las notas de la versión antes de cruzar un límite de versión mayor, toma antes una instantánea, y recuerda que una migración de base de datos se ejecuta en el primer arranque de la nueva versión — lo cual es una puerta sin retorno. La actualización automática al estilo Watchtower es una buena idea para un sitio estático y una mala idea para la máquina que retiene todas tus ramas.
Cuatro comprobaciones antes de darlo por terminado. Cierra sesión y confirma que la instancia no ofrece ninguna manera de crear una cuenta. Desde un navegador sin sesión, confirma que un repositorio privado es invisible y no simplemente está prohibido. Confirma que el ejecutor no puede leer el directorio de datos de la forja. Y confirma que el último restic check pasó — la tarea de copia de seguridad que falla en silencio es la que todo el mundo tiene, hasta el día en que la necesita.
Has eliminado a una de las partes. No has eliminado el edificio.
Autoalojar una forja es un cambio real en quién retiene tu trabajo, y no es invisibilidad. Cuatro cosas siguen siendo ciertas después de hacer todo lo anterior, y conocerlas es la diferencia entre una defensa real y una historia que te cuentas a ti mismo.
El disco está en el edificio de alguien. Un servidor alquilado funciona sobre hardware en un centro de datos con puertas y personal. NordBastion no inspecciona las cargas de trabajo de los clientes, y el informe de transparencia y el warrant canary describen qué pasaría si nos lo pidieran — pero la declaración arquitectónica es la honesta: lo que cambia es que no hay ningún índice a nivel de producto de tus repositorios, ningún pipeline de analítica sobre tus commits y ninguna política de privacidad que se pueda enmendar. Lo que no cambia es que la máquina es física y no está en tu casa.
El nombre de host se vuelve público en el momento en que se emite el certificado. Todo certificado de confianza pública se publica en registros de transparencia de certificados que cualquiera puede consultar, así que git.yourproject.com es descubrible aunque nunca enlaces a él. Eso no es una filtración de tu código, pero sí es una filtración del hecho de que el proyecto existe y de aproximadamente cuándo empezó. Usa un subdominio de un nombre que ya publiques, o prescinde por completo del certificado público y accede a la forja por WireGuard o un servicio onion.
Ahora estás parcheando una aplicación web. La forja es una página de inicio de sesión, un pipeline de renderizado para marcado no confiable, un servidor SSH y un motor de CI, todo ello accesible desde internet. Esa es una superficie considerablemente mayor que la del repositorio desnudo del paso 01, y es una superficie que tienes que mantener al día. Suscríbete a los anuncios de versiones, y trata una versión de seguridad como una tarea de esta misma semana y no de este mismo trimestre.
La federación todavía no ha llegado. Forgejo está haciendo un trabajo real en la federación de forjas y publica sus avances al respecto, pero a día de hoy no puedes abrir un pull request en la instancia de otra persona desde la tuya, como sí puedes hacer en una plataforma compartida. En la práctica, eso significa que un colaborador externo todavía necesita una cuenta en tu forja, o aceptas parches por correo electrónico, o mantienes un espejo público para contribuciones ocasionales. Prepárate para la que de las tres encaje con tu proyecto, en lugar de dejar que te sorprenda.
Lo que en realidad has comprado, con precisión: el registro fechado de lo que construyes, con quién, y cuándo, ya no lo retiene una empresa cuyo modelo de negocio incluye analizarlo. Esa es una afirmación limitada, y es una afirmación real. Vale lo que cuesta solo si el paso 06 está hecho — una forja autoalojada sin una restauración probada no es una mejora de privacidad, es un punto único de fallo con mejor imagen de marca.
La forja es pequeña. La CI no lo es.
| Nivel | Mensual | Recursos | Qué ejecuta con holgura |
|---|---|---|---|
| Sentinel | $3.90 | 2 vCPU · 4 GB · 120 GB | Forgejo + PostgreSQL para una persona o un equipo pequeño. El punto de partida correcto. |
| Un segundo Sentinel | $3.90 | El ejecutor, en su propia máquina | El aislamiento que de verdad importa, por el precio de un café |
| Garrison | $7.90 | 4 vCPU · 8 GB · 240 GB | Una forja para diez personas, un registro de contenedores y artefactos |
| Ravelin | $16.90 | 8 vCPU · 16 GB · 480 GB | CI con mucha carga, repositorios grandes, varios trabajos en paralelo |
Nada en esta tabla está dimensionado para Git. Forgejo y PostgreSQL juntos reposan en unos pocos cientos de megabytes; lo que llena una máquina es la CI — capas de contenedor, cachés de compilación, artefactos — y contenido de repositorio que no es código fuente. Dimensiona primero por el disco, luego por los núcleos, y por último por la memoria. Aquí, dos máquinas pequeñas superan a una grande, porque la segunda es un límite de seguridad y no una cuestión de capacidad.
Seis maneras en que esto sale mal. Dos de ellas cuestan dinero.
Registro abierto, y una forja llena de desconocidos
El certificado aparece en los registros de transparencia, los escáneres llegan a los pocos días, y una instancia con las altas habilitadas se llena de cuentas de spam y repositorios de spam. Configura DISABLE_REGISTRATION antes del primer arranque, no después del primer incidente.
El ejecutor que mina criptomonedas para otra persona
Una CI que ejecuta flujos de trabajo de cualquier pull request es cómputo gratuito para quien lo encuentre. Exige aprobación para quienes contribuyen por primera vez, mantén el ejecutor en su propia máquina, y revisa de vez en cuando la duración de los trabajos.
ROOT_URL mal configurado, y todo funciona a medias
Las URL de clonado apuntan al host equivocado, los webhooks se disparan hacia la dirección equivocada, los callbacks de OAuth fallan y los avatares se rompen. La interfaz se ve bien, así que nadie sospecha de una sola línea. Configura DOMAIN, ROOT_URL, SSH_DOMAIN y SSH_PORT juntos, y comprueba una URL de clonado en la interfaz.
Dos servidores SSH, un puerto
El contenedor quiere el 22 y el host ya lo está usando, así que el mapeo aterriza silenciosamente en algún sitio inesperado y git push pide una contraseña. Mueve primero el SSH administrativo, publica el contenedor en un puerto propio, y verifica con ssh -T.
Un volcado que nunca se ha restaurado
El archivo integrado es un artefacto de soporte, no una vía de recuperación probada, y su SQL tiene problemas conocidos al reimportar. Vuelca la base de datos con pg_dump, respalda el directorio de datos como archivos, y restaura el conjunto completo en una máquina de prueba una vez.
El disco se llena de capas de compilación, no de código
El código fuente es diminuto; las capas de contenedor, los artefactos y las cachés de CI no lo son. Una máquina de 120 GB con un pipeline entusiasta se llena por completo en semanas. Poda las imágenes con un temporizador, limita la retención de artefactos, y vigila el disco en lugar de la CPU.
Preguntas, respondidas.
Once preguntas que surgen al construir esto — empezando por las dos que deciden si deberías construirlo siquiera.
Forgejo o Gitea: ¿cuál deberías instalar en realidad?
Forgejo, para la mayoría de las personas, y el motivo es la gobernanza más que las funciones. Los dos proyectos comparten un antepasado y siguen sintiéndose casi idénticos de usar: el mismo binario en Go, la misma huella ligera, la misma interfaz web, una CI comparable. Lo que difiere es quién los dirige. Forgejo está en manos de Codeberg e.V., una asociación registrada sin ánimo de lucro en Berlin, y se convirtió en una bifurcación completa a principios de 2024; publica todo como software libre y no pide a los colaboradores que cedan sus derechos de autor. Gitea lo desarrolla una empresa con fines de lucro que posee la marca y el dominio, exige la cesión de derechos de autor a los colaboradores, y sigue un modelo open core con funciones de pago alrededor de la base gratuita. Ninguno de esos hechos hace de Gitea un mal software. Pero el objetivo de sacar tus repositorios de una plataforma es dejar de depender de la hoja de ruta de una empresa, así que elegir la bifurcación cuyo custodio es una organización sin ánimo de lucro es la opción que coincide con el motivo por el que estás aquí. Una nota práctica si cambias más adelante: Forgejo puede instalarse sobre un directorio de datos de Gitea ya existente; hacerlo en sentido contrario no es compatible.
¿Necesito siquiera una forja? ¿No basta con un repositorio desnudo por SSH?
Para una sola persona con un portátil y la costumbre de escribir buenos mensajes de commit, un repositorio desnudo basta de verdad, y es lo más robusto de toda esta guía: git init --bare en el servidor, una cuenta SSH normal, y no hay ninguna aplicación web que parchear, ninguna base de datos que respaldar ni más superficie de ataque que sshd. Nada de esa configuración llegará jamás a su fin de vida. Necesitas una forja en el momento en que interviene una segunda persona, o en el momento en que quieres cualquiera de las cuatro cosas que un repositorio desnudo no contempla: un historial navegable, pull requests con revisión, un gestor de incidencias junto al código, y control de acceso por repositorio. Eso no es un pequeño salto; es la diferencia entre almacenamiento y colaboración. Sé honesto sobre cuál de los dos problemas estás resolviendo, porque una forja es un servicio que ahora operas tú, y un repositorio desnudo es un directorio.
¿Puedo migrar mis repositorios de GitHub, incluidas las incidencias y los pull requests?
Sí, y es una de las mejores experiencias de migración que hay en el autoalojamiento. La herramienta de migración integrada de Forgejo toma una URL de repositorio y un token de acceso personal, y trae mucho más que el código: ramas y etiquetas, incidencias con sus comentarios, pull requests, etiquetas, hitos y lanzamientos. Dale un token con alcance de lectura, ejecuta primero un repositorio para ver cómo queda el resultado, y luego sigue con el resto. Tres cosas que esperar. Las migraciones grandes o numerosas toparán con los límites de tasa de la API de la plataforma de origen y sencillamente tardarán más — inícialas y déjalas ir. Los archivos adjuntos de las incidencias se descargan por red, así que una instancia detrás de un cortafuegos de salida restrictivo producirá incidencias con imágenes rotas. Y los hilos de revisión no siempre acaban exactamente donde estaban, porque los dos modelos de datos no son idénticos. Prevé mantener los repositorios de origen en solo lectura durante unas semanas en lugar de borrarlos esa misma tarde.
¿Es una forja autoalojada realmente más privada, o solo distinta?
Es genuinamente distinta en un aspecto concreto e importante: nadie más que tú tiene el índice. En una plataforma, el repositorio privado es privado para los demás usuarios — no es privado para la plataforma, que lo almacena, lo escanea, calcula a partir de él un grafo de dependencias, y puede verse obligada a entregarlo por un tribunal de su propia jurisdicción. Ese índice es inusualmente revelador incluso cuando el código es aburrido: las marcas de tiempo de los commits describen tu horario de trabajo, los coautores describen a tu equipo, los nombres de las ramas describen productos que nadie ha anunciado, y el primer commit fecha un proyecto que no se ha hecho público. Trasladarlo a tu propio servidor elimina a la plataforma por completo de esa imagen. Lo que no hace es que la máquina desaparezca. Sigues alquilando hardware en un centro de datos, el disco sigue siendo físicamente accesible para quienes son dueños del edificio, y el nombre de host que elegiste sigue estando en los registros de transparencia de certificados. El resumen honesto: has sustituido una empresa con una política de privacidad contractual por un servidor cuya única política es tu configuración, en una jurisdicción que elegiste deliberadamente — y la cuenta que lo paga no tiene por qué llevar tu nombre.
¿Qué tamaño de VPS hace falta?
Más pequeño de lo que la documentación de GitLab ha entrenado a todo el mundo a esperar. Forgejo y Gitea son binarios únicos en Go que reposan en un par de cientos de megabytes de RAM; añade PostgreSQL y un proxy inverso, y la forja de un desarrollador en solitario cabe cómodamente en un Sentinel — 2 vCPU, 4 GB, 120 GB NVMe, $3.90 al mes — con margen de sobra. La presión viene de otros tres sitios, y cada uno de ellos merece que se dimensione a propósito. La CI es la principal: un ejecutor que construye contenedores usará todos los núcleos que le des y llenará el disco de capas. El tamaño del repositorio es el segundo: los recursos de videojuegos, los notebooks y las dependencias empaquetadas crecen mucho más rápido que el código fuente. Los artefactos y un registro de contenedores son el tercero. Una regla que ha funcionado bien en la práctica: pon la forja en un Sentinel, pon el ejecutor en su propio segundo Sentinel, y sube de nivel solo cuando lo pida el disco y no cuando lo pida la CPU.
¿Es Forgejo Actions realmente compatible con mis flujos de trabajo de GitHub Actions?
Lo bastante compatible como para que la mayoría de los flujos de trabajo sencillos se ejecuten sin cambios, y no tan compatible como para migrar un pipeline complejo sin leerlo antes. El formato del archivo de flujo de trabajo es el mismo, vive en .forgejo/workflows/ (y también se lee .github/workflows/), y los bloques habituales — checkout, configuración del lenguaje, caché, compilaciones matriciales — se comportan como cabría esperar porque el ejecutor los ejecuta en contenedores de la misma manera. Lo que se rompe es todo aquello que da por hecho GitHub la plataforma en lugar de Actions el formato: acciones del marketplace ancladas a URLs de github.com que tu instancia tiene que poder consultar, acciones que llaman a la API REST de GitHub para obtener metadatos de lanzamientos o de PR, imágenes de ejecutor alojadas por GitHub con un conjunto de herramientas preinstalado muy específico, y autenticación en la nube basada en OIDC. El patrón de migración que funciona: empieza con un flujo de trabajo que solo compile y pruebe, consigue que pase en verde, y luego vuelve a añadir los pasos de despliegue de uno en uno.
¿Qué pasa con mi código si el VPS muere?
El código en sí es la única parte que está a salvo, y esa es la ventaja silenciosa de Git sobre casi cualquier otro servicio autoalojado: cada clon es una copia completa del historial, así que mientras un solo desarrollador tenga una copia de trabajo actualizada, el repositorio no se pierde. Lo que muere con el servidor es todo lo que rodea al código — incidencias, discusiones de pull requests, comentarios de revisión, lanzamientos, wiki, usuarios, reglas de acceso, historial de CI. Ese material solo existe en la base de datos, nadie tiene un clon de él, y suele ser la parte que ha tardado años en acumularse. Así que trata las dos cosas de forma distinta. Para el código, configura un espejo push hacia una segunda ubicación y tendrás protección externa, continua y automática sin ningún esfuerzo. Para los metadatos necesitas una copia de seguridad real: un volcado de PostgreSQL más el directorio de datos, cifrados y enviados a una máquina en otra jurisdicción según un temporizador. El paso 06 cubre ambas cosas, y el simulacro de restauración al final es lo que las convierte de una intención en una garantía.
¿Puedo mantener GitHub como espejo en lugar de abandonarlo del todo?
Sí, y para muchos proyectos esa es la respuesta correcta y no un compromiso a medias. Forgejo admite espejos push, así que tu instancia es el origen contra el que trabaja tu equipo y cada push se replica automáticamente a un repositorio en GitHub, Codeberg o un segundo Forgejo. La visibilidad pública, los contribuidores ocasionales, los registros de paquetes que esperan una URL de GitHub y el enlace al gestor de incidencias en un README antiguo siguen funcionando, mientras que la fuente de verdad — y los repositorios privados, y los registros de CI, y el historial de incidencias de todo lo que no publicas — se queda en tu máquina. También funciona en la otra dirección: los espejos pull mantienen una copia local y siempre actualizada de los proyectos de terceros de los que dependes, algo que vale la pena para cualquier cosa con la que te quedarías atascado si desapareciera mañana. Lo único con lo que hay que ser deliberado es qué estás replicando: un espejo push de un repositorio cuyo historial contiene un secreto que querías eliminar vuelve a publicar ese secreto, de inmediato y automáticamente.
¿Cómo doy acceso a un contratista a un repositorio sin darle acceso al resto?
Usa la capa que corresponda a cuánto debe durar el acceso. Para una persona que va a leer, hacer commits y abrir pull requests, crea una cuenta de usuario y añádela como colaboradora exactamente en los repositorios que necesita, con un nivel de permiso explícito — lectura, escritura o administración — en lugar de meterla en un equipo de la organización que le concede más sin que nadie lo note. Para un sistema automatizado que solo necesita hacer fetch — un destino de despliegue, una máquina de compilación, un espejo — usa una clave de despliegue de solo lectura en vez de una cuenta de usuario: está limitada a un repositorio, no concede nada más, y revocarla es borrar una línea. Para los scripts que hablan con la API, emite un token de acceso con alcance limitado en lugar de entregar una contraseña. Dos hábitos hacen que todo esto se sostenga: mantén el registro cerrado para que las únicas cuentas que existan sean las que tú has creado, y pon una fecha en tu calendario cuando concedas acceso temporal, porque ninguna forja te recordará jamás que un contrato terminó.
¿Necesita la forja un nombre de dominio, y eso filtra mi identidad?
Necesita un nombre de host para la interfaz web, porque los certificados TLS se emiten para nombres y aquí ningún navegador debería confiar en una dirección IP. No necesita que ese nombre se pueda rastrear hasta ti. Tres cosas en las que hay que ser deliberado. Registra el dominio en algún sitio que no exija la identidad que cuidaste en otra parte, y mantén activada la privacidad de WHOIS — el registrador es una decisión de confianza separada del host, y es la que la gente olvida. Cuenta con que el nombre de host se vuelva público en el momento en que se emita el certificado, porque todo certificado de confianza pública se publica en registros de transparencia de certificados que cualquiera puede consultar; un comodín sobre un dominio que ya usas evita añadir un nombre nuevo y buscable. Y si prefieres no tener ningún nombre público en absoluto, la alternativa es real: pon la forja en un servicio onion de Tor o hazla accesible solo por WireGuard, prescinde por completo del certificado público, y acepta que con ello se va también la comodidad de abrir un navegador desde cualquier sitio.
¿Le importa a NordBastion que ejecute una forja Git y ejecutores de CI en un VPS?
En absoluto — una forja y sus ejecutores son una carga de trabajo corriente, y es una de las cosas más habituales que construyen nuestros clientes. La política de uso aceptable no dice nada sobre alojar código fuente o compilarlo. Dos notas operativas, no de política. Primero, un ejecutor de CI que acepta flujos de trabajo de desconocidos es un servicio de cómputo gratuito para quien lo encuentre: el abuso habitual es el minado de criptomonedas en un pull request, y se detectará a los pocos días de estar abierto. Mantén el registro cerrado, y exige aprobación antes de ejecutar flujos de trabajo de cualquiera que no sea ya colaborador. Segundo, si tus compilaciones descargan imágenes de contenedor grandes en cada ejecución, eso es tráfico normal y está incluido — pero aun así vale la pena cachearlas localmente, porque hace tu pipeline más rápido y es de buena educación con los registros externos de los que dependes.
Una forja propia, en una cuenta que no es tu nombre. Sin KYC, pago en criptomoneda.
Sentinel — 2 vCPU y 4 GB por $3.90 al mes, en Helsinki, Stockholm, Oslo o Reykjavík. Suficiente para Forgejo, PostgreSQL y el proxy inverso, con margen para los repositorios que llevas tiempo queriendo trasladar. Añade un segundo para el ejecutor. Sin correo electrónico al darte de alta, sin documento de identidad, y sin ningún índice a nivel de producto de nada de lo que subas.
Última revisión · 2026-10-12 · Fuentes · Documentación de administración de Forgejo (instalación, Actions, línea de comandos), la comparación de Forgejo con Gitea, las páginas de gobernanza de Codeberg e.V., la documentación de PostgreSQL y Caddy, git-config(1) · Cadencia · anual
Anonymous VPS hosting in 2026 — the cluster.
This guide is one spoke of a larger series. The pillar walks the three privacy layers end to end — the sibling spokes below dive into the specifics.
Three independent layers — signup, payment, network — explained, legal context included, common mistakes flagged.
Bitwarden-compatible password vault under your own control.
Files, calendar, contacts, photos — owned, not rented.
Postfix, Dovecot, SPF/DKIM/DMARC — deliverability included.
A meta search engine that does not log you — because you own it.