Files
web_scraping/CHROMIUM_SYSTEM.md
T
2026-06-05 17:27:18 +02:00

15 KiB

Chromium en este equipo: dónde se toca y cómo

Mapa de referencia de TODOS los puntos donde la configuración de Chromium se manipula en esta máquina (Linux nativo, Ubuntu 24.04, Chromium 148 del paquete .deb de xtradeb — no snap). Objetivo: no volver a redescubrir a ciegas de dónde sale cada comportamiento (extensiones, CDP, proxy). Reconstruido el 2026-06-05 desde el sistema en vivo + transcripts de sesiones anteriores.

El wrapper que une todo

/usr/bin/chromium es un shell script (no el binario). En cada arranque hace, en orden:

  1. Sourcea todos los archivos de /etc/chromium.d/* (cada uno exporta/añade a CHROMIUM_FLAGS).
  2. Lee las managed policies de /etc/chromium/policies/managed/*.json.
  3. Aplica master_preferences (/etc/chromium/master_preferences) al crear un perfil nuevo.
  4. Lanza el binario real /usr/lib/chromium/chromium $CHROMIUM_FLAGS "$@".

Por eso cualquier cosa en /etc/chromium.d/ o en el policy aplica a TODO chromium que se lance, con cualquier perfil. Editar requiere sudo (pass show claude/sudo | sudo -S ...).

Inventario de puntos de configuración

Path Qué controla Quién/cuándo lo creó Cómo editar
/etc/chromium/policies/managed/extensions.json Extensiones force-instaladas en cualquier perfil (ExtensionInstallForcelist). Hoy: solo uBlock Origin Lite. Proyecto "Code", migración de PC (2026-05-31), 4 extensiones. Reducido a uBlock 2026-06-04. fn run apply_chromium_extension_policy --keep <id>... (idempotente, backup auto) o sudo editar el JSON. Backup: extensions.json.bak.20260605 (las 4 originales).
/etc/chromium.d/cdp CDP global: --remote-debugging-port=9222 --remote-allow-origins=* (bind loopback). Proyecto web_scraping (2026-06-05), regla 8. fn run apply_chromium_cdp_flag [--remove] o sudo editar/borrar el fragmento.
/etc/chromium.d/web_proxy_ext Carga la extensión de captura del proxy (--load-extension=~/.web_proxy/extension). Proyecto web_proxy (2026-06-02). Función install_chromium_proxy_extension_bash_browser lo reescribe; --uninstall lo borra.
/etc/chromium.d/extensions Pre-existente del .deb: --enable-remote-extensions + carga unpacked de /usr/share/chromium/extensions/* (vacío). Paquete Debian (Jan 2025). No tocar salvo necesidad.
/etc/chromium.d/default-flags Flags base del .deb: --show-component-extension-options, --enable-gpu-rasterization, --no-default-browser-check, --disable-pings, --media-router=0. Paquete Debian. No tocar.
/etc/chromium.d/dev-shm Añade --disable-dev-shm-usage si /dev/shm < 3.8 GB. Paquete Debian. No tocar.
/etc/chromium.d/apikeys GOOGLE_API_KEY de Debian (pública, para sync/gmail). Paquete Debian. No tocar (no es secreto).
/etc/chromium/master_preferences Estado inicial de perfiles nuevos (homepage, DuckDuckGo, signin off). Sin extensiones. Distro. No tocar para extensiones (no es el sitio).
~/.web_proxy/extension/ Código de la extensión toggle del proxy (MV3, chrome.proxy). App web_proxy. Vía install_chromium_proxy_extension.
~/.mitmproxy/mitmproxy-ca-cert.pem CA de mitmproxy para HTTPS sin warnings. mitmproxy. ./web_proxy ca para instrucciones.

No existe (verificado): external-extensions dir (/usr/share/chromium/extensions está vacío; /opt/chromium.org/... no existe), cron ni systemd-timer que regenere config de chromium, ni política recommended/. La forcelist es un archivo estático sin regenerador automático del sistema; se aplica de forma reproducible con fn run apply_chromium_extension_policy (idempotente, backup automático) o editándola a mano con sudo (también persistente).

Extensiones: el mecanismo (LO QUE MÁS CONFUNDE)

Las extensiones de la Chrome Web Store (uBlock, Dark Reader, NoScript, OneTab) se instalan en cualquier perfil vía ExtensionInstallForcelist en el policy managed. Chrome las descarga de clients2.google.com/service/update2/crx al arrancar cualquier perfil (incluido temporal/nuevo) y quedan "managed" (no removibles por la UI). Para cambiarlas se edita el JSON (sudo).

  • uBlock se usa en la variante Lite (ddkjiahejlhfcafbddmgiahcphecmpfh, MV3) porque el uBO clásico (MV2) no carga en Chromium 148.
  • IDs: uBlock Lite ddkjiahejlhfcafbddmgiahcphecmpfh · Dark Reader eimadpbcbfnmbkopoojfekhnkhdbieeh · NoScript doojmbjmlfjjnbmnoijecmcbfeoakpjm · OneTab chphlpgkkbolifaimnlloiipkdnihall.

Anomalía resuelta (2026-06-05): backups dentro de managed/ reinyectan extensiones

Tras reducir la forcelist a solo uBlock en disco, los perfiles nuevos seguían instalando las 4 (incluso un --user-data-dir recién creado las recibía como location=7 external_policy_download, activas). Causa raíz: Chromium lee TODOS los archivos del directorio policies/managed/ sin filtrar por extensión de nombre. El backup extensions.json.bak.20260605 (con las 4 originales) vivía dentro de managed/ y Chromium lo mergeaba con extensions.json, así que el forcelist efectivo seguía teniendo las 4 — ganando incluso sobre un ExtensionInstallBlocklist. Mover el .bak fuera de managed/ (a policies/policy-backups/) dejó el forcelist efectivo en solo uBlock y los perfiles nuevos pasaron a instalar únicamente uBlock.

Regla dura: en policies/managed/ (y recommended/) solo archivos .json de política activa. Cualquier .bak, .old, .orig ahí se carga como política. La función del registry apply_chromium_extension_policy_bash_browser ya guarda sus backups fuera de managed/.

El secundario (caché en memoria) también existe: aun con el disco correcto, hay que cerrar TODOS los Chromium (pkill -9 chromium) o pulsar chrome://policy → Reload policies para que el cambio surta efecto en runtime.

Para diagnosticar la forcelist EFECTIVA (no la del archivo): abrir chrome://policy en el navegador y mirar ExtensionInstallForcelist (su columna Source y Value). No es scriptable por CDP (chrome.send no accesible vía Runtime.evaluate); hay que verlo en la UI y pulsar "Reload policies".

Para que un cambio en la forcelist surta efecto de verdad: cerrar todos los procesos chromium a la vez (pkill -9 chromium) y relanzar uno; o usar chrome://policy → Reload policies. Mientras quede un chromium vivo con la política vieja, los perfiles nuevos pueden heredarla.

Perfil limpio para scraping

Dos caminos (regla 9 de CONVENTIONS.md):

  1. Perfil nuevo desde cero + forcelist=solo uBlock → nace solo con uBlock (una vez refrescada la política). Es lo más limpio; no arrastra nada.
  2. prepare_chrome_profile (clona el perfil real conservando solo uBlock): útil cuando se necesitan las cookies/sesión del usuario. Borra carpetas de extensiones no-whitelist y purga sus refs de Preferences/Secure Preferences (si no, Chrome las re-descarga del Web Store).

CDP: mapa de puertos

Puerto Quién Cómo se activa
9222 Chromium diario del usuario Fragmento /etc/chromium.d/cdp (global, loopback). Todo chromium nuevo nace con él.
9333 (o el que se pida) Navegador de automatización dedicado script-navegador launch --port 9333 o systemd-run ... chromium --remote-debugging-port=9333. Se pasa --port para no chocar con el 9222 global.

Dos procesos chromium no pueden compartir el mismo --remote-debugging-port. El --port en cmdline sobreescribe al del fragmento global.

Proxy / captura mitm (web_proxy)

  • App: projects/web_scraping/apps/web_proxy (sub-repo Gitea dataforge/web_proxy). Compone funciones del registry: start_mitm_capture, query_mitm_flows, rotate_capture_flows, launch_chromium_proxy, install_chromium_proxy_extension.
  • Servicio web_proxy.service (systemd --user, Restart=always): mitmdump/mitmweb.
  • Puertos: proxy de captura 127.0.0.1:8889, UI mitmweb http://127.0.0.1:8081.
  • Capturas: ~/captures/traffic-*.mitm, rotación configurable (--rotate-min), retención 2048 MB / 7 días. El addon hace flush() por flujo (sobrevive a kill -9).
  • Enrutar el navegador al proxy — dos vías:
    1. Extensión toggle ~/.web_proxy/extension: popup ON → chrome.proxy a 127.0.0.1:8889; OFF → directo. Desde 2026-06-05 se instala vía managed policy, no con --load-extension (Chromium 137+ desactiva --load-extension en cuanto hay una managed policy activa: "Loading of unpacked extensions is disabled by the administrator"). La extensión se empaquetó como .crx (chromium --pack-extension, clave en ~/.web_proxy/extension.pem — NO perder, fija el id nanldmckabfghgdebblpfbdbhphhbnde), con un ~/.web_proxy/update.xml (file://), y se fuerza con apply_chromium_extension_policy --keep "<id>=file://$HOME/.web_proxy/update.xml". Si se edita la extensión: re-empaquetar con la MISMA .pem, subir version en manifest.json y update.xml. /etc/chromium.d/web_proxy_ext ya NO usa --load-extension.
    2. Perfil dedicado: chromium --proxy-server=127.0.0.1:8889 (+ CA mitmproxy o --ignore-certificate-errors para HTTPS).
  • Consultar: ./web_proxy query "~d dominio.com" --last, ./web_proxy har salida.har, ./web_proxy inspect.

"Si quiero X, toco Y" (resumen accionable)

Quiero… Toco…
Cambiar qué extensiones tiene cualquier perfil fn run apply_chromium_extension_policy --keep <id>... (o editar el JSON con sudo) + cerrar TODO chromium + relanzar
Activar/quitar CDP global fn run apply_chromium_cdp_flag [--remove] (o editar /etc/chromium.d/cdp con sudo)
Controlar un chromium con CDP puerto 9222 (diario) o script-navegador launch --port N (dedicado)
Capturar tráfico HTTP/HTTPS web_proxy (proxy 8889, UI 8081); navegador con --proxy-server=127.0.0.1:8889 o extensión toggle ON
Perfil de scraping limpio perfil nuevo desde cero (política da solo uBlock) o prepare_chrome_profile --src ~/.config/chromium --dst <perfil>
Ver la política EFECTIVA chrome://policy en la UI (no por CDP) → "Reload policies"

Selector de perfil — SIEMPRE pasar --profile-directory

Este equipo tiene varios perfiles de chromium en ~/.config/chromium: Default, Personal, Profile 1, Automation (+ System Profile). Si se lanza chromium sin --profile-directory=<perfil>, Chrome se queda en el selector de perfil y NO carga ninguno. Consecuencias observadas:

  • CDP responde (/json/version OK) pero no hay perfil activo → los comandos operan sobre una ventana vacía.
  • Las extensiones no se procesan: las force-removed de la política no se desinstalan (fue la causa real de que las 3 extensiones "no se quitaran" — el diario estaba atascado en el picker).
  • La sesión (--restore-last-session) no se restaura.

Regla: SIEMPRE lanzar con --profile-directory="<perfil>".

  • Navegador diario del usuario: --profile-directory="Default" (o el que use a diario).
  • Navegador de automatización/scraping: --profile-directory="Automation" (perfil dedicado), o un --user-data-dir nuevo (que tiene un solo perfil y por tanto no muestra picker).
# Diario (visible, con su perfil y CDP global)
systemd-run --user --unit=chromium-daily --collect --setenv=DISPLAY=:0.0 \
  chromium --profile-directory="Default" --restore-last-session

# Automatización (perfil dedicado, proxy mitm, CDP en puerto propio)
systemd-run --user --unit=ws-explore --collect --setenv=DISPLAY=:0.0 \
  chromium --profile-directory="Automation" --remote-debugging-port=9333 \
  '--remote-allow-origins=*' --proxy-server=127.0.0.1:8889 --ignore-certificate-errors \
  --window-size=1366,768 about:blank

Nota: script-navegador launch con --user-data-dir propio evita el picker (perfil único). Para apuntar al perfil real multi-perfil del usuario, añadir --profile-directory.

Gotchas aprendidos (para no repetir)

  • .bak/.old/.orig en directorios "source-todo" se activan: tanto /etc/chromium/policies/managed/ como /etc/chromium.d/ se cargan ENTEROS (todos los archivos, sin filtrar por extensión de nombre). Un extensions.json.bak en managed/ se mergea como política (y reinyecta sus extensiones); un cdp.bak en chromium.d/ se sourcea como shell. Guardar SIEMPRE los backups FUERA de esos directorios (este equipo usa policies/policy-backups/ y chromium/chromiumd-backups/).
  • Perfil diario real = ~/.config/chromium-cdp (lo fuerza /etc/chromium.d/cdp), NO ~/.config/chromium. Limpiar/inspeccionar el perfil del usuario = operar sobre chromium-cdp.
  • Selector de perfil: con varios perfiles, sin --profile-directory Chrome se atasca en el picker y no carga nada (ver sección arriba). SIEMPRE especificarlo.
  • El archivo de policy en disco ≠ política efectiva: Chrome cachea; verifica siempre en chrome://policy, no solo con cat. Para aplicar cambios, cierra todos los chromium.
  • Lanzar chromium desde el Bash tool de Claude da exit-144 (el harness mata el cgroup). Usa systemd-run --user --unit=<x> --collect chromium ... aislado. Ver memoria harness-exit-144-chromium. (No afecta a binarios Go ni al uso real del usuario.)
  • --remote-allow-origins=* debe ir entre comillas en zsh (el * se expande como glob).
  • Dark Reader no toca páginas chrome://: una captura de chrome://version sale clara aunque Dark Reader esté activo; usa una web normal para verificar si está oscureciendo.
  • prepare_chrome_profile clonando: borra carpetas Y purga Preferences, pero pueden quedar refs benignas en commands/pins; lo que causa re-descarga es extensions.settings (ya se purga).
  • Lock por user-data-dir: dos procesos chromium NO pueden compartir el mismo --user-data-dir (aunque sea con --profile-directory distinto). Si el diario tiene ~/.config/chromium abierto, un segundo chromium sobre ese mismo user-data-dir muere/delegará al existente y su --remote-debugging-port no escucha. Para automatización en paralelo: usar un --user-data-dir dedicado (p.ej. ~/.local/share/web_scraping/scrape-fresh).
  • Ventana visible (headless=false) desde systemd-run: hay que pasar el entorno gráfico: --setenv=DISPLAY=:0 --setenv=XAUTHORITY=$HOME/.Xauthority. Sin ellos chromium no conecta al X server y muere. (DISPLAY es :0, no :0.0.)
  • Mover la ventana sin xdotool/wmctrl (no instalados): usar CDP nativo — Browser.getWindowForTarget (sobre el ws browser-level de /json/version) → windowId, luego Browser.setWindowBounds {left,top,width,height}. Funciona en modo visible; windowState:normal confirma ventana real.
  • Proxy mitm (8889) ralentiza/cuelga sitios externos: con --proxy-server=127.0.0.1:8889, la navegación a sitios externos (p.ej. TED) puede tardar mucho o dejar el renderer atascado, y eso bloquea open/eval/shot sobre esa tab. Para scraping con captura: subir timeouts, o revisar la salud del upstream del proxy. Sin proxy, en este equipo la salida directa a internet puede dar ERR_CONNECTION_RESET (la red parece pasar por la infra de captura). A revisar.