# jmrp.io: Full Context > Personal technical blog and portfolio of José Manuel Requena Plens, a firmware and software engineer in Valencia, Spain: industrial embedded systems, open-source tooling, and self-hosted infrastructure. > This file is an index. Every entry links to a markdown twin that carries > the detail, which is what keeps the index itself small enough to fit in an > agent's context. Posts, tools, the CV and the publications each live at > their page's own URL with `index.md` appended. > Reuse: articles, blog covers and data files are CC BY 4.0 with attribution; the source code is MIT; the portrait is reserved. Full terms: https://jmrp.io/license/ Canonical: https://jmrp.io/ Build-Date: 2026-10-16 ## About the Author José Manuel Requena Plens (JMRP) is a firmware and software engineer in Valencia, Spain. From April 2023 to May 2026 he was an R&D Software Developer at Power Electronics, writing firmware in C on STM32 and FreeRTOS for solar inverters, with Modbus communications and hardware test automation; before that, acoustics research at the UPV (2019–2023) on rocket launch noise mitigation for the European Space Agency (ESA), acoustic metamaterials and biomedical ultrasound. Since May 2026 he has been looking for firmware, software or QA roles, on-site, remote or hybrid. Active open-source contributor and self-hoster. ## Blog Posts Each post's full body lives in its own file, so no ingestion cap ever truncates mid-guide: - [Mastering Mutual TLS (mTLS) with Nginx: A Deep Dive](https://jmrp.io/blog/001-secure-nginx-client-certificates/index.md): Implement Mutual TLS (mTLS) with Nginx — create a CA, generate client certificates, configure CRL and OCSP revocation, and enable Zero Trust. ([article](https://jmrp.io/blog/001-secure-nginx-client-certificates/)) - [Mastering Virtual Files in Nginx: A Complete Guide](https://jmrp.io/blog/002-serve-virtual-files-nginx/index.md): Serve virtual files in Nginx without disk I/O. Covers root vs alias vs try_files, named locations, Kubernetes health endpoints, and containers. ([article](https://jmrp.io/blog/002-serve-virtual-files-nginx/)) - [Content Security Policy (CSP) with Nginx: The Complete Guide](https://jmrp.io/blog/003-implementing-content-security-policy-nginx/index.md): Master Content Security Policy from zero to A+ — nonces, hashes, strict-dynamic, Trusted Types, bypass prevention, and production Nginx configs. ([article](https://jmrp.io/blog/003-implementing-content-security-policy-nginx/)) - [Mastering QUIC and HTTP/3 with Nginx: The Complete Guide](https://jmrp.io/blog/004-enabling-quic-http3-nginx/index.md): Deep dive into QUIC and HTTP/3 — technical architecture, security features, and step-by-step Nginx configuration for production deployment. ([article](https://jmrp.io/blog/004-enabling-quic-http3-nginx/)) - [Implementing a Tarpit in Nginx: Trap Malicious Scanners](https://jmrp.io/blog/005-implementing-tarpit-nginx/index.md): Implement an Nginx tarpit to slow down and trap malicious bots, vulnerability scanners, and brute-force attackers. Includes CrowdSec integration. ([article](https://jmrp.io/blog/005-implementing-tarpit-nginx/)) - [MikroTik Honeypot: Trap & Auto-Block Port Scanners](https://jmrp.io/blog/006-implementing-mikrotik-honeypot/index.md): Configure a MikroTik honeypot to detect port scanners, log malicious activity, and auto-block attackers using firewall address lists and the RAW table. ([article](https://jmrp.io/blog/006-implementing-mikrotik-honeypot/)) - [MikroTik WireGuard VPN: Dual-Stack IPv4/IPv6 Configuration](https://jmrp.io/blog/007-mikrotik-wireguard-dual-stack-vpn/index.md): Configure WireGuard VPN on MikroTik RouterOS with full IPv4/IPv6 dual-stack. Access your home network with native IPv6 from any connection. ([article](https://jmrp.io/blog/007-mikrotik-wireguard-dual-stack-vpn/)) - [MikroTik PPPoE + DHCPv6-PD: Dual-Stack for DIGI Spain](https://jmrp.io/blog/008-mikrotik-pppoe-dualstack-digi/index.md): Configure PPPoE with DHCPv6 Prefix Delegation on MikroTik RouterOS for DIGI Spain. VLAN tagging, SLAAC, prefix change handling, and firewall rules. ([article](https://jmrp.io/blog/008-mikrotik-pppoe-dualstack-digi/)) - [Running a Tor Bridge on Linux: obfs4 and WebTunnel Guide](https://jmrp.io/blog/009-running-tor-bridge/index.md): Guide to running obfs4 and WebTunnel Tor bridges on Linux with Nginx camouflage, firewall hardening, Prometheus monitoring, and CrowdSec. ([article](https://jmrp.io/blog/009-running-tor-bridge/)) - [What the Linker Won't Do: Packing i18n Strings on an MCU](https://jmrp.io/blog/010-packed-i18n-string-pool/index.md): A build-time generator packs firmware UI translations into one string pool indexed by uint16 offsets, halving the index table on a 32-bit MCU. ([article](https://jmrp.io/blog/010-packed-i18n-string-pool/)) - [A Vault File That Fails Closed: Encrypt-then-MAC on an MCU](https://jmrp.io/blog/011-encrypt-then-mac-vault/index.md): How a hardware password manager authenticates every vault file before it decrypts: encrypt-then-MAC, verify-before-decrypt, and fail-closed reads. ([article](https://jmrp.io/blog/011-encrypt-then-mac-vault/)) - [Your 4-Digit PIN Is Fine: Device-Bound Keys on ESP32-S3](https://jmrp.io/blog/012-device-bound-key-derivation/index.md): Why PBKDF2 iterations can't protect a 4-digit PIN on a microcontroller, and how an eFuse-HMAC device secret plus HKDF stops offline brute force. ([article](https://jmrp.io/blog/012-device-bound-key-derivation/)) - [What building a GitLab MCP server taught me about GitLab's API](https://jmrp.io/blog/013-gitlab-mcp-server-api-lessons/index.md): Building and checking an MCP server against GitLab found a 401 that meant 403 and writes answered as successes that saved nothing; each went upstream. ([article](https://jmrp.io/blog/013-gitlab-mcp-server-api-lessons/)) - [GitLab fine-grained personal access tokens, one action at a time](https://jmrp.io/blog/014-gitlab-fine-grained-tokens-per-action/index.md): A GitLab fine-grained token holds a grant, not scopes: REST refuses outside it, GraphQL answers null. I derive what each API action needs, ahead of time. ([article](https://jmrp.io/blog/014-gitlab-fine-grained-tokens-per-action/)) ## Blog Posts (Español) El cuerpo completo de cada artículo vive en su propio fichero, para que ningún límite de ingesta corte a mitad de una guía: - [Dominando Mutual TLS (mTLS) con Nginx: Una Guía Completa](https://jmrp.io/es/blog/001-secure-nginx-client-certificates/index.md): Implementa Mutual TLS (mTLS) con Nginx — crea una CA, genera certificados de cliente, configura revocación CRL y OCSP, y habilita Zero Trust. ([artículo](https://jmrp.io/es/blog/001-secure-nginx-client-certificates/)) - [Domina los archivos virtuales en Nginx: Guía completa](https://jmrp.io/es/blog/002-serve-virtual-files-nginx/index.md): Sirve archivos virtuales en Nginx sin I/O de disco. Cubre root vs alias vs try_files, named locations, endpoints de salud en Kubernetes y containers. ([artículo](https://jmrp.io/es/blog/002-serve-virtual-files-nginx/)) - [Content Security Policy (CSP) con Nginx: La Guía Completa](https://jmrp.io/es/blog/003-implementing-content-security-policy-nginx/index.md): Domina Content Security Policy de cero a A+ — nonces, hashes, strict-dynamic, Trusted Types, prevención de bypass y configuraciones Nginx en producción. ([artículo](https://jmrp.io/es/blog/003-implementing-content-security-policy-nginx/)) - [Dominando QUIC y HTTP/3 con Nginx: La Guía Completa](https://jmrp.io/es/blog/004-enabling-quic-http3-nginx/index.md): Inmersión profunda en QUIC y HTTP/3 — arquitectura técnica, seguridad y configuración paso a paso de Nginx para despliegue en producción. ([artículo](https://jmrp.io/es/blog/004-enabling-quic-http3-nginx/)) - [Implementar un Tarpit en Nginx: Atrapa a los Escáneres Maliciosos](https://jmrp.io/es/blog/005-implementing-tarpit-nginx/index.md): Implementa un tarpit en Nginx para ralentizar bots maliciosos, escáneres de vulnerabilidades y ataques de fuerza bruta. Integración con CrowdSec incluida. ([artículo](https://jmrp.io/es/blog/005-implementing-tarpit-nginx/)) - [Honeypot en MikroTik: Atrapa y Bloquea Escáneres de Puertos](https://jmrp.io/es/blog/006-implementing-mikrotik-honeypot/index.md): Configura un honeypot en MikroTik para detectar escáneres de puertos, registrar actividad maliciosa y bloquear atacantes automáticamente con la tabla RAW. ([artículo](https://jmrp.io/es/blog/006-implementing-mikrotik-honeypot/)) - [WireGuard en MikroTik: configuración dual-stack IPv4/IPv6](https://jmrp.io/es/blog/007-mikrotik-wireguard-dual-stack-vpn/index.md): Configura WireGuard en MikroTik RouterOS con dual-stack IPv4/IPv6 completo. Accede a tu red doméstica con IPv6 nativo desde cualquier conexión. ([artículo](https://jmrp.io/es/blog/007-mikrotik-wireguard-dual-stack-vpn/)) - [MikroTik PPPoE + DHCPv6-PD: Dual-Stack para DIGI España](https://jmrp.io/es/blog/008-mikrotik-pppoe-dualstack-digi/index.md): Configura PPPoE con DHCPv6 Prefix Delegation en MikroTik RouterOS para DIGI España. VLAN tagging, SLAAC, gestión de cambios de prefijo y firewall. ([artículo](https://jmrp.io/es/blog/008-mikrotik-pppoe-dualstack-digi/)) - [Bridge Tor en Linux: guía completa de obfs4 y WebTunnel](https://jmrp.io/es/blog/009-running-tor-bridge/index.md): Guía para ejecutar bridges Tor obfs4 y WebTunnel en Linux con camuflaje Nginx, firewall, monitorización Prometheus e integración CrowdSec. ([artículo](https://jmrp.io/es/blog/009-running-tor-bridge/)) - [Lo que el linker no hará: empaquetar cadenas i18n en un MCU](https://jmrp.io/es/blog/010-packed-i18n-string-pool/index.md): Un generador empaqueta las traducciones del firmware en un pool indexado por offsets uint16, reduciendo a la mitad la tabla índice en un MCU de 32 bits. ([artículo](https://jmrp.io/es/blog/010-packed-i18n-string-pool/)) - [Una bóveda con bloqueo ante fallos: Encrypt-then-MAC en un MCU](https://jmrp.io/es/blog/011-encrypt-then-mac-vault/index.md): Cómo un gestor de contraseñas hardware autentica cada fichero antes de descifrar: Encrypt-then-MAC, verificación antes de descifrar y bloqueo ante fallos. ([artículo](https://jmrp.io/es/blog/011-encrypt-then-mac-vault/)) - [Un PIN de 4 dígitos basta: claves vinculadas al ESP32-S3](https://jmrp.io/es/blog/012-device-bound-key-derivation/index.md): Por qué las iteraciones de PBKDF2 no protegen un PIN de 4 dígitos en un MCU, y cómo un secreto del dispositivo más HKDF frenan la fuerza bruta offline. ([artículo](https://jmrp.io/es/blog/012-device-bound-key-derivation/)) - [Lo que construir un servidor MCP me enseñó sobre la API de GitLab](https://jmrp.io/es/blog/013-gitlab-mcp-server-api-lessons/index.md): Construir y contrastar un servidor MCP con GitLab destapó un 401 que era un 403 y escrituras aceptadas que no guardaban nada; cada caso acabó upstream. ([artículo](https://jmrp.io/es/blog/013-gitlab-mcp-server-api-lessons/)) - [Tokens de grano fino de GitLab, acción por acción](https://jmrp.io/es/blog/014-gitlab-fine-grained-tokens-per-action/index.md): Un token de grano fino de GitLab lleva una concesión, no scopes: fuera de ella, REST rechaza y GraphQL responde null. Deduzco qué necesita cada acción. ([artículo](https://jmrp.io/es/blog/014-gitlab-fine-grained-tokens-per-action/)) ## Developer Tools ### Base64 Encoder / Decoder URL: https://jmrp.io/tools/base64-encoder/ Markdown: https://jmrp.io/tools/base64-encoder/index.md Category: developer Tags: base64, encoding, decoding, hex, url-encoding Encode and decode Base64, Base64URL, URL encoding, hex, and HTML entities. File support for images and documents. Runs client-side. Features: - Encode and decode Base64 and Base64URL - Convert URL, hex, HTML entities, and binary - Encode files via drag-and-drop with preview - Generate Data URIs for CSS and HTML - Runs fully client-side, no uploads Questions answered: **Is Base64 a form of encryption?** No. Base64 is an encoding scheme, not encryption. It makes binary data safe to transmit as text but provides no confidentiality, since anyone can decode it instantly. Never use it to protect secrets. **What is the difference between Base64 and Base64URL?** Standard Base64 ([RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648)) uses + and / characters plus = padding, which can break inside URLs. Base64URL replaces them with - and _ and usually drops the padding, making it safe for URLs and JWTs. **Is my data uploaded to a server when I encode a file?** No. All encoding and decoding runs entirely in your browser. Files you drop are never uploaded, so your data never leaves your device. **Why is my Base64 output larger than the original file?** Base64 represents every 3 bytes of input as 4 ASCII characters, so the output is roughly 33% larger than the source data. This is expected overhead for any Base64 encoding. **What is a Data URI and when should I use it?** A Data URI embeds the Base64-encoded content directly inside CSS or HTML using a data:;base64,... prefix, avoiding a separate file request. Enable the Data URI toggle to get a ready-to-paste string for small assets like icons. ### Certificate Inspector URL: https://jmrp.io/tools/cert-inspector/ Markdown: https://jmrp.io/tools/cert-inspector/index.md Category: security Tags: ssl, tls, certificates, x509, pem, security Decode PEM SSL/TLS certificates or fetch from a URL client-side. Inspect subject, issuer, validity, SANs, key usage, and security assessment. Features: - Decode PEM or fetch certificates by URL - Inspect subject, issuer, validity, and SANs - View key details, usage, and extensions - Compute SHA-256 fingerprint in-browser - Security assessment of keys and algorithms Questions answered: **Is my certificate uploaded to a server?** No. All ASN.1/DER parsing, SHA-256 fingerprinting, and the security assessment run entirely in your browser. Pasted PEM data never leaves your device. **Can I inspect a private or internal certificate?** Yes. Paste the PEM-encoded data directly instead of fetching by URL. URL fetching relies on public Certificate Transparency log APIs (certspotter, crt.sh) and only works for publicly logged certificates. **What does the security assessment check?** The Certificate Inspector's security assessment evaluates key strength, the signature algorithm, the validity duration, and Certificate Transparency (SCT) compliance, flagging weak keys, deprecated algorithms, and overly long validity periods. **What is a Subject Alternative Name (SAN)?** A SAN lists every hostname, IP, email, or URI a certificate is valid for. Modern browsers ignore the Common Name and match the requested host against the SAN entries, so a missing SAN causes trust errors. **How do I inspect a certificate without this tool?** Use OpenSSL from the terminal, for example "openssl s_client -connect host:443" piped into "openssl x509 -noout -text". The Linux command reference above lists ready-to-use snippets. ### Color Contrast Checker URL: https://jmrp.io/tools/color-contrast-checker/ Markdown: https://jmrp.io/tools/color-contrast-checker/index.md Category: developer Tags: accessibility, wcag, contrast, color, a11y, apca Check color contrast ratios for WCAG 2.2 AA and AAA compliance with APCA support, color blindness simulation, and auto-fix suggestions. Runs client-side. Features: - Check WCAG 2.2 AA and AAA contrast ratios - Score perceptual contrast with APCA Lc - Simulate four color vision deficiencies - Auto-fix suggestions for failing colors - Export CSS and share via URL Questions answered: **What is the minimum WCAG 2.2 contrast ratio for normal text?** Normal text needs at least 4.5:1 for AA and 7:1 for AAA. Large text (18pt+, or 14pt+ bold) only needs 3:1 for AA and 4.5:1 for AAA. **What's the difference between WCAG 2.2 contrast and APCA?** WCAG 2.x uses a simple luminance ratio, while APCA (planned for WCAG 3.0) models human perception, accounting for text polarity, font size, and weight. This tool reports both so you can compare them. **Does the contrast checker run in my browser?** Yes. All contrast calculations happen entirely client-side and no color data is sent to any server. Shareable links only encode the colors in the URL parameters. **Why check colors against color blindness simulations?** Roughly 8% of men and 0.5% of women have some color vision deficiency, so a pair that passes for typical vision may still fail for them. Each simulation card shows the perceived contrast ratio for protanopia, deuteranopia, tritanopia, and achromatopsia. **What does the non-text contrast (SC 1.4.11) check cover?** The non-text contrast check (SC 1.4.11) applies the WCAG 2.2 minimum of 3:1 to UI components such as buttons, inputs, and borders, plus graphical objects that convey information "meaning". ### Cron Expression Builder URL: https://jmrp.io/tools/cron-builder/ Markdown: https://jmrp.io/tools/cron-builder/index.md Category: developer Tags: cron, scheduling, linux, crontab, automation Visual cron expression builder with interactive field selectors, presets, next execution preview, and crontab output. Runs client-side. Features: - Build cron expressions with visual field selectors - Choose from 14 common schedule presets - Read human-readable schedule descriptions - Preview the next 10 executions - Generate crontab lines and shareable links Questions answered: **What is a cron expression?** A cron expression is a string of five space-separated fields (minute, hour, day of month, month, day of week) that tells a Unix-like scheduler when to run a task repeatedly. **How do I run a cron job every 5 minutes?** Use the step syntax "*/5 * * * *". You can build it here by selecting the minute field's step or picking the "every 5 minutes" preset, then copy the generated crontab line. **Does this tool send my cron expression to a server?** No. All parsing, the human-readable description, and the next-execution preview run entirely in your browser. The shareable link only encodes the expression in the URL. **What happens when both day of month and day of week are set?** Most cron implementations use OR logic: when neither field is "*", the job runs whenever either the day-of-month or the day-of-week condition matches. **Why does my cron job fail even though the schedule is correct?** Cron runs with a minimal PATH and the system timezone, so use absolute paths for commands and check timedatectl. Redirect output with ">> /var/log/myjob.log 2>&1" to capture errors. ### CSP Hash Calculator URL: https://jmrp.io/tools/hash-calculator/ Markdown: https://jmrp.io/tools/hash-calculator/index.md Category: security Tags: csp, hash, sha256, security, sri Generate SHA-256 hashes for inline scripts. Get ready-to-use CSP directives for your Content Security Policy. Runs client-side. Features: - Real-time SHA-256 hashing as you type - Supports SHA-256, SHA-384 and SHA-512 - Outputs ready-to-use CSP script-src directives - Optional whitespace cleanup before hashing - Web Crypto API, content never sent to a server Questions answered: **When should I use a CSP hash instead of a nonce?** Use a hash for inline scripts or styles whose content never changes, so you can allow them without "unsafe-inline". If the script contains dynamic values like a user ID, use a nonce instead, because any change to the content breaks the hash. **Why does my inline script still get blocked after adding the hash?** CSP hashes require an exact byte-for-byte match, so even a single extra space or newline produces a different hash and the browser blocks the script. Make sure you hash only the inner content, without the surrounding "