Version: 1.5.0
Fecha: 5 de Agosto, 2026
Estado: NORMATIVO - Procedimiento de Referencia
Arquitecto: Carlos Alberto Torres Camargo
Audiencia: Desarrolladores Backend (Senior, Semi-Senior y Junior)
Este flujo describe como ejecutar un solo microservicio en tu maquina consumiendo la infraestructura de plataforma que ya esta corriendo en el servidor (Eureka, Config-Server, OAuth2 y Gateway), en lugar de levantar todo el stack localmente.
Es la alternativa ligera al Flujo de Arranque Local, que levanta toda la infraestructura y los servicios de plataforma con Docker en el propio PC.
| Enfoque | Que corre local | Cuando conviene |
|---|---|---|
| Arranque Local (todo local) | BD + Eureka + Config + Gateway + OAuth2 + servicio | Trabajo offline, sin VPN, o cambios en la plataforma misma |
| Prueba local con tunel SSH (este flujo) | Solo tu microservicio | Iteracion rapida sobre un servicio contra la plataforma real y poblada de DEV |
NOTA SOBRE RUTAS (importante). Las rutas que aparecen en este documento (
~/code/centrica/backend/,~/environment/<dominio>/.env, etc.) reflejan la estructura de directorios del workspace de referencia del arquitecto, no una ruta obligatoria. Cada desarrollador debe ajustarlas a la raiz y el layout de su propia maquina. Lo que importa es la relacion entre las piezas (script de tunel +local-dev.env+ repo del servicio + espejo del.envdel dominio), no la ruta absoluta. Como toda la parametrizacion vive enlocal-dev.env(seccion 5), basta con poner ahi tus rutas reales (SERVICE_DIR,DOMAIN_ENV_FILE) y el script funciona igual.
El tunel SSH usa un unico proceso (ControlMaster) que reenvia a localhost los puertos de la infraestructura expuestos en el nodo. Tu servicio local "cree" que la plataforma corre en su propia maquina.
| Servicio de plataforma | Puerto | Para que lo usa tu servicio |
|---|---|---|
| Eureka | 8761 | Registro y descubrimiento de servicios |
| Config-Server | 8890 | Resolucion de configuracion en el bootstrap (config import) |
| OAuth2 | 8787 | Validacion de tokens / login |
| Gateway | 8090 | Consumo de otros modulos (nebula-*, simappe-admin, simappe-client) |
Regla: los servicios
nebula-*ysimappe-clientno exponen puerto host propio en el nodo (0/tcp): se consumen siempre via Gateway (localhost:8090), nunca por puerto directo.
Cuando tu servicio local X llama a otros servicios Y y Z del ecosistema (p.ej. nebula-masters, simappe-admin, nebula-shared clients), esas llamadas salen por el Gateway (localhost:8090 a traves del tunel), nunca a un puerto directo de Y/Z. El Gateway las enruta a las instancias reales de Y y Z que corren en el nodo.
Motivo: los nebula-* y simappe-* no exponen puerto host; el unico punto de entrada es el Gateway. Es la misma razon por la que simappe.admin.url debe ser una URL del Gateway (ver incidente OAuth2).
Para que las URLs de cliente de X resuelvan al Gateway tunelado, depende del perfil:
Perfil (APP_PROFILE) |
URLs de plataforma en el config | Que necesitas |
|---|---|---|
dev (estandar, recomendado) |
usan hostnames Docker (simappe-gateway-server:8090, simappe-eureka-server:8761, ...) |
Obligatorio: registrar esos hostnames en /etc/hosts contra la IP interna del nodo (ver abajo) |
localhost (alternativa sin /etc/hosts) |
ya apuntan a localhost:8090 / 8761 / 8890 / 8787 |
Nada extra: el tunel las reenvia |
Como el flujo estandar usa perfil dev, es obligatorio registrar estos hostnames en /etc/hosts (una sola vez) para que las URLs Docker resuelvan.
10.120.0.2)Los hostnames Docker se resuelven siempre contra la IP interna de DEV, que solo existe dentro de la VPN. Esto cubre tanto la plataforma (config, eureka, gateway, oauth2) como los backing services que tu servicio local necesita de forma directa: Oracle, Postgres, Mongo, Kafka y Redis. Sin ellos el servicio no levanta ni se conecta a la base de datos.
1. Archivo a editar: /etc/hosts (requiere sudo). Linea unica:
10.120.0.2 simappe-config-server simappe-eureka-server simappe-gateway-server simappe-oauth2-server oracle-xe redis-dev kafka-dev postgres-dev mongodb-dev
2. Registro automatico (idempotente) — pega este comando una sola vez; solo agrega la entrada si no existe:
LINE='10.120.0.2 simappe-config-server simappe-eureka-server simappe-gateway-server simappe-oauth2-server oracle-xe redis-dev kafka-dev postgres-dev mongodb-dev'
grep -qF 'simappe-gateway-server' /etc/hosts || echo "$LINE" | sudo tee -a /etc/hosts
3. Verificar:
getent hosts simappe-gateway-server # debe responder 10.120.0.2
getent hosts oracle-xe # debe responder 10.120.0.2
Sin este registro, el servicio local no resuelve la plataforma y falla el bootstrap/llamadas.
Nada apunta a
127.0.0.1ni a un host publico. El unico camino es la red interna por VPN: sin VPN conectada, ningun hostname es alcanzable.
| # | Requisito | Verificacion |
|---|---|---|
| 1 | VPN de Centrica activa — el nodo NO es alcanzable por Internet | ping 10.120.0.2 responde. Ver Diagnostico Conexion VPN |
| 2 | Cuenta SSH restringida en nodo-01, con tu llave publica instalada | ssh nodo-01 NO abre sesion pero tampoco pide contrasena. Ver seccion 3.1 |
| 3 | Toolchain backend instalado (JDK 25 Corretto, Maven 3.9.12, settings.xml de Nexus) |
java -version, mvn -version. Ver Setup Ambiente de Desarrollo |
| 4 | Servicio clonado y compilado | mvn -o clean package verde (el arranque se hace con mvn spring-boot:run, ver Paso 3) |
| 5 | Espejo local de los .env del dominio |
Existe ~/environment/<dominio>/.env. Ver Variables de Entorno Local |
| 6 | Hostnames Docker registrados en /etc/hosts (obligatorio con perfil dev) |
Plataforma y backing services (oracle-xe, postgres-dev, mongodb-dev, kafka-dev, redis-dev) → 10.120.0.2. Ver seccion 2. Requiere sudo en TU PC |
| 7 | Puertos locales 8761 / 8890 / 8787 / 8090 libres | ss -ltn no los muestra ocupados. Si tienes infra local en Docker, bajala antes (ver regla 7) |
Alcance del acceso. La cuenta del nodo existe unicamente para reenviar esos 4 puertos de DEV (nodo-01). No da shell, no ejecuta comandos, no tiene sudo ni docker, y no alcanza Oracle, Postgres, Mongo, Kafka ni Redis. QA (nodo-02) no esta contemplado en este acceso.
Esta seccion se hace una sola vez. Sigue los pasos en orden; no te saltes ninguno.
Una llave SSH son dos archivos: uno privado (se queda en tu PC para siempre) y uno publico (el que entregas). Ejecuta en tu terminal, reemplazando <tu-usuario> por el login que te asignaron (liderbackend1, seniorbackend1, juniorbackend1 o juniorbackend2):
ssh-keygen -t ed25519 -C "<tu-usuario>@centrica" -f ~/.ssh/id_ed25519_nebula
Te va a preguntar dos cosas:
Enter passphrase → escribe una frase de seguridad y recuerdala. (Si pulsas Enter dos veces se crea sin frase: funciona igual, pero cualquiera que tome tu PC podria abrir el tunel).Enter same passphrase again → repite la misma.Al terminar quedan dos archivos:
| Archivo | Que es | Que haces con el |
|---|---|---|
~/.ssh/id_ed25519_nebula |
Llave PRIVADA | NUNCA la envias, ni la copias, ni la subes a Git. Se queda en tu PC. |
~/.ssh/id_ed25519_nebula.pub |
Llave PUBLICA | Es la que entregas al arquitecto. |
Regla de oro: lo unico que sale de tu PC es el archivo que termina en
.pub. Si envias el otro, hay que borrar todo y empezar de cero.
cat ~/.ssh/id_ed25519_nebula.pub
Sale una sola linea parecida a esta:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx juniorbackend1@centrica
Verifica antes de enviarla:
ssh-ed25519. Si empieza con -----BEGIN, estas mirando la llave privada: no la envies.Envia esa linea al arquitecto por el canal interno del equipo, indicando cual es tu login (liderbackend1, seniorbackend1, juniorbackend1 o juniorbackend2). El arquitecto es quien la instala en el nodo; nadie mas lo hace.
Espera su confirmacion de que la cuenta quedo creada antes de seguir.
~/.ssh/configAbre (o crea) el archivo ~/.ssh/config y pega este bloque, cambiando solo la linea User por tu login:
Host nodo-01
HostName 10.120.0.2
Port 2202
User <tu-usuario>
IdentityFile ~/.ssh/id_ed25519_nebula
IdentitiesOnly yes
Deja el archivo con permisos correctos:
chmod 600 ~/.ssh/config
10.120.0.2es una direccion interna: solo existe dentro de la VPN. Esto es intencional — el nodo no se expone a Internet. Sin VPN conectada no vas a poder entrar, y eso es lo esperado.
Levanta la VPN de Centrica y comprueba que el nodo responde:
ping -c 2 10.120.0.2
Si no responde, el problema es la VPN, no el tunel. Ver Diagnostico Conexion VPN.
ssh nodo-01
Lo correcto es que NO te deje entrar. Vas a ver algo como This account is currently not available. o la conexion se cierra de inmediato. Eso significa que tu acceso funciona. Tu cuenta esta hecha para reenviar puertos, no para darte una consola en el servidor.
Como leer el resultado:
| Lo que ves | Que significa | Que haces |
|---|---|---|
This account is currently not available / se cierra al instante |
Correcto. Autenticaste bien y la cuenta es restringida | Sigue al paso A7 |
Te pide contrasena (password:) |
El nodo no reconocio tu llave | Avisa al arquitecto: la llave no quedo instalada o enviaste una distinta |
Permission denied (publickey) |
Tu llave no coincide con la registrada | Avisa al arquitecto con tu .pub de nuevo |
Connection timed out / No route to host |
No hay VPN | Conecta la VPN (paso A5) |
Te da un prompt del servidor (usuario@nodo-01:~$) |
Estas usando una cuenta que no es la tuya | Detente y avisa al arquitecto |
Esta es la prueba definitiva de que tu cuenta sirve para lo que tiene que servir. Abre un reenvio de prueba del puerto de Eureka:
ssh -fN -L 8761:127.0.0.1:8761 nodo-01
No imprime nada (queda corriendo en segundo plano). Comprueba que el puerto quedo escuchando en tu PC:
ss -ltn | grep 8761
Debe aparecer una linea con 127.0.0.1:8761. Cierra la prueba:
pkill -f "ssh -fN -L 8761"
| Lo que ves | Que significa |
|---|---|
El puerto aparece en ss -ltn |
Tu acceso quedo listo. Continua con la seccion 4 |
channel ... open failed: administratively prohibited |
Pediste un puerto que tu llave no autoriza. Solo se permiten 8761, 8890, 8787 y 8090 |
bind: Address already in use |
Ese puerto ya esta ocupado en TU PC (infra local en Docker). Bajala primero — ver regla 7 |
Con esto terminas la configuracion inicial. De aqui en adelante tu rutina diaria es solo la seccion 4.
La provision y la revocacion se hacen con el script versionado
nodo01-ssh-dev-access.sh, que se ejecuta desde el PC del arquitecto (con VPN y sudo en nodo-01). No queda instalado nada en el servidor.
cd zona-interna/02-infraestructura/scripts
# 0) Una vez: verificar que el nodo admite este modelo (sshd, forwarding, ACLs)
./nodo01-ssh-dev-access.sh preflight
# 1) Crear las 4 cuentas backend de una vez, SIN llave (existen pero sin acceso)
./nodo01-ssh-dev-access.sh bootstrap
# 2) Habilitar el acceso de un desarrollador cuando entregue su llave publica
./nodo01-ssh-dev-access.sh add juniorbackend1 ~/llaves-recibidas/juniorbackend1.pub "Kevin"
# 3) Auditar quien tiene acceso
./nodo01-ssh-dev-access.sh list
./nodo01-ssh-dev-access.sh show juniorbackend1
# 4) Revocar (conserva la cuenta bloqueada y respalda la llave retirada)
./nodo01-ssh-dev-access.sh revoke juniorbackend1
# 5) Baja definitiva (elimina la cuenta y su home)
./nodo01-ssh-dev-access.sh remove juniorbackend1
bootstrap crea las cuatro cuentas de golpe con el titular en el campo GECOS, pero sin authorized_keys: la cuenta existe y queda auditable, y no da acceso hasta que se instale la llave con add.
Lo que hace add en el nodo:
Crea la cuenta con shell /usr/sbin/nologin, en el grupo aislado devtunnel, sin sudo y sin docker (y la saca de esos grupos si estuviera en ellos).
Bloquea la autenticacion por contrasena: el unico acceso posible es por llave.
Instala una llave con las opciones restringidas:
restrict,port-forwarding,permitopen="127.0.0.1:8761",permitopen="127.0.0.1:8890",permitopen="127.0.0.1:8787",permitopen="127.0.0.1:8090" ssh-ed25519 AAAA...
restrict apaga todo (shell interactiva, agente, X11, user-rc) y permitopen limita el reenvio a esos cuatro destinos. Cualquier otro puerto del nodo queda fuera de alcance.
El script rechaza una llave privada enviada por error, una llave invalida, un archivo con mas de una llave, y avisa si el login no esta en la lista de backend autorizados (liderbackend1, seniorbackend1, juniorbackend1, juniorbackend2).
| Login | Titular | Rol | Nodo | Estado |
|---|---|---|---|---|
liderbackend1 |
Vanessa Luna | Lider backend | nodo-01 (DEV) | Llave configurada |
seniorbackend1 |
Jhoan Sebastian Saldarriaga Villada | Senior backend | nodo-01 (DEV) | Pendiente de llave |
juniorbackend1 |
Kevin | Junior backend | nodo-01 (DEV) | Llave configurada |
juniorbackend2 |
Brahian | Junior backend | nodo-01 (DEV) | Llave configurada |
Mantener esta tabla actualizada en cada alta y baja.
listdel script es la fuente de verdad contra la que se concilia.
Antes de empezar: conecta la VPN. Sin VPN no hay SSH al nodo y por lo tanto no hay tunel (seccion 3.1, paso A5).
cd <directorio-de-tus-scripts> # donde tengas infra-tunnel.sh y local-dev.env
./infra-tunnel.sh up
./infra-tunnel.sh status # OK eureka/config/oauth2/gateway
La primera vez debes crear tu local-dev.env (una sola vez, ver seccion 5.1):
cp local-dev.env.example local-dev.env && $EDITOR local-dev.env
Con
/etc/hostsapuntando a10.120.0.2(seccion 2), los hostnames resuelven directo contra el nodo por la VPN y este paso se omite: los puertos ya son alcanzables y el resto del procedimiento es identico.
.env completo)Sin DB_ENCRYPTION_KEY todo request tenant-scoped revienta con 500 (ConnectionSchemaCipher: NO inicializado). Pero el .env del dominio no se puede sourcear tal cual, por dos razones verificadas:
JAVA_TOOL_OPTIONS multi-token (-XX:+UseSerialGC -XX:MaxRAMPercentage=75.0 ...): al sourcear en bash, la shell intenta ejecutar -XX:MaxRAMPercentage=75.0 → orden no encontrada. En el servidor no pasa porque Docker lo inyecta con env_file, no por shell.JAVA_TOOL_OPTIONS incluye -Dserver.port=0: si se exporta, tu servicio arranca en un puerto aleatorio en vez del que fijaste.Exporta solo las variables necesarias:
ENVF=~/environment/nebula/business-domains/finance/.env
set -a
eval "$(grep -E '^(SPRING_PROFILES_ACTIVE|APP_PROFILE|CONFIG_ENV|DB_ENCRYPTION_KEY|EUREKA_SERVICE_URL|CONFIG_GIT_URI|CONFIG_GIT_USERNAME|CONFIG_GIT_PASSWORD)=' "$ENVF")"
set +a
Detalle completo en Variables de Entorno Local.
mvn spring-boot:run (NUNCA java -jar)cd <repo-del-servicio>
mvn spring-boot:run -Dspring-boot.run.jvmArguments=-Dserver.port=8095
El perfil correcto es common,dev (lo aporta SPRING_PROFILES_ACTIVE del .env). common es indispensable: application-common.yml del Config-Server es donde se resuelve application.jwt.secret. Si arrancas con --spring.profiles.active=dev a secas —o con java -jar perdiendo common— falta el jwt secret y el servicio aborta en el arranque.
Con perfil dev el servicio resuelve la plataforma por los hostnames Docker, que por el /etc/hosts (prerequisito #6) apuntan a 10.120.0.2: Config (:8890), Eureka (:8761), OAuth2 (:8787) y Gateway (:8090), ademas de los backing services (oracle-xe:1521, postgres-dev, mongodb-dev, kafka-dev, redis-dev).
Arranque correcto en el log: application.jwt.secret length=..., Fetching config from server at: ..., Started ... in Ns.
Perfil: el estandar es
common,dev, que requiere el registro/etc/hostsde la seccion 2. Alternativa sin/etc/hosts:APP_PROFILE=localhost, cuyas URLs ya sonlocalhost.
Puerto del servicio local: es el puerto donde escucha TU servicio (
-Dserver.port=; en el ejemplo8095). Reglas:
- Debe ser un puerto libre y distinto de los del tunel (
8761 / 8890 / 8787 / 8090) y de cualquier otro servicio local que corras en paralelo (usa8081,8082, ... uno por servicio).- No exportes
JAVA_TOOL_OPTIONS(trae-Dserver.port=0), o el puerto que fijaste se ignora.- Si tu servicio se registra en Eureka, anuncia ese puerto y el host de tu maquina; tenlo presente por la consideracion de Eureka compartido (otros podrian intentar enrutar hacia tu instancia local).
Todos los servicios exponen context-path /nebula-<servicio> (viene del Config-Server); la raiz / responde 404:
curl -s localhost:8095/nebula-accounting-core/actuator/health # {"status":"UP"}
Para un request tenant-scoped real (que confirma DB_ENCRYPTION_KEY):
Authorization: Bearer <token> y x-simappe-environment: dev.http://localhost:8095/nebula-accounting-core/api/v1/... (con context-path).page-response / get-record../infra-tunnel.sh down
Los scripts son archivos fijos y listos para usar (no plantillas que haya que editar). Toda la parametrizacion vive en un unico archivo .env de configuracion que el desarrollador crea con los valores de su servicio y nodo. Para cambiar de servicio o de ambiente solo se edita ese .env; los scripts nunca se tocan.
local-dev.env — unico archivo que crea/edita el desarrollador# ============================================================
# local-dev.env — configuracion de prueba local con tunel SSH.
# Crea este archivo con TUS valores. NO lo subas a Git.
# ============================================================
# --- Nodo destino (alias de ~/.ssh/config o IP) ---
SSH_HOST=nodo-01 # Solo DEV. Requiere VPN activa
# --- Puertos de infra a reenviar (formato "nombre:puerto", separados por espacio) ---
TUNNEL_PORTS="eureka:8761 config:8890 oauth2:8787 gateway:8090"
# --- Servicio a ejecutar ---
SERVICE_DIR=${HOME}/code/centrica/backend/nebula-treasury # repo del servicio (se arranca con mvn spring-boot:run)
APP_PROFILE=dev # dev (nodo-01). Estandar; requiere /etc/hosts (seccion 2). Alternativa sin hosts: localhost
SERVICE_PORT=8081 # puerto local de TU servicio; libre y != a 8761/8890/8787/8090 ni a otro servicio local
# --- Archivo .env del dominio con los secretos (DB_ENCRYPTION_KEY, etc.) ---
DOMAIN_ENV_FILE=${HOME}/environment/nebula/business-domains/finance/.env
| Parametro | Que define |
|---|---|
SSH_HOST |
Alias SSH del nodo DEV (nodo-01). Se resuelve a 10.120.0.2, alcanzable solo por VPN |
TUNNEL_PORTS |
Lista nombre:puerto de los servicios de plataforma a reenviar |
SERVICE_DIR |
Directorio del repo del microservicio a correr (mvn spring-boot:run) |
APP_PROFILE |
Perfil Spring del ambiente (dev) |
SERVICE_PORT |
Puerto local donde escucha tu servicio |
DOMAIN_ENV_FILE |
.env del dominio que aporta DB_ENCRYPTION_KEY y demas secretos |
Versiona en el repo un
local-dev.env.examplecon estos campos vacios/de ejemplo; ellocal-dev.envreal va en.gitignore.
infra-tunnel.sh — archivo listo (se alimenta de local-dev.env)#!/usr/bin/env bash
# infra-tunnel.sh {up|down|status|restart}
# Lee la configuracion de ./local-dev.env (o la ruta en $TUNNEL_CONF). No se edita el script.
set -euo pipefail
CONF="${TUNNEL_CONF:-$(dirname "$0")/local-dev.env}"
[ -f "$CONF" ] || { echo "No existe la config: $CONF"; exit 1; }
set -a; . "$CONF"; set +a
: "${SSH_HOST:?Falta SSH_HOST en $CONF}"
: "${TUNNEL_PORTS:?Falta TUNNEL_PORTS en $CONF}"
SOCKET="${HOME}/.ssh/cm-infra-tunnel-${SSH_HOST}.sock"
read -ra PORTS <<< "$TUNNEL_PORTS"
is_up() { ssh -S "$SOCKET" -O check "$SSH_HOST" 2>/dev/null; }
up() {
is_up && { echo "Tunel ya activo hacia $SSH_HOST."; status; return 0; }
local fwd=()
for s in "${PORTS[@]}"; do fwd+=( -L "127.0.0.1:${s#*:}:127.0.0.1:${s#*:}" ); done
ssh -fN -M -S "$SOCKET" \
-o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o ExitOnForwardFailure=yes \
"${fwd[@]}" "$SSH_HOST"
echo "Tunel ARRIBA hacia $SSH_HOST. Modulos nebula/client -> gateway."
}
down() { is_up && { ssh -S "$SOCKET" -O exit "$SSH_HOST" 2>/dev/null || true; echo "Tunel CERRADO."; } || echo "Sin tunel activo."; }
status() { is_up || { echo "Tunel INACTIVO."; return; }; for s in "${PORTS[@]}"; do (exec 3<>"/dev/tcp/127.0.0.1/${s#*:}") 2>/dev/null && echo " OK ${s%%:*} (:${s#*:})" || echo " FALLA ${s%%:*} (:${s#*:})"; done; }
case "${1:-}" in
up) up ;; down) down ;; restart) down; sleep 1; up ;; status) status ;;
*) echo "Uso: $0 {up|down|restart|status}"; exit 1 ;;
esac
run-local.sh — archivo listo (tunel + secretos del dominio + arranque)#!/usr/bin/env bash
# run-local.sh — levanta el tunel, carga los secretos del dominio y corre el servicio.
# Toda la parametrizacion vive en ./local-dev.env. Sin argumentos.
set -euo pipefail
DIR="$(cd "$(dirname "$0")" && pwd)"
CONF="${TUNNEL_CONF:-$DIR/local-dev.env}"
[ -f "$CONF" ] || { echo "No existe la config: $CONF"; exit 1; }
set -a; . "$CONF"; set +a
: "${SERVICE_DIR:?Falta SERVICE_DIR en $CONF}"
: "${DOMAIN_ENV_FILE:?Falta DOMAIN_ENV_FILE en $CONF}"
TUNNEL_CONF="$CONF" "$DIR/infra-tunnel.sh" up
[ -f "$DOMAIN_ENV_FILE" ] || { echo "No existe DOMAIN_ENV_FILE: $DOMAIN_ENV_FILE"; exit 1; }
# Exporta SOLO las variables necesarias: sourcear el .env completo rompe por
# JAVA_TOOL_OPTIONS multi-token y ademas impone -Dserver.port=0 (puerto aleatorio).
set -a
eval "$(grep -E '^(SPRING_PROFILES_ACTIVE|APP_PROFILE|CONFIG_ENV|DB_ENCRYPTION_KEY|EUREKA_SERVICE_URL|CONFIG_GIT_URI|CONFIG_GIT_USERNAME|CONFIG_GIT_PASSWORD)=' "$DOMAIN_ENV_FILE")"
set +a
APP_PROFILE="${APP_PROFILE:-dev}"
SPRING_PROFILES_ACTIVE="${SPRING_PROFILES_ACTIVE:-common,${APP_PROFILE}}" # 'common' aporta application.jwt.secret
export APP_PROFILE SPRING_PROFILES_ACTIVE
echo "Arrancando ${SERVICE_DIR} (perfiles=${SPRING_PROFILES_ACTIVE}, puerto=${SERVICE_PORT:-8081}, nodo=${SSH_HOST})"
cd "$SERVICE_DIR"
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-Dserver.port=${SERVICE_PORT:-8081}"
# 1) crear tu config una sola vez (no se versiona)
cp local-dev.env.example local-dev.env && $EDITOR local-dev.env
# 2) todo en uno: tunel + secretos + arranque
./run-local.sh
# o por separado, controlando el tunel
./infra-tunnel.sh up
./infra-tunnel.sh status
./infra-tunnel.sh down
Cambiar de servicio = editar
local-dev.env(SERVICE_DIR,SERVICE_PORT,DOMAIN_ENV_FILE). El script no se toca. El alcance de este flujo es DEV (nodo-01); QA no esta contemplado.
DB_ENCRYPTION_KEY es obligatoria. El TenantFilter inicializa la conexion multi-esquema cifrada en CADA request tenant-scoped; sin la clave devuelve 500. @IgnoreTenant no lo evita. Siempre exportarla antes de arrancar (Paso 2)..env del dominio completo ni exportar JAVA_TOOL_OPTIONS: rompe la shell (multi-token) e impone -Dserver.port=0. Exportar solo el subconjunto del Paso 2.mvn spring-boot:run, no con java -jar, y con perfiles common,<ambiente>. Sin common falta application.jwt.secret y el servicio aborta./nebula-<servicio>; la raiz responde 404. Listados por page-response / get-record./etc/hosts: una sola linea, todo contra 10.120.0.2 (plataforma y backing services). Nada apunta a 127.0.0.1 ni a un host publico, y sin VPN nada resuelve. Ver seccion 2.nodo-01 (DEV). QA no esta contemplado ni en el acceso al nodo ni en el procedimiento.eureka.client.register-with-eureka=false (consumes sin ser consumido). Registrar un duplicado requiere autorizacion previa del arquitecto y aviso al equipo.localhost:8090, nunca por puerto directo (los nebula-* no exponen puerto host)..env no se versionan (estan en .gitignore) y viven solo en el espejo local ~/environment/. Nunca commitear claves, ni distribuirlas por Slack/correo/WhatsApp; la rotacion la hace el arquitecto.ServerAliveInterval=30; si la red o la VPN cae, el tunel muere — re-levantar con up.| Sintoma | Causa probable | Solucion |
|---|---|---|
status muestra FALLA en un puerto |
Tunel no levanto ese reenvio (puerto local ocupado) | down + liberar el puerto local + up |
500 ConnectionSchemaCipher: NO inicializado |
Falta DB_ENCRYPTION_KEY en el entorno |
Exportarla con el grep/eval del Paso 2 y re-arrancar |
Aborta en el arranque por application.jwt.secret |
Perfiles sin common (o arranque con java -jar) |
SPRING_PROFILES_ACTIVE=common,dev + mvn spring-boot:run |
-XX:MaxRAMPercentage...: orden no encontrada |
Se sourceo el .env del dominio completo |
Exportar solo el subconjunto (Paso 2) |
| El servicio arranca en un puerto aleatorio | Se exporto JAVA_TOOL_OPTIONS (trae -Dserver.port=0) |
No exportarlo; fijar -Dserver.port=NNNN |
| 404 en todos los endpoints | Falta el context-path | http://localhost:PORT/nebula-<servicio>/... |
| Bootstrap falla resolviendo config | VPN caida, /etc/hosts sin registrar, o config import mal apuntado |
getent hosts simappe-config-server (debe dar 10.120.0.2) + ping 10.120.0.2 |
| El servicio no conecta a la base de datos | Falta oracle-xe (o postgres-dev/mongodb-dev) en /etc/hosts |
Registrar la linea completa de la seccion 2; getent hosts oracle-xe debe dar 10.120.0.2 |
| 401/403 en requests | OAuth2 no alcanzable o token invalido | Verificar puerto 8787 en status; re-login contra api-dev publico con x-simappe-environment: dev |
Connection refused a simappe-admin |
Config del oauth2/servicio apunta al host pelado en vez del Gateway | Ver patron simappe.admin.url = host:port del Gateway sin sufijo |
Connection timed out / No route to host al hacer SSH |
VPN caida (el nodo solo existe en la red interna) | Reconectar la VPN y ping 10.120.0.2. Ver Diagnostico Conexion VPN |
| SSH pide contrasena | La llave publica no quedo instalada en el nodo | Reenviar el .pub al arquitecto; el confirma con nodo01-ssh-dev-access.sh show <usuario> |
Permission denied (publickey) |
La llave del PC no coincide con la registrada, o IdentityFile mal apuntado |
Verificar el bloque de ~/.ssh/config (paso A4) y la huella con ssh-keygen -lf ~/.ssh/id_ed25519_nebula.pub |
channel ... open failed: administratively prohibited |
Se pidio reenviar un puerto que la llave no autoriza | Solo se permiten 8761 / 8890 / 8787 / 8090. Cualquier otro destino esta bloqueado por diseno |
ssh nodo-01 no da consola |
No es un error: la cuenta es restringida y no otorga shell | Continuar con el tunel (paso A7) |
Las rutas locales de esta tabla son del workspace de referencia del arquitecto; ajustalas a tu maquina (ver Nota sobre rutas en la seccion 1). Solo la ruta del servidor es fija.
| Elemento | Ruta (referencia — ajustar a tu workspace) |
|---|---|
| Scripts versionados (fuente unica) | wiki-arquitectura/zona-interna/02-infraestructura/scripts/ — infra-tunnel.sh, run-local.sh, local-dev.env.example |
| Provision/revocacion de accesos SSH (solo arquitecto) | nodo01-ssh-dev-access.sh |
local-dev.env (tu copia, NO se versiona) |
donde tengas tus utilidades locales (ej. junto al servicio) |
Espejo local de .env |
~/environment/<dominio>/.env (misma estructura que el servidor) |
.env en el servidor (fijo) |
/home/sysadmin/docker/compose/<dominio>/.env (directiva env_file) |
| Servicios aplicables | Cualquier microservicio nebula-* o simappe-* que resuelva config por Config-Server y se registre en Eureka |
.env y DB_ENCRYPTION_KEY| Version | Fecha | Autor | Descripcion |
|---|---|---|---|
| 1.5.0 | 2026-08-05 | Carlos Torres | Alcance acotado a DEV (nodo-01): eliminadas las referencias a QA/nodo-02 en titulo, vision general, diagrama, perfiles, local-dev.env y reglas. Regla 8 endurecida: prohibido registrarse en el Eureka compartido (eureka.client.register-with-eureka=false obligatorio; el duplicado exige autorizacion previa del arquitecto). Nuevo subcomando bootstrap del script de accesos: crea las 4 cuentas backend de golpe, sin llave y por tanto sin acceso, hasta que se instale la .pub con add. |
| 1.4.0 | 2026-08-05 | Carlos Torres | Todo el acceso pasa por la red interna via VPN. Eliminado el acceso por host publico (SSH) y eliminados los "dos modos" de /etc/hosts: queda una linea unica contra 10.120.0.2 que incluye plataforma y backing services (oracle-xe, postgres-dev, mongodb-dev, kafka-dev, redis-dev), sin la cual el servicio local no conecta a la base de datos. Nueva seccion 3.1 con el derrotero paso a paso del desarrollador (generar el par de llaves, entregar solo la .pub, configurar ~/.ssh/config, verificar y probar el reenvio), incluida la tabla de lectura de resultados y las reglas del acceso. Nueva seccion 3.2 de administracion (solo arquitecto) con el script nodo01-ssh-dev-access.sh (provision, auditoria, revocacion y baja) y el registro de cuentas provisionadas: cuentas restringidas con restrict,port-forwarding + permitopen a los 4 puertos de plataforma, shell nologin, sin sudo ni docker, solo nodo-01 (DEV). Tabla de prerequisitos ampliada (VPN, toolchain, sudo local para /etc/hosts, puertos locales libres). Scripts infra-tunnel.sh, run-local.sh y local-dev.env.example materializados y versionados en 02-infraestructura/scripts/. Nuevas filas de troubleshooting de acceso SSH. |
| 1.3.0 | 2026-07-29 | Carlos Torres | Alineacion con el procedimiento verificado en DEV (accounting-core/treasury): arranque con mvn spring-boot:run y perfiles common,<ambiente> (obligatorio para application.jwt.secret) en lugar de java -jar; prohibicion de sourcear el .env del dominio completo y de exportar JAVA_TOOL_OPTIONS (multi-token + -Dserver.port=0) con el subconjunto exacto a exportar; dos modos excluyentes de /etc/hosts (tunel 127.0.0.1 vs VPN directa IP interna); dos variantes de ~/.ssh/config (host publico → tunel sin VPN, IP interna → fuerza VPN); verificacion con context-path /nebula-<servicio> y token 2 pasos contra api-dev publico; local-dev.env/run-local.sh migrados a SERVICE_DIR + mvn; nuevas reglas y filas de troubleshooting. |
| 1.2.1 | 2026-06-10 | Carlos Torres | Registro de /etc/hosts accionable: ruta del archivo + comando ejecutable idempotente + verificacion. |
| 1.2.0 | 2026-06-10 | Carlos Torres | Nota sobre rutas: las rutas del doc son del workspace de referencia del arquitecto; cada dev las ajusta en local-dev.env. Reforzado en seccion 8. |
| 1.1.0 | 2026-06-10 | Carlos Torres | Consumo de otros servicios (X→Y/Z) por el Gateway; perfil estandar dev/qa con registro obligatorio de hostnames en /etc/hosts (prereq #5); localhost como alternativa; IPs internas en ~/.ssh/config (fuerza VPN); regla del puerto del servicio local. |
| 1.0.0 | 2026-06-10 | Carlos Torres | Creacion del flujo de prueba local con tunel SSH (estandarizacion del proceso + implementacion generica parametrizable DEV/QA) |