{"id":1894,"date":"2026-10-31T08:13:10","date_gmt":"2026-10-31T11:13:10","guid":{"rendered":"https:\/\/www.linuxpro.com.br\/?p=1894"},"modified":"2026-10-31T08:13:10","modified_gmt":"2026-10-31T11:13:10","slug":"goguacamole-rdp-ssh-e-vnc-no-navegador-com-um-binario-go","status":"publish","type":"post","link":"https:\/\/www.linuxpro.com.br\/es\/2026\/10\/goguacamole-rdp-ssh-e-vnc-no-navegador-com-um-binario-go\/","title":{"rendered":"GoGuacamole: RDP, SSH y VNC en el navegador con un binario Go"},"content":{"rendered":"<p><img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/10\/goguacamole-rdp-ssh-vnc-navegador-go.webp\" alt=\"Mascote LinuxPro tocando um tel\u00e3o com sess\u00f5es SSH, RDP e VNC no navegador, com o logo do Go e o cachorro caramelo ao lado\" \/><\/p>\n<p>Quien ya haya subido el <a href=\"\/es\/2026\/09\/apache-guacamole-acesso-remoto-com-docker-ldap-e-sso\/\">Apache Guacamole<\/a> conoce el paquete: Tomcat, el <code data-no-translation=\"\">guacamole-client<\/code> en Java, una extensi\u00f3n JDBC para la base de datos, otra para LDAP, otra para TOTP, otra para grabaciones, cada una con su archivo de configuraci\u00f3n. El <strong>GoGuacamole<\/strong> es mi nuevo proyecto para sustituir esa parte por <strong>un \u00fanico binario Go<\/strong>, con la interfaz en Vue 3 integrada, manteniendo el mismo <code data-no-translation=\"\">guacd<\/code> de Apache por debajo. Sigues accediendo a servidores mediante <strong>RDP, SSH y VNC desde el navegador<\/strong>, pero obtienes grabaci\u00f3n de sesi\u00f3n, auditor\u00eda, SSO y MFA configurados en la propia interfaz, adem\u00e1s de poder importar la base de datos de Guacamole que ya tienes.<\/p>\n<p>Esta entrada cubren la versi\u00f3n <strong>0.6.2<\/strong> (30 de octubre de 2026): qu\u00e9 hace el proyecto, c\u00f3mo encaja en guacd, c\u00f3mo levantarlo en un minuto con una sola imagen, c\u00f3mo colocarlo detr\u00e1s de nginx, c\u00f3mo grabar y auditar sesiones y c\u00f3mo migrar desde el cliente Java. El c\u00f3digo est\u00e1 en <a href=\"https:\/\/github.com\/jniltinho\/go-guacamole\">github.com\/jniltinho\/go-guacamole<\/a>, bajo licencia MIT.<\/p>\n<h2>Qu\u00e9 es GoGuacamole<\/h2>\n<p>Apache Guacamole tiene dos mitades. El <strong>guacd<\/strong> es el demonio en C que habla RDP, SSH y VNC con los servidores y lo traduce todo al protocolo Guacamole. El <strong>guacamole-client<\/strong> es la aplicaci\u00f3n web en Java que autentica al usuario, guarda las conexiones y los permisos y entrega la pantalla al navegador. GoGuacamole reescribe solo la segunda mitad:<\/p>\n<ul>\n<li><strong>Backend en Go<\/strong> con Echo v5 y Cobra: API REST con <code data-no-translation=\"\">\/api\/v1<\/code>, t\u00fanel WebSocket compatible con el <code data-no-translation=\"\">guacamole-common-js<\/code> y el protocolo Guacamole implementado directamente, incluido el handshake con guacd (por TCP o TLS).<\/li>\n<li><strong>Frontend en Vue 3<\/strong> (Vite y Tailwind v4) integrado en el binario con <code data-no-translation=\"\">embed<\/code>, la misma t\u00e9cnica que la <a href=\"\/es\/2026\/09\/vue-go-echo-v5-parte-5-embed-binario-unico-e-docker\/\">parte 5 de la serie Vue.js + Go con Echo v5<\/a>.<\/li>\n<li><strong>Base de datos<\/strong>: SQLite por defecto, MariaDB\/MySQL o PostgreSQL cuando crezca, con migraciones integradas que se ejecutan al iniciar.<\/li>\n<li><strong>guacd oficial<\/strong>: la imagen <code data-no-translation=\"\">guacamole\/guacd<\/code> 1.6 sigue haciendo el trabajo pesado de los protocolos.<\/li>\n<\/ul>\n<p>Usuarios, grupos, carpetas de conexiones, permisos heredados, historial, grabaci\u00f3n, auditor\u00eda, inicio de sesi\u00f3n externo y MFA vienen listos, sin extensiones separadas. La interfaz tiene 16 temas y est\u00e1 en ingl\u00e9s y portugu\u00e9s de Brasil.<\/p>\n<p><img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/10\/goguacamole-painel.webp\" alt=\"Painel do GoGuacamole em portugu\u00eas com conex\u00f5es SSH, RDP e VNC, atividade recente e acessos aos servidores\" \/><\/p>\n<h2>Arquitectura: qui\u00e9n habla con qui\u00e9n<\/h2>\n<p>El navegador solo se comunica con goguacamole, mediante HTTPS y WebSocket. goguacamole habla el protocolo Guacamole con guacd, que permanece en una red privada, y guacd abre la conexi\u00f3n RDP, SSH o VNC con el servidor de destino. El host, el usuario y la contrase\u00f1a de la conexi\u00f3n permanecen en el servidor, cifrados con AES-256-GCM; el navegador nunca los ve.<\/p>\n<p><img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/10\/goguacamole-arquitetura.webp\" alt=\"Diagrama da arquitetura do GoGuacamole: navegador, nginx, goguacamole, guacd e servidores RDP, SSH e VNC, com identidade, banco, Redis, grava\u00e7\u00f5es e object storage\" \/><\/p>\n<p>La apertura de una sesi\u00f3n sigue este camino:<\/p>\n<ol>\n<li>El navegador solicita <code data-no-translation=\"\">POST \/api\/v1\/sessions<\/code> con el ID de la conexi\u00f3n. El servidor comprueba la sesi\u00f3n, las restricciones del usuario (validez de la cuenta, ventana de acceso) y el permiso efectivo de lectura.<\/li>\n<li>La respuesta es un <strong>ticket de un solo uso, v\u00e1lido durante 30 segundos<\/strong>, que ya reserva la plaza en caso de que la conexi\u00f3n tenga un l\u00edmite de sesiones.<\/li>\n<li>El navegador abre el WebSocket <code data-no-translation=\"\">\/api\/v1\/tunnel?ticket=\u2026<\/code> enviando solo par\u00e1metros de pantalla (anchura, altura, DPI, zona horaria). El servidor valida el origen, recupera el ticket y vuelve a autorizar.<\/li>\n<li>goguacamole realiza el handshake con guacd usando los par\u00e1metros guardados, activa la entrada del historial (creada como pendiente cuando se emiti\u00f3 el ticket) y pasa a reenviar las instrucciones en ambos sentidos.<\/li>\n<\/ol>\n<p>Si se revoca el permiso a mitad del proceso, el t\u00fanel se cierra al instante. Los cambios realizados por otro proceso (la CLI o el importador) se detectan en un plazo de hasta 5 segundos.<\/p>\n<h2>Levant\u00e1ndolo en un minuto: la imagen all-in-one<\/h2>\n<p>Desde la versi\u00f3n 0.6.0, cada versi\u00f3n publica en GHCR una imagen que re\u00fane guacd, goguacamole y Redis en un contenedor, con SQLite en el volumen <code data-no-translation=\"\">\/data<\/code>:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">docker run -d --name goguacamole -p 8080:8080 \\\n  -v goguacamole-data:\/data ghcr.io\/jniltinho\/go-guacamole:allinone\n\n# a senha gerada do admin aparece uma \u00fanica vez no log\ndocker logs goguacamole 2>&1 | grep 'bootstrap administrator'<\/code><\/pre>\n<p>Para fijar la versi\u00f3n, usa la etiqueta <code data-no-translation=\"\">0.6.2-allinone<\/code> (o <code data-no-translation=\"\">0.6-allinone<\/code>). Abra <code data-no-translation=\"\">http:\/\/localhost:8080<\/code>, entre como <code data-no-translation=\"\">admin<\/code> con la contrase\u00f1a del log y el sistema pide una contrase\u00f1a nueva en el primer acceso. La disponibilidad se puede comprobar mediante la API:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">curl -s http:\/\/localhost:8080\/ready\n# {\"db\":\"up\",\"guacd\":\"up\",\"queue\":\"up\"}<\/code><\/pre>\n<p>Dentro del contenedor, supervisord mantiene los tres procesos en ejecuci\u00f3n como el usuario <code data-no-translation=\"\">guacd<\/code> (uid 1000), propietario de los archivos en <code data-no-translation=\"\">\/data<\/code>. Por eso, los comandos de la CLI se ejecutan como <code data-no-translation=\"\">-u guacd<\/code>:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">docker exec goguacamole supervisorctl status            # guacd, redis, goguacamole\ndocker exec -u guacd goguacamole goguacamole user passwd admin\ndocker exec goguacamole goguacamole version<\/code><\/pre>\n<p>Este modo HTTP es para evaluaci\u00f3n local. Para producci\u00f3n, consulta la lista de verificaci\u00f3n m\u00e1s abajo.<\/p>\n<h2>Prob\u00e1ndolo con un servidor SSH de laboratorio<\/h2>\n<p>Para ver una sesi\u00f3n real sin tocar ning\u00fan servidor, coloca GoGuacamole y un OpenSSH desechable en la misma red Docker. El guacd de la imagen all-in-one resuelve el destino por nombre de contenedor. Si el contenedor de la secci\u00f3n anterior sigue en ejecuci\u00f3n, elim\u00ednalo antes (<code data-no-translation=\"\">docker rm -f goguacamole<\/code>), porque el laboratorio utiliza el mismo nombre y el mismo puerto:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">docker network create guac-lab\ndocker run -d --name goguacamole --network guac-lab -p 8080:8080 \\\n  -v goguacamole-data:\/data ghcr.io\/jniltinho\/go-guacamole:allinone\ndocker run -d --name ssh-alvo --network guac-lab \\\n  -e USER_NAME=demo -e USER_PASSWORD='troque-esta-senha' -e PASSWORD_ACCESS=true \\\n  lscr.io\/linuxserver\/openssh-server:latest<\/code><\/pre>\n<p>En la interfaz, en <strong>Conexiones \u2192 Nueva conexi\u00f3n<\/strong>, elige SSH, host <code data-no-translation=\"\">ssh-alvo<\/code>, puerta <code data-no-translation=\"\">2222<\/code> (la puerta de esta imagen), usuario <code data-no-translation=\"\">demo<\/code> y la contrase\u00f1a. Antes de guardar, usa <strong>Probar conexi\u00f3n<\/strong>: GoGuacamole abre una conexi\u00f3n real mediante guacd con los valores del formulario e indica si el host respondi\u00f3 y si el inicio de sesi\u00f3n funcion\u00f3. En mi prueba, la contrase\u00f1a correcta volvi\u00f3 como \u00e9xito en unos 200 ms, y la incorrecta volvi\u00f3 como fallo de autenticaci\u00f3n, sin guardar nada. Despu\u00e9s solo hay que guardar y hacer clic en <strong>Conectar<\/strong>: la terminal se abre en una pesta\u00f1a del navegador.<\/p>\n<p>Al terminar, elimina el laboratorio:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">docker rm -f goguacamole ssh-alvo\ndocker volume rm goguacamole-data\ndocker network rm guac-lab<\/code><\/pre>\n<h2>Docker Compose con servicios separados<\/h2>\n<p>Para un entorno duradero, el repositorio incluye un <code data-no-translation=\"\">docker-compose.yml<\/code> con goguacamole, guacd y Redis en contenedores separados, y perfiles para MariaDB, PostgreSQL y servidores de prueba:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">git clone https:\/\/github.com\/jniltinho\/go-guacamole.git\ncd go-guacamole\ncp .env.example .env\n# no .env, defina APP_ADMIN_PASSWORD (8+ caracteres); a chave pode ser gerada assim:\nprintf 'APP_SECRET_KEY=%s\\n' \"$(openssl rand -hex 32)\" &gt;&gt; .env\nmake up            # app + guacd + Redis, SQLite \u2192 http:\/\/localhost:8080<\/code><\/pre>\n<table>\n<thead>\n<tr>\n<th>Comando<\/th>\n<th>Qu\u00e9 se levanta<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code data-no-translation=\"\">make up<\/code><\/td>\n<td>app, guacd y Redis con SQLite<\/td>\n<\/tr>\n<tr>\n<td><code data-no-translation=\"\">make up-mariadb<\/code><\/td>\n<td>lo mismo, m\u00e1s MariaDB 11.4<\/td>\n<\/tr>\n<tr>\n<td><code data-no-translation=\"\">make up-postgres<\/code><\/td>\n<td>lo mismo, m\u00e1s PostgreSQL 17<\/td>\n<\/tr>\n<tr>\n<td><code data-no-translation=\"\">make up-lab<\/code><\/td>\n<td>objetivos de prueba SSH, VNC y RDP<\/td>\n<\/tr>\n<tr>\n<td><code data-no-translation=\"\">make certs up-tls<\/code><\/td>\n<td>HTTPS nativo en <code data-no-translation=\"\">https:\/\/localhost:8443<\/code> con una CA local<\/td>\n<\/tr>\n<tr>\n<td><code data-no-translation=\"\">make down<\/code><\/td>\n<td>tira todo<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>A <code data-no-translation=\"\">APP_SECRET_KEY<\/code> deriva la clave que cifra las contrase\u00f1as de las conexiones. <strong>Gu\u00e1rdala junto con la copia de seguridad de la base de datos<\/strong>: sin ella, las credenciales almacenadas no se pueden recuperar. Si no defines la clave, GoGuacamole genera una <code data-no-translation=\"\">secret.key<\/code> en el primer inicio, y ese archivo pasa a ser igualmente cr\u00edtico.<\/p>\n<p>Tambi\u00e9n se puede ejecutar solo el binario (Linux\/amd64, en las <a href=\"https:\/\/github.com\/jniltinho\/go-guacamole\/releases\">releases<\/a>) apuntando a un guacd:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">docker run -d -p 127.0.0.1:4822:4822 guacamole\/guacd:1.6.0\nAPP_ADMIN_PASSWORD='troque-agora' GUACD_ADDR=127.0.0.1:4822 .\/goguacamole serve<\/code><\/pre>\n<h2>Detr\u00e1s de nginx con HTTPS<\/h2>\n<p>El t\u00fanel de sesi\u00f3n es un WebSocket que puede permanecer abierto durante horas, por lo que el proxy necesita HTTP\/1.1, las cabeceras de upgrade y tiempos de espera largos. El repositorio incluye un ejemplo completo en <code data-no-translation=\"\">docker\/nginx\/goguacamole.conf<\/code>; lo esencial es esto:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-nginx\" data-no-translation=\"\">map $http_upgrade $connection_upgrade {\n    default upgrade;\n    ''      '';\n}\n\nserver {\n    listen 443 ssl;\n    http2 on;\n    server_name guac.example.com;\n    # ssl_certificate \/ ssl_certificate_key ...\n\n    location \/ {\n        proxy_pass http:\/\/127.0.0.1:8080;\n        proxy_http_version 1.1;\n        proxy_set_header Host              $host;\n        proxy_set_header X-Real-IP         $remote_addr;\n        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_set_header Upgrade           $http_upgrade;\n        proxy_set_header Connection        $connection_upgrade;\n    }\n\n    # o t\u00fanel transmite a tela: sem buffer e com timeouts longos\n    location = \/api\/v1\/tunnel {\n        proxy_pass http:\/\/127.0.0.1:8080;\n        proxy_http_version 1.1;\n        proxy_set_header Host              $host;\n        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_set_header Upgrade           $http_upgrade;\n        proxy_set_header Connection        $connection_upgrade;\n        proxy_buffering    off;\n        proxy_read_timeout 12h;\n        proxy_send_timeout 12h;\n    }\n}<\/code><\/pre>\n<p>En el lado de GoGuacamole, tres variables completan la pareja:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">APP_BASE_URL=https:\/\/guac.example.com   # o host aceito como Origin do WebSocket\nAPP_COOKIE_SECURE=true                  # TLS termina no proxy\nAPP_TRUSTED_PROXIES=127.0.0.1           # s\u00f3 esse IP pode informar X-Forwarded-For<\/code><\/pre>\n<p>Con <code data-no-translation=\"\">APP_TRUSTED_PROXIES<\/code> claro, el registro, la auditor\u00eda y el historial registran la IP del cliente, no la de nginx, y un <code data-no-translation=\"\">X-Forwarded-For<\/code> forjado procedente de otro lugar se ignora. Si prefieres el <a href=\"\/es\/2026\/10\/caddy-no-linux-servidor-web-com-https-automatico\/\">Caddy<\/a>, el <code data-no-translation=\"\">reverse_proxy<\/code> de este ya gestiona WebSocket sin configuraci\u00f3n adicional.<\/p>\n<h2>Grabaci\u00f3n de sesiones y auditor\u00eda<\/h2>\n<p>Aqu\u00ed est\u00e1 buena parte del motivo del proyecto. guacd guarda la sesi\u00f3n en un volumen compartido y GoGuacamole se encarga del resto:<\/p>\n<ul>\n<li><strong>V\u00eddeo de la pantalla<\/strong> de RDP, SSH y VNC, reproducido en el propio navegador.<\/li>\n<li><strong>Transcripci\u00f3n de SSH<\/strong> en texto, con cada comando y su salida, para leer o buscar.<\/li>\n<li><strong>Teclas pulsadas<\/strong>, opcional y desactivada por defecto.<\/li>\n<li><strong>Pol\u00edtica por conexi\u00f3n<\/strong>: v\u00eddeo, transcripci\u00f3n y teclas pueden heredar el valor predeterminado, forzarse o desactivarse; el v\u00eddeo y la transcripci\u00f3n tienen sus propias retenciones (las teclas forman parte del v\u00eddeo).<\/li>\n<li><strong>Fail-closed<\/strong>: si la grabaci\u00f3n requerida no est\u00e1 disponible, la sesi\u00f3n no se abre (hay excepciones temporales, auditadas).<\/li>\n<li><strong>Retenci\u00f3n y retenci\u00f3n legal<\/strong>: la limpieza sigue el historial, y una grabaci\u00f3n bajo retenci\u00f3n legal no se elimina.<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/10\/goguacamole-player-gravacao.webp\" alt=\"Player de grava\u00e7\u00e3o do GoGuacamole reproduzindo uma sess\u00e3o SSH no navegador\" \/><\/p>\n<p>Los valores predeterminados iniciales provienen de variables de entorno (despu\u00e9s de que un administrador guarda en <strong>Administraci\u00f3n \u2192 Grabaci\u00f3n<\/strong>, prevalece lo que est\u00e1 en la base de datos):<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">RECORDING_ENABLED=true          # padr\u00e3o false; true no compose\nRECORDING_SCREEN=true           # v\u00eddeo de todos os protocolos\nRECORDING_TYPESCRIPT=true       # transcri\u00e7\u00e3o de SSH\nRECORDING_INCLUDE_KEYS=false    # teclas no v\u00eddeo\nRECORDING_RETENTION_DAYS=90<\/code><\/pre>\n<p>Las grabaciones tambi\u00e9n pueden enviarse a <strong>object storage<\/strong>: AWS S3, compatibles con S3 (MinIO, Ceph, R2, Wasabi), Oracle Cloud y Google Cloud Storage, mediante rclone. Cada env\u00edo se verifica mediante SHA-256, releyendo el objeto; la copia local se puede eliminar y el reproductor reproduce directamente desde el bucket. El bot\u00f3n <strong>Probar acceso<\/strong> graba, lee y elimina un objeto de prueba e informa si el bucket tiene versionado y object lock. Estas tareas se ejecutan en una cola de Redis con <a href=\"\/es\/2026\/09\/asynq-filas-de-tarefas-em-go-com-redis-e-asynqmon\/\">asynq<\/a>, y el panel asynqmon est\u00e1 en <code data-no-translation=\"\">\/asynqmon<\/code>, solo para administradores.<\/p>\n<p>Por seguridad, la conexi\u00f3n con el almacenamiento de objetos pasa por un proxy interno que rechaza direcciones privadas, loopback, link-local y de metadatos de nube. Un MinIO de laboratorio en la red local debe habilitarse de forma expl\u00edcita:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">OBJSTORE_ALLOWED_ENDPOINTS=minio\nOBJSTORE_ALLOW_HTTP=true<\/code><\/pre>\n<p>La auditor\u00eda registra los inicios de sesi\u00f3n, las sesiones y los cambios administrativos realizados desde la interfaz y la API. El panel tambi\u00e9n incluye un informe de acceso a los servidores: qui\u00e9n accedi\u00f3 a cada servidor, cu\u00e1ndo y durante cu\u00e1nto tiempo.<\/p>\n<h2>Inicio de sesi\u00f3n: LDAP, OIDC, SAML y MFA<\/h2>\n<p>En el cliente Java, cada m\u00e9todo de inicio de sesi\u00f3n es una extensi\u00f3n con su propio archivo. En GoGuacamole, todo se encuentra en <strong>Administraci\u00f3n \u2192 Autenticaci\u00f3n<\/strong>, con los secretos guardados cifrados en la base de datos y un bot\u00f3n de prueba para cada m\u00e9todo:<\/p>\n<ul>\n<li><strong>LDAP \/ Active Directory<\/strong>, con los grupos del directorio asignados a grupos locales por nombre. Si administras AD o Samba 4, el <a href=\"\/es\/2026\/10\/ad-manager-active-directory-e-samba-4-pelo-navegador-desktop-e-cli\/\">AD Manager<\/a> hazlo por ti.<\/li>\n<li><strong>OpenID Connect<\/strong> (authorization code con PKCE) y <strong>SAML 2.0<\/strong>.<\/li>\n<li><strong>Cabecera HTTP<\/strong> procedente de proxies de confianza y <strong>JSON cifrado<\/strong> compatible con el <code data-no-translation=\"\">guacamole-auth-json<\/code>.<\/li>\n<li><strong>TOTP<\/strong> con c\u00f3digo QR y protecci\u00f3n contra la reutilizaci\u00f3n de c\u00f3digos, y <strong>Duo Universal Prompt<\/strong>, como segundo factor de los inicios de sesi\u00f3n con contrase\u00f1a.<\/li>\n<\/ul>\n<p>Los usuarios externos se crean en el primer inicio de sesi\u00f3n. Un detalle importante: el segundo factor de GoGuacamole es v\u00e1lido para el inicio de sesi\u00f3n con contrase\u00f1a. En el inicio de sesi\u00f3n con SSO, exige MFA en tu proveedor de identidad.<\/p>\n<h2>Migrando desde Apache Guacamole<\/h2>\n<p>El importador lee la base de datos de Guacamole (MySQL o PostgreSQL) en una transacci\u00f3n de solo lectura, \u00fanicamente con <code data-no-translation=\"\">SELECT<\/code>. Empiece siempre con <code data-no-translation=\"\">--dry-run<\/code>:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\"># n\u00e3o grava nada importado; a origem nunca \u00e9 alterada\ngoguacamole import guacamole --source-driver mysql \\\n  --dsn 'guacamole_user:senha@tcp(db-antigo:3306)\/guacamole_db' --dry-run\n\n# importa\u00e7\u00e3o de verdade (reexecutar \u00e9 idempotente; conflitos s\u00e3o ignorados por padr\u00e3o)\ngoguacamole import guacamole --source-driver mysql \\\n  --dsn 'guacamole_user:senha@tcp(db-antigo:3306)\/guacamole_db'<\/code><\/pre>\n<p>Un detalle: incluso en <code data-no-translation=\"\">--dry-run<\/code>, el comando abre la base de datos de destino de GoGuacamole y aplica las migraciones pendientes del esquema, como hace el <code data-no-translation=\"\">serve<\/code>. Los datos importados no se escriben.<\/p>\n<p>Se importan los usuarios (con el hash y el salt, por lo que <strong>las contrase\u00f1as siguen funcionando<\/strong> y se migran a bcrypt en el pr\u00f3ximo inicio de sesi\u00f3n), la validez y la ventana de acceso, los grupos y sus miembros, las carpetas, las conexiones con sus par\u00e1metros (secretos recifrados), los l\u00edmites, los permisos del sistema que tienen equivalente (<code data-no-translation=\"\">ADMINISTER<\/code>, <code data-no-translation=\"\">CREATE_CONNECTION<\/code>, <code data-no-translation=\"\">CREATE_USER<\/code> e <code data-no-translation=\"\">AUDIT<\/code>) y los permisos de lectura de las conexiones. Los grupos anidados se aplanan. Quedan fuera, y aparecen en el informe, los perfiles de uso compartido y los permisos que no sean de lectura. Los grupos de balanceo se convierten en carpetas normales.<\/p>\n<p>Al final, el importador compara, usuario por usuario, las conexiones y los privilegios que cada uno ten\u00eda en el origen y tiene en el destino, e imprime l\u00edneas <code data-no-translation=\"\">ACCESS DIFF<\/code>. Esas diferencias se <strong>informan, no se bloquean<\/strong>: por ejemplo, si ya existe en el destino una cuenta con el mismo nombre y con <code data-no-translation=\"\">ADMINISTER<\/code>, el informe muestra la ganancia de privilegios. La flag <code data-no-translation=\"\">--accept-expansion<\/code> solo decide si la lectura de los grupos de balanceo se convierte en una lectura en cada conexi\u00f3n secundaria. La opci\u00f3n sensata es ejecutar el dry-run en una copia de la base de datos de producci\u00f3n, revisar cada <code data-no-translation=\"\">ACCESS DIFF<\/code> y hacer una prueba piloto con algunos usuarios junto al cliente Java, en otro puerto, antes de cambiar el proxy.<\/p>\n<h2>La CLI<\/h2>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">goguacamole serve                       # servidor HTTP(S)\ngoguacamole migrate up|down|status      # migra\u00e7\u00f5es do banco\ngoguacamole user create|passwd|list|disable\ngoguacamole import guacamole            # importa\u00e7\u00e3o do Apache Guacamole\ngoguacamole config print                # configura\u00e7\u00e3o efetiva, segredos ocultos\ngoguacamole healthcheck                 # usado pelo HEALTHCHECK do Docker\ngoguacamole version<\/code><\/pre>\n<p>La configuraci\u00f3n procede de <code data-no-translation=\"\">config.toml<\/code> (hay una <code data-no-translation=\"\">config.toml.example<\/code> en el repositorio) y de variables de entorno con prefijos como <code data-no-translation=\"\">APP_<\/code>, <code data-no-translation=\"\">DB_<\/code>, <code data-no-translation=\"\">GUACD_<\/code>, <code data-no-translation=\"\">RECORDING_<\/code>, <code data-no-translation=\"\">REDIS_<\/code> e <code data-no-translation=\"\">OBJSTORE_<\/code>.<\/p>\n<h2>Cliente Java x GoGuacamole<\/h2>\n<table>\n<thead>\n<tr>\n<th><\/th>\n<th>Apache guacamole-client<\/th>\n<th>GoGuacamole<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Ejecuci\u00f3n<\/td>\n<td>Java, Tomcat y extensiones<\/td>\n<td>un binario Go con la interfaz integrada<\/td>\n<\/tr>\n<tr>\n<td>Base de datos<\/td>\n<td>MySQL, PostgreSQL o SQL Server mediante una extensi\u00f3n JDBC<\/td>\n<td>SQLite, MariaDB\/MySQL o PostgreSQL integrados<\/td>\n<\/tr>\n<tr>\n<td>SSO y MFA<\/td>\n<td>extensiones separadas, configuradas en archivos<\/td>\n<td>integradas, configuradas y probadas desde la interfaz<\/td>\n<\/tr>\n<tr>\n<td>Grabaci\u00f3n<\/td>\n<td>grabaci\u00f3n en disco; reproductor mediante extensi\u00f3n<\/td>\n<td>reproductor integrado, transcripciones SSH, retenci\u00f3n, retenci\u00f3n legal, almacenamiento de objetos<\/td>\n<\/tr>\n<tr>\n<td>Actualizaci\u00f3n<\/td>\n<td>volver a desplegar el WAR y las extensiones<\/td>\n<td>cambiar el binario o la imagen; las migraciones se ejecutan al iniciar<\/td>\n<\/tr>\n<tr>\n<td>guacd<\/td>\n<td><code data-no-translation=\"\">guacamole\/guacd<\/code><\/td>\n<td>lo mismo <code data-no-translation=\"\">guacamole\/guacd<\/code> (1.6)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Lista de comprobaci\u00f3n para producci\u00f3n<\/h2>\n<ul>\n<li><code data-no-translation=\"\">APP_ENV=production<\/code>: el servicio solo se inicia con <code data-no-translation=\"\">TLS_ENABLED=true<\/code> o <code data-no-translation=\"\">APP_COOKIE_SECURE=true<\/code>, con una clave definida (<code data-no-translation=\"\">APP_SECRET_KEY<\/code> o <code data-no-translation=\"\">APP_SECRET_KEY_FILE<\/code>), y rechaza <code data-no-translation=\"\">TLS_SELF_SIGNED=true<\/code> e <code data-no-translation=\"\">GUACD_TLS_INSECURE=true<\/code>. No comprueba si el proxy realmente tiene TLS: eso queda en tus manos.<\/li>\n<li><code data-no-translation=\"\">APP_SECRET_KEY<\/code> en un almac\u00e9n de secretos, con copia de seguridad junto a la base de datos. Prueba la restauraci\u00f3n en un host limpio.<\/li>\n<li>HTTPS: <code data-no-translation=\"\">TLS_ENABLED=true<\/code> en el propio binario, o TLS terminado en el proxy con <code data-no-translation=\"\">APP_COOKIE_SECURE=true<\/code> e <code data-no-translation=\"\">APP_TRUSTED_PROXIES<\/code>, manteniendo el tramo proxy \u2192 goguacamole en <code data-no-translation=\"\">127.0.0.1<\/code> o en una red privada.<\/li>\n<li><code data-no-translation=\"\">APP_BASE_URL<\/code> con la URL p\u00fablica.<\/li>\n<li>guacd en una red aislada, nunca expuesto; considera <code data-no-translation=\"\">GUACD_TLS=true<\/code>.<\/li>\n<li>MFA (TOTP o Duo) para los inicios de sesi\u00f3n con contrase\u00f1a; para SSO, MFA en el proveedor.<\/li>\n<li>Redis en red privada (o con <code data-no-translation=\"\">REDIS_PASSWORD<\/code> e <code data-no-translation=\"\">REDIS_TLS<\/code>), una base de datos por instalaci\u00f3n.<\/li>\n<li>Almacenamiento de objetos con un bucket o prefijo dedicado y credenciales limitadas a put\/get\/list\/delete en \u00e9l.<\/li>\n<\/ul>\n<h2>L\u00edmites actuales<\/h2>\n<p>El proyecto es nuevo, est\u00e1 en la serie 0.x, y conviene saber lo que a\u00fan no tiene:<\/p>\n<ul>\n<li><strong>Una r\u00e9plica para los t\u00faneles<\/strong>: el registro de t\u00faneles, los l\u00edmites y la finalizaci\u00f3n de sesi\u00f3n se mantienen en la memoria del proceso. Escala verticalmente. Las tareas en segundo plano y las subidas ya son seguras con varias instancias.<\/li>\n<li><strong>Sin compartici\u00f3n de sesi\u00f3n<\/strong> (entrar en una sesi\u00f3n activa de otro usuario) ni grupos de balanceo.<\/li>\n<li><strong>Grupos de usuarios planos<\/strong>: los grupos anidados a\u00fan no existen.<\/li>\n<li><strong>Binarios e imagen para Linux\/amd64<\/strong>; otras arquitecturas requieren compilar.<\/li>\n<li>Telnet y Kubernetes, que admite guacd, a\u00fan no est\u00e1n en los formularios.<\/li>\n<\/ul>\n<p>O <a href=\"https:\/\/github.com\/jniltinho\/go-guacamole\/blob\/main\/ROADMAP.md\">ROADMAP<\/a> enumera estos elementos y otros, como m\u00e9tricas Prometheus, paquetes .deb\/.rpm y Helm chart.<\/p>\n<h2>Conclusi\u00f3n<\/h2>\n<p>guacd sigue siendo la pieza adecuada para hablar de RDP, SSH y VNC. Lo que cambia GoGuacamole es lo dem\u00e1s: un binario, un contenedor para empezar, inicio de sesi\u00f3n externo y MFA sin extensiones, grabaci\u00f3n con reproductor y transcripci\u00f3n, y un importador que trae la base de datos de Guacamole e informa de cada diferencia de acceso. Si ya usas Guacamole, ejecuta el importador con <code data-no-translation=\"\">--dry-run<\/code> en una copia de la base de datos y compara. Si est\u00e1s empezando, el <code data-no-translation=\"\">docker run<\/code> de la imagen todo en uno basta para probar.<\/p>\n<p>Las incidencias y las solicitudes de extracci\u00f3n son bienvenidas en el <a href=\"https:\/\/github.com\/jniltinho\/go-guacamole\">repositorio de GoGuacamole<\/a>. Otros proyectos en Go aqu\u00ed del blog siguen la misma idea de un \u00fanico binario: <a href=\"\/es\/2026\/09\/go-postfixadmin\/\">go-postfixadmin<\/a>, <a href=\"\/es\/2026\/09\/go-imapsync\/\">go-imapsync<\/a> e <a href=\"\/es\/2026\/09\/mcp-wp-go-wordpress-por-mcp-sem-ssh\/\">mcp-wp-go<\/a>. Y, para el acceso SSH directo, sin gateway, consulta <a href=\"\/es\/2017\/04\/ssh-sem-senha\/\">claves de autenticaci\u00f3n en SSH<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>GoGuacamole sustituye el cliente Java de Apache Guacamole por un binario Go con interfaz Vue 3: RDP, SSH y VNC en el navegador, grabaci\u00f3n de sesiones, auditor\u00eda, SSO, MFA e importaci\u00f3n de la base de datos de Guacamole.<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[46,2,111,120],"tags":[557,156,58,556,555,546,203,506,547],"class_list":["post-1894","post","type-post","status-publish","format-standard","hentry","category-devops","category-linux","category-opensource","category-servidores","tag-acesso-remoto","tag-docker","tag-go","tag-goguacamole","tag-guacamole","tag-rdp","tag-self-hosted","tag-ssh","tag-vnc"],"_links":{"self":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts\/1894","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/comments?post=1894"}],"version-history":[{"count":1,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts\/1894\/revisions"}],"predecessor-version":[{"id":1895,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts\/1894\/revisions\/1895"}],"wp:attachment":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/media?parent=1894"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/categories?post=1894"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/tags?post=1894"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}