<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://xxzkid.github.io/en/</id>
    <title>Apache Wangye</title>
    <updated>2026-04-04T12:19:36.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://xxzkid.github.io/en/"/>
    <subtitle>Practical notes on Java, Linux, databases, cloud native technologies, and software engineering.</subtitle>
    <icon>https://xxzkid.github.io/en/favicon.ico</icon>
    <rights>Copyright © 2026 Apache Wangye</rights>
    <entry>
        <title type="html"><![CDATA[Install OpenClaw and Connect a Feishu Bot]]></title>
        <id>https://xxzkid.github.io/en/2026/openclaw-start/</id>
        <link href="https://xxzkid.github.io/en/2026/openclaw-start/"/>
        <updated>2026-04-04T12:19:36.000Z</updated>
        <summary type="html"><![CDATA[Install OpenClaw, configure model authorization and its gateway, connect a Feishu bot, grant permissions, subscribe to events, and secure the deployment.]]></summary>
        <content type="html"><![CDATA[<p>This guide describes the end-to-end structure for connecting an OpenClaw deployment to a Feishu bot and using it as an internal AI assistant.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-prepare-the-runtime">1. Prepare the runtime<a href="https://xxzkid.github.io/en/2026/openclaw-start/#1-prepare-the-runtime" class="hash-link" aria-label="Direct link to 1. Prepare the runtime" title="Direct link to 1. Prepare the runtime" translate="no">​</a></h2>
<p>Install the runtime and dependencies required by the OpenClaw release used by the project. Keep the application, plugin, and model-provider versions pinned, and store configuration outside source control.</p>
<p>After installation, start the service locally and confirm its health endpoint and logs before exposing any network port.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-configure-the-model-provider">2. Configure the model provider<a href="https://xxzkid.github.io/en/2026/openclaw-start/#2-configure-the-model-provider" class="hash-link" aria-label="Direct link to 2. Configure the model provider" title="Direct link to 2. Configure the model provider" translate="no">​</a></h2>
<p>Create credentials for the selected model provider and place them in environment variables or a secret manager. Configure the model name, API endpoint, timeout, retry policy, and token or spending limits.</p>
<p>Do not embed model keys in frontend code, screenshots, bot messages, or committed configuration files. Use a separate key and account for production.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-configure-the-openclaw-gateway">3. Configure the OpenClaw gateway<a href="https://xxzkid.github.io/en/2026/openclaw-start/#3-configure-the-openclaw-gateway" class="hash-link" aria-label="Direct link to 3. Configure the OpenClaw gateway" title="Direct link to 3. Configure the OpenClaw gateway" translate="no">​</a></h2>
<p>The gateway receives Feishu events and sends messages to the model-backed agent. Configure a stable public HTTPS callback URL, request timeouts, allowed tenants, and logging that excludes message content and credentials.</p>
<p>Place the service behind a reverse proxy when appropriate, and restrict administrative endpoints to trusted networks.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-create-the-feishu-application">4. Create the Feishu application<a href="https://xxzkid.github.io/en/2026/openclaw-start/#4-create-the-feishu-application" class="hash-link" aria-label="Direct link to 4. Create the Feishu application" title="Direct link to 4. Create the Feishu application" translate="no">​</a></h2>
<p>In the Feishu developer console:</p>
<ol>
<li class="">Create an internal application.</li>
<li class="">Enable the bot capability.</li>
<li class="">Record the App ID and App Secret securely.</li>
<li class="">Add only the message and user permissions required by the assistant.</li>
<li class="">Configure the event-subscription callback URL and verification token.</li>
<li class="">Subscribe to the message events required by the integration.</li>
<li class="">Publish the application to the intended organization scope.</li>
</ol>
<p>Permission names and console locations can change, so follow the exact UI and documentation for the current Feishu platform version.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-verify-event-handling">5. Verify event handling<a href="https://xxzkid.github.io/en/2026/openclaw-start/#5-verify-event-handling" class="hash-link" aria-label="Direct link to 5. Verify event handling" title="Direct link to 5. Verify event handling" translate="no">​</a></h2>
<p>Feishu first verifies the callback endpoint. The service must validate the request signature or verification token before accepting events.</p>
<p>Test with a dedicated chat and account. Confirm that:</p>
<ul>
<li class="">the callback receives the event once;</li>
<li class="">duplicate event IDs are ignored;</li>
<li class="">bot messages do not trigger an infinite reply loop;</li>
<li class="">user and tenant scope are enforced;</li>
<li class="">long model responses are split or formatted correctly;</li>
<li class="">timeouts return a controlled message instead of failing silently.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-security-and-operations">6. Security and operations<a href="https://xxzkid.github.io/en/2026/openclaw-start/#6-security-and-operations" class="hash-link" aria-label="Direct link to 6. Security and operations" title="Direct link to 6. Security and operations" translate="no">​</a></h2>
<p>Treat chat messages as potentially sensitive business data. Define what content may be sent to the model provider, apply redaction where required, and make retention and audit behavior explicit.</p>
<p>Use least-privilege Feishu permissions, rotate secrets, verify webhook signatures, rate-limit requests, and isolate tool execution. Any feature that can read files, invoke commands, query internal systems, or send messages should require explicit authorization and allowlisted operations.</p>
<p>Monitor callback errors, model latency, token use, failed replies, duplicate events, and provider outages. Add a circuit breaker or fallback response so a model failure does not overload Feishu retries.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-production-checklist">7. Production checklist<a href="https://xxzkid.github.io/en/2026/openclaw-start/#7-production-checklist" class="hash-link" aria-label="Direct link to 7. Production checklist" title="Direct link to 7. Production checklist" translate="no">​</a></h2>
<p>Before rollout, complete a small pilot with synthetic or low-sensitivity data. Document the bot's scope, supported commands, escalation path, model limitations, and data policy. Test secret rotation, service restart, network interruption, duplicate delivery, and rollback of the OpenClaw configuration.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="AI" term="AI"/>
        <category label="OpenClaw" term="OpenClaw"/>
        <category label="Claude" term="Claude"/>
        <category label="ChatGPT" term="ChatGPT"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Deploy MinIO with Docker Compose: A Practical Quick Start]]></title>
        <id>https://xxzkid.github.io/en/2025/minio-quickstart/</id>
        <link href="https://xxzkid.github.io/en/2025/minio-quickstart/"/>
        <updated>2025-12-09T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Deploy MinIO with Docker Compose, persistent storage, a separate console port, secure credentials, health checks, TLS, backups, and production safeguards.]]></summary>
        <content type="html"><![CDATA[<p>MinIO provides an S3-compatible object storage API that works well for development, private clouds, backups, and application file storage. This guide starts with a single-node Docker Compose deployment and then explains what must change before exposing it to production traffic.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="prerequisites">Prerequisites<a href="https://xxzkid.github.io/en/2025/minio-quickstart/#prerequisites" class="hash-link" aria-label="Direct link to Prerequisites" title="Direct link to Prerequisites" translate="no">​</a></h2>
<p>Install Docker Engine and the Docker Compose plugin, then verify them:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">docker version</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">docker compose version</span><br></div></code></pre></div></div>
<p>Create directories for persistent data and configuration:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">sudo mkdir -p /srv/minio/data</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">sudo chown -R 1000:1000 /srv/minio</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="docker-compose-configuration">Docker Compose configuration<a href="https://xxzkid.github.io/en/2025/minio-quickstart/#docker-compose-configuration" class="hash-link" aria-label="Direct link to Docker Compose configuration" title="Direct link to Docker Compose configuration" translate="no">​</a></h2>
<p>Create <code>compose.yaml</code>:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token key atrule">services</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">minio</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> quay.io/minio/minio</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain">RELEASE.2024</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">09</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">22T00</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">33</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">43Z</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">container_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> minio</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">command</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> server /data </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">address "</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain">9001"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">restart</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> unless</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">stopped</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">environment</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">MINIO_ROOT_USER</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">MINIO_ROOT_USER</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">MINIO_ROOT_PASSWORD</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">MINIO_ROOT_PASSWORD</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">volumes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> /srv/minio/data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain">/data</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">ports</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"9000:9000"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"9001:9001"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">healthcheck</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">test</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">"CMD"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"curl"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"-f"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"http://localhost:9000/minio/health/live"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">interval</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> 30s</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">timeout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> 10s</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">retries</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">3</span><br></div></code></pre></div></div>
<p>Store credentials in a local <code>.env</code> file and keep it out of version control:</p>
<div class="language-dotenv codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dotenv codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">MINIO_ROOT_USER=minio-root</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">MINIO_ROOT_PASSWORD=replace-with-a-long-random-secret</span><br></div></code></pre></div></div>
<p>Start the service and inspect its health:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">docker compose up -d</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">docker compose ps</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">docker compose logs --tail=100 minio</span><br></div></code></pre></div></div>
<p>The S3 API listens on port <code>9000</code>; the administration console uses <code>9001</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-the-minio-client">Configure the MinIO client<a href="https://xxzkid.github.io/en/2025/minio-quickstart/#configure-the-minio-client" class="hash-link" aria-label="Direct link to Configure the MinIO client" title="Direct link to Configure the MinIO client" translate="no">​</a></h2>
<p>Install the official <code>mc</code> client, then create an alias:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc alias set local http://127.0.0.1:9000 minio-root 'your-password'</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc admin info local</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc mb local/example</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc ls local</span><br></div></code></pre></div></div>
<p>Applications should not use the root account. Create a dedicated user and attach only the policy it needs:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc admin user add local app-user 'another-long-random-secret'</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc admin policy attach local readwrite --user app-user</span><br></div></code></pre></div></div>
<p>For production, replace the broad <code>readwrite</code> policy with a bucket-specific policy.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="production-checklist">Production checklist<a href="https://xxzkid.github.io/en/2025/minio-quickstart/#production-checklist" class="hash-link" aria-label="Direct link to Production checklist" title="Direct link to Production checklist" translate="no">​</a></h2>
<p>A running container is not yet a resilient storage service:</p>
<ul>
<li class="">Terminate TLS at MinIO or a trusted reverse proxy, and do not expose the console publicly without access controls.</li>
<li class="">Pin an image release, test upgrades in staging, and read the release notes before changing versions.</li>
<li class="">Use multiple drives and nodes when availability matters. A single data directory has no disk redundancy.</li>
<li class="">Back up configuration and critical objects to a separate failure domain.</li>
<li class="">Monitor disk capacity, request errors, latency, and node health.</li>
<li class="">Restrict ports with a firewall and rotate credentials regularly.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="common-problems">Common problems<a href="https://xxzkid.github.io/en/2025/minio-quickstart/#common-problems" class="hash-link" aria-label="Direct link to Common problems" title="Direct link to Common problems" translate="no">​</a></h2>
<p>If the container exits immediately, check directory ownership and <code>docker compose logs</code>. If S3 requests work locally but fail through a proxy, verify forwarded headers, the public server URL, TLS configuration, and request-size limits. Clock drift can also break signed S3 requests, so keep the host synchronized with NTP.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="minio" term="minio"/>
        <category label="java" term="java"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Self-Host n8n with Docker Compose Securely]]></title>
        <id>https://xxzkid.github.io/en/2025/n8n-quickstart/</id>
        <link href="https://xxzkid.github.io/en/2025/n8n-quickstart/"/>
        <updated>2025-12-09T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Self-host n8n with Docker Compose, persistent data, encryption keys, correct webhook URLs, HTTPS reverse proxy settings, backups, and update practices.]]></summary>
        <content type="html"><![CDATA[<p>n8n is a workflow automation platform that can connect APIs, databases, AI services, and internal tools. A self-hosted instance may contain production credentials and business data, so persistence, encryption, HTTPS, access control, and backups should be part of the first deployment.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="docker-compose-configuration">Docker Compose configuration<a href="https://xxzkid.github.io/en/2025/n8n-quickstart/#docker-compose-configuration" class="hash-link" aria-label="Direct link to Docker Compose configuration" title="Direct link to Docker Compose configuration" translate="no">​</a></h2>
<p>Create a dedicated directory and a <code>.env</code> file containing a stable encryption key:</p>
<div class="language-dotenv codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dotenv codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">N8N_HOST=n8n.example.com</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">N8N_ENCRYPTION_KEY=replace-with-a-long-random-value</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">TZ=UTC</span><br></div></code></pre></div></div>
<p>Never change or lose <code>N8N_ENCRYPTION_KEY</code> after credentials have been saved. Without it, encrypted credentials may become unreadable.</p>
<p>Create <code>compose.yaml</code>:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token key atrule">services</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">n8n</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> docker.n8n.io/n8nio/n8n</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain">2.0.0</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">container_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> n8n</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">restart</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> unless</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">stopped</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">environment</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> N8N_HOST=$</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">N8N_HOST</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> N8N_PROTOCOL=https</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> N8N_PORT=5678</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> WEBHOOK_URL=https</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain">//$</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">N8N_HOST</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain">/</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> N8N_PROXY_HOPS=1</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> N8N_ENCRYPTION_KEY=$</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">N8N_ENCRYPTION_KEY</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> GENERIC_TIMEZONE=$</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">TZ</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> TZ=$</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">TZ</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">volumes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> n8n_data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain">/home/node/.n8n</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">expose</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"5678"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">volumes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  n8n_data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><br></div></code></pre></div></div>
<p>Start and inspect the container:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">docker compose up -d</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">docker compose logs -f --tail=100 n8n</span><br></div></code></pre></div></div>
<p>Using <code>expose</code> keeps port 5678 off the public host interface. Place n8n behind an HTTPS reverse proxy on the same Docker network or publish the port only to <code>127.0.0.1</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="reverse-proxy-requirements">Reverse proxy requirements<a href="https://xxzkid.github.io/en/2025/n8n-quickstart/#reverse-proxy-requirements" class="hash-link" aria-label="Direct link to Reverse proxy requirements" title="Direct link to Reverse proxy requirements" translate="no">​</a></h2>
<p>Your proxy must forward the original host, protocol, and client address. For Nginx, the core location is:</p>
<div class="language-nginx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-nginx codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">location / {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    proxy_pass http://127.0.0.1:5678;</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    proxy_http_version 1.1;</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    proxy_set_header Host $host;</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    proxy_set_header X-Real-IP $remote_addr;</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    proxy_set_header X-Forwarded-Proto https;</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    proxy_set_header Upgrade $http_upgrade;</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    proxy_set_header Connection "upgrade";</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></div></code></pre></div></div>
<p>Incorrect <code>WEBHOOK_URL</code>, proxy headers, or proxy-hop settings are common reasons test webhooks work but production webhooks point to localhost or use HTTP.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="backups">Backups<a href="https://xxzkid.github.io/en/2025/n8n-quickstart/#backups" class="hash-link" aria-label="Direct link to Backups" title="Direct link to Backups" translate="no">​</a></h2>
<p>Back up both the database and the encryption key. With the default SQLite setup, the named volume contains the database and instance data. Stop writes or use an application-consistent method before copying it. Larger teams should evaluate PostgreSQL and test a complete restore regularly.</p>
<p>Exporting workflows is useful, but workflow JSON alone is not a full disaster-recovery backup because credentials, executions, users, and instance configuration live elsewhere.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="security-checklist">Security checklist<a href="https://xxzkid.github.io/en/2025/n8n-quickstart/#security-checklist" class="hash-link" aria-label="Direct link to Security checklist" title="Direct link to Security checklist" translate="no">​</a></h2>
<ul>
<li class="">Use HTTPS and restrict editor access with an identity-aware proxy, VPN, or firewall.</li>
<li class="">Run the container as its default non-root user.</li>
<li class="">Keep secrets out of workflow logs and source control.</li>
<li class="">Limit community nodes and review any node that executes code.</li>
<li class="">Configure execution retention so old payloads do not grow forever.</li>
<li class="">Pin versions, read release notes, and back up before upgrades.</li>
<li class="">Protect public webhooks with signatures, tokens, rate limits, and input validation.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="updating-n8n">Updating n8n<a href="https://xxzkid.github.io/en/2025/n8n-quickstart/#updating-n8n" class="hash-link" aria-label="Direct link to Updating n8n" title="Direct link to Updating n8n" translate="no">​</a></h2>
<p>Pull and recreate the service after reviewing breaking changes:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">docker compose pull</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">docker compose up -d</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">docker compose logs --tail=100 n8n</span><br></div></code></pre></div></div>
<p>For important workflows, rehearse upgrades against a restored backup before updating production.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="n8n" term="n8n"/>
        <category label="ai" term="ai"/>
        <category label="java" term="java"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Migrate MinIO Data Safely with mc mirror]]></title>
        <id>https://xxzkid.github.io/en/2025/minio-data-migration/</id>
        <link href="https://xxzkid.github.io/en/2025/minio-data-migration/"/>
        <updated>2025-11-27T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Migrate MinIO buckets with mc mirror using full and incremental synchronization, validation, versioning checks, policy migration, and a low-downtime cutover plan.]]></summary>
        <content type="html"><![CDATA[<p>Moving MinIO is more than copying the latest object files. A reliable migration must account for versions, delete markers, metadata, lifecycle rules, access policies, encryption, and writes that occur during the copy. The safest pattern is a full synchronization followed by incremental catch-up and a controlled cutover.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-configure-source-and-destination-aliases">1. Configure source and destination aliases<a href="https://xxzkid.github.io/en/2025/minio-data-migration/#1-configure-source-and-destination-aliases" class="hash-link" aria-label="Direct link to 1. Configure source and destination aliases" title="Direct link to 1. Configure source and destination aliases" translate="no">​</a></h2>
<p>Install a recent MinIO Client release and configure both endpoints:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc alias set old https://old-minio.example.com ACCESS_KEY SECRET_KEY</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc alias set new https://new-minio.example.com ACCESS_KEY SECRET_KEY</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc admin info old</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc admin info new</span><br></div></code></pre></div></div>
<p>Avoid placing real secrets in shell history. Prefer environment variables, a restricted configuration file, or a secrets manager.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-inventory-the-source">2. Inventory the source<a href="https://xxzkid.github.io/en/2025/minio-data-migration/#2-inventory-the-source" class="hash-link" aria-label="Direct link to 2. Inventory the source" title="Direct link to 2. Inventory the source" translate="no">​</a></h2>
<p>Before copying data, record the bucket list and important settings:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc ls old</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc admin info old</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc ilm rule ls old/my-bucket</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc version info old/my-bucket</span><br></div></code></pre></div></div>
<p>Also inventory users, groups, policies, bucket notifications, object-lock settings, replication rules, and server-side encryption keys. <code>mc mirror</code> focuses on objects; it does not automatically reproduce every administrative setting.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-run-the-initial-mirror">3. Run the initial mirror<a href="https://xxzkid.github.io/en/2025/minio-data-migration/#3-run-the-initial-mirror" class="hash-link" aria-label="Direct link to 3. Run the initial mirror" title="Direct link to 3. Run the initial mirror" translate="no">​</a></h2>
<p>Create the destination bucket if needed and start the full copy:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc mb --ignore-existing new/my-bucket</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc mirror --preserve --overwrite old/my-bucket new/my-bucket</span><br></div></code></pre></div></div>
<p>Use <code>--remove</code> only when the destination must be an exact mirror and you are certain that destination-only objects may be deleted. Test that behavior on a disposable bucket first.</p>
<p>For a long migration, run the command in a managed terminal session and save logs:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc mirror --preserve --overwrite --json old/my-bucket new/my-bucket</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-catch-up-new-writes">4. Catch up new writes<a href="https://xxzkid.github.io/en/2025/minio-data-migration/#4-catch-up-new-writes" class="hash-link" aria-label="Direct link to 4. Catch up new writes" title="Direct link to 4. Catch up new writes" translate="no">​</a></h2>
<p>While applications still write to the old cluster, repeat the mirror to transfer changes. Shortly before cutover:</p>
<ol>
<li class="">Put writers into maintenance or read-only mode.</li>
<li class="">Run one final incremental mirror.</li>
<li class="">Compare source and destination.</li>
<li class="">Switch application endpoints and credentials.</li>
<li class="">Keep the old service read-only until validation is complete.</li>
</ol>
<p>This sequence minimizes downtime without losing objects written during the first copy.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-validate-the-result">5. Validate the result<a href="https://xxzkid.github.io/en/2025/minio-data-migration/#5-validate-the-result" class="hash-link" aria-label="Direct link to 5. Validate the result" title="Direct link to 5. Validate the result" translate="no">​</a></h2>
<p>Compare object counts and total sizes, but do not treat matching totals as sufficient proof. Sample critical objects and verify metadata, content type, ETag or checksums, application reads, presigned URLs, and permissions.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc du --recursive old/my-bucket</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc du --recursive new/my-bucket</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc stat old/my-bucket/path/to/object</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mc stat new/my-bucket/path/to/object</span><br></div></code></pre></div></div>
<p>Multipart uploads and encrypted objects can make ETags unsuitable as universal content hashes. Use application-level checksums when correctness is critical.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="versioning-and-deletion-caveats">Versioning and deletion caveats<a href="https://xxzkid.github.io/en/2025/minio-data-migration/#versioning-and-deletion-caveats" class="hash-link" aria-label="Direct link to Versioning and deletion caveats" title="Direct link to Versioning and deletion caveats" translate="no">​</a></h2>
<p>Confirm how the client version you use handles object versions and delete markers. If legal retention, object lock, or historical versions matter, test the complete behavior with representative data before migrating production. For very large or continuously changing datasets, MinIO replication may be a better fit than repeated mirroring.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="rollback-plan">Rollback plan<a href="https://xxzkid.github.io/en/2025/minio-data-migration/#rollback-plan" class="hash-link" aria-label="Direct link to Rollback plan" title="Direct link to Rollback plan" translate="no">​</a></h2>
<p>Do not delete the source immediately. Define a rollback window, preserve DNS or endpoint settings, and document how writes will be reconciled if traffic must return to the old cluster. A successful migration ends only after monitoring confirms normal error rates, latency, permissions, and object integrity.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="minio" term="minio"/>
        <category label="java" term="java"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[openGauss Database Quick Start]]></title>
        <id>https://xxzkid.github.io/en/2025/opengauss-quickstart/</id>
        <link href="https://xxzkid.github.io/en/2025/opengauss-quickstart/"/>
        <updated>2025-11-26T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Install openGauss, initialize an instance, create users and databases, enable controlled remote access, and run basic SQL.]]></summary>
        <content type="html"><![CDATA[<p>openGauss is a relational database with PostgreSQL-influenced tooling and SQL behavior. Follow the exact documentation for the selected release because installation requirements and commands vary.</p>
<p>After installing the packages, initialize and start an instance with the supplied management tools, then connect through <code>gsql</code>. Create a dedicated application user and database instead of using the administrator account:</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">CREATE</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">USER</span><span class="token plain"> app_user IDENTIFIED </span><span class="token keyword" style="font-style:italic">BY</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'long-random-password'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">CREATE</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">DATABASE</span><span class="token plain"> app_db OWNER app_user</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>For remote access, update the listening address and host-based authentication rules, then restrict the database port with a firewall. Test with:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">gsql -d app_db -U app_user -h 127.0.0.1 -p 5432</span><br></div></code></pre></div></div>
<p>Before production use, configure TLS, backups, archive or replication strategy, resource limits, monitoring, and tested restore procedures.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="opengauss" term="opengauss"/>
        <category label="java" term="java"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Configure Proxy Rules with SwitchOmega or ZeroOmega]]></title>
        <id>https://xxzkid.github.io/en/2025/switchomega-config/</id>
        <link href="https://xxzkid.github.io/en/2025/switchomega-config/"/>
        <updated>2025-09-13T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Configure SwitchOmega or ZeroOmega profiles, proxy servers, automatic switching rules, external rule lists, and common troubleshooting checks.]]></summary>
        <content type="html"><![CDATA[<p>SwitchOmega and its maintained alternatives such as ZeroOmega let a browser select different proxy profiles according to URL rules.</p>
<p>The extension only chooses a configured proxy server; it does not provide a proxy service itself. Before importing a third-party rule list, verify its source and avoid routing passwords or other sensitive traffic through an untrusted proxy.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="install-the-extension">Install the extension<a href="https://xxzkid.github.io/en/2025/switchomega-config/#install-the-extension" class="hash-link" aria-label="Direct link to Install the extension" title="Direct link to Install the extension" translate="no">​</a></h2>
<p>Download a release from the ZeroOmega project:</p>
<ul>
<li class="">Chrome and Chromium-based browsers use the <code>.crx</code> package when manual installation is supported.</li>
<li class="">Firefox uses the <code>.xpi</code> package.</li>
</ul>
<p>Release page:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">https://github.com/zero-peak/ZeroOmega/releases</span><br></div></code></pre></div></div>
<p>Browser extension policies change over time. On managed Chrome installations, manual <code>.crx</code> installation may be blocked, so use an approved extension store or the organization's deployment policy when required.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="create-a-proxy-profile">Create a proxy profile<a href="https://xxzkid.github.io/en/2025/switchomega-config/#create-a-proxy-profile" class="hash-link" aria-label="Direct link to Create a proxy profile" title="Direct link to Create a proxy profile" translate="no">​</a></h2>
<p>Open the extension and create a proxy profile. Enter the proxy protocol, host, and port supplied by your own proxy service. Test the profile directly before adding automatic switching rules.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-automatic-switching">Configure automatic switching<a href="https://xxzkid.github.io/en/2025/switchomega-config/#configure-automatic-switching" class="hash-link" aria-label="Direct link to Configure automatic switching" title="Direct link to Configure automatic switching" translate="no">​</a></h2>
<p>Open the <strong>Auto Switch</strong> profile, add a rule-list condition, and enter a trusted rule-list URL, for example:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt</span><br></div></code></pre></div></div>
<p>Choose the proxy profile for requests that match the rule list. Configure a direct or fallback profile for unmatched requests, then apply the changes.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="troubleshooting">Troubleshooting<a href="https://xxzkid.github.io/en/2025/switchomega-config/#troubleshooting" class="hash-link" aria-label="Direct link to Troubleshooting" title="Direct link to Troubleshooting" translate="no">​</a></h2>
<p>When a site does not use the expected route:</p>
<ol>
<li class="">Confirm that the proxy profile works when selected manually.</li>
<li class="">Refresh the external rule list and inspect whether the domain is included.</li>
<li class="">Check rule order because earlier rules may take precedence.</li>
<li class="">Verify that another VPN, system proxy, or browser policy is not overriding the extension.</li>
<li class="">Review DNS behavior, authentication errors, and the proxy server logs.</li>
</ol>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="tools" term="tools"/>
        <category label="switchomega" term="switchomega"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Build a Safe Batch File Renaming Tool in Java]]></title>
        <id>https://xxzkid.github.io/en/2025/file-rename-quickstart/</id>
        <link href="https://xxzkid.github.io/en/2025/file-rename-quickstart/"/>
        <updated>2025-06-16T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Rename files in batches with Java regular expressions while adding previews, collision checks, validation, and rollback-friendly behavior.]]></summary>
        <content type="html"><![CDATA[<p>Batch renaming is less about speed than preventing overwrites and irreversible mistakes. A reliable tool should first generate a preview, detect duplicate target names and invalid paths, and require confirmation before changing files.</p>
<p>The following example appends <code>.json</code> to filenames made of six digits:</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">import java.io.File;</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">import java.util.regex.Matcher;</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">import java.util.regex.Pattern;</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">String directory = "C:\\tests";</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">String matchRegex = "(\\d{6})";</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">String replaceRegex = "$1.json";</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Pattern pattern = Pattern.compile(matchRegex);</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">File folder = new File(directory);</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">if (folder.isDirectory()) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    File[] files = folder.listFiles();</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    if (files != null) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        System.out.println("files: " + files.length);</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        for (File source : files) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            Matcher matcher = pattern.matcher(source.getName());</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            if (!matcher.matches()) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                continue;</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            String targetName = matcher.replaceAll(replaceRegex);</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            File target = new File(source.getParentFile(), targetName);</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            System.out.printf("%s -&gt; %s%n", source.getName(), targetName);</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            if (target.exists()) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                System.err.println("Skipped because the target already exists: " + target);</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                continue;</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            if (!source.renameTo(target)) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                System.err.println("Rename failed: " + source);</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="recommended-improvements">Recommended improvements<a href="https://xxzkid.github.io/en/2025/file-rename-quickstart/#recommended-improvements" class="hash-link" aria-label="Direct link to Recommended improvements" title="Direct link to Recommended improvements" translate="no">​</a></h2>
<p>For production code, use <code>java.nio.file.Files.move</code> so failures produce useful exceptions:</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">Files.move(source.toPath(), target.toPath());</span><br></div></code></pre></div></div>
<p>Before applying changes:</p>
<ol>
<li class="">Build the complete source-to-target mapping.</li>
<li class="">Reject duplicate target paths and existing files.</li>
<li class="">Print or export a preview.</li>
<li class="">Store a reverse mapping for rollback.</li>
<li class="">Apply moves only after validation succeeds.</li>
</ol>
<p>Also decide explicitly whether symbolic links, hidden files, directories, and recursive traversal are allowed.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="file-renaming" term="file-renaming"/>
        <category label="tools" term="tools"/>
        <category label="java" term="java"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[npm install Hangs? A Systematic Troubleshooting Guide]]></title>
        <id>https://xxzkid.github.io/en/2025/npm-install-hang/</id>
        <link href="https://xxzkid.github.io/en/2025/npm-install-hang/"/>
        <updated>2025-05-29T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Diagnose npm install hangs using verbose logs, registry and proxy checks, cache verification, lockfile analysis, lifecycle script isolation, and Node.js compatibility.]]></summary>
        <content type="html"><![CDATA[<p>When <code>npm install</code> appears frozen, repeatedly restarting it usually hides the useful evidence. The delay is commonly caused by network access, proxy configuration, dependency resolution, a lifecycle script, native compilation, cache damage, or a Node.js version mismatch.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-capture-detailed-logs">1. Capture detailed logs<a href="https://xxzkid.github.io/en/2025/npm-install-hang/#1-capture-detailed-logs" class="hash-link" aria-label="Direct link to 1. Capture detailed logs" title="Direct link to 1. Capture detailed logs" translate="no">​</a></h2>
<p>Run the install with verbose output:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm install --verbose</span><br></div></code></pre></div></div>
<p>Also record the active toolchain and configuration:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">node --version</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm --version</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm config get registry</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm config list</span><br></div></code></pre></div></div>
<p>A line such as <code>idealTree:userRequests</code> describes the dependency-resolution stage; it is not the root cause by itself. Inspect the requests and messages immediately before and after it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-test-registry-and-dns-access">2. Test registry and DNS access<a href="https://xxzkid.github.io/en/2025/npm-install-hang/#2-test-registry-and-dns-access" class="hash-link" aria-label="Direct link to 2. Test registry and DNS access" title="Direct link to 2. Test registry and DNS access" translate="no">​</a></h2>
<p>Verify that npm can reach the registry:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm ping</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm view lodash version</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">curl -I https://registry.npmjs.org/</span><br></div></code></pre></div></div>
<p>If these commands are slow, check DNS, VPN, firewall, corporate TLS inspection, and proxy settings. Review both npm-specific and environment proxies:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm config get proxy</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm config get https-proxy</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">env | grep -i proxy</span><br></div></code></pre></div></div>
<p>Remove stale npm proxy values when they are no longer required:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm config delete proxy</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm config delete https-proxy</span><br></div></code></pre></div></div>
<p>Do not disable TLS verification as a permanent workaround. Install the correct organization CA certificate instead.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-verify-the-cache">3. Verify the cache<a href="https://xxzkid.github.io/en/2025/npm-install-hang/#3-verify-the-cache" class="hash-link" aria-label="Direct link to 3. Verify the cache" title="Direct link to 3. Verify the cache" translate="no">​</a></h2>
<p>Use npm's built-in verification first:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm cache verify</span><br></div></code></pre></div></div>
<p>Cache deletion should be a targeted experiment, not the default first step. If verification reports corruption and you have ruled out network problems, use:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm cache clean --force</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-separate-dependency-resolution-from-scripts">4. Separate dependency resolution from scripts<a href="https://xxzkid.github.io/en/2025/npm-install-hang/#4-separate-dependency-resolution-from-scripts" class="hash-link" aria-label="Direct link to 4. Separate dependency resolution from scripts" title="Direct link to 4. Separate dependency resolution from scripts" translate="no">​</a></h2>
<p>Packages may run <code>preinstall</code>, <code>install</code>, or <code>postinstall</code> scripts that download binaries or compile native modules. Test without scripts:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm install --ignore-scripts</span><br></div></code></pre></div></div>
<p>If that completes, inspect lifecycle scripts and rerun the relevant one with foreground output:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm install --foreground-scripts --verbose</span><br></div></code></pre></div></div>
<p>Native builds may require Python, a C/C++ toolchain, and platform development headers.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-check-the-lockfile-and-node-version">5. Check the lockfile and Node version<a href="https://xxzkid.github.io/en/2025/npm-install-hang/#5-check-the-lockfile-and-node-version" class="hash-link" aria-label="Direct link to 5. Check the lockfile and Node version" title="Direct link to 5. Check the lockfile and Node version" translate="no">​</a></h2>
<p>For CI and reproducible installs, prefer:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm ci</span><br></div></code></pre></div></div>
<p>It requires <code>package.json</code> and <code>package-lock.json</code> to agree. Do not delete a committed lockfile casually; doing so changes the resolved dependency graph. Confirm the project's supported Node version through <code>.nvmrc</code>, <code>.node-version</code>, the <code>engines</code> field, or project documentation.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-find-the-slow-package">6. Find the slow package<a href="https://xxzkid.github.io/en/2025/npm-install-hang/#6-find-the-slow-package" class="hash-link" aria-label="Direct link to 6. Find the slow package" title="Direct link to 6. Find the slow package" translate="no">​</a></h2>
<p>Useful experiments include:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm install --timing</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm explain package-name</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm ls</span><br></div></code></pre></div></div>
<p>Check the npm debug log path printed by the failed command. Git-based dependencies may be waiting on SSH credentials, inaccessible hosts, or Git LFS. Browser automation packages often download large binaries and can be blocked by proxies.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-reliable-cleanup-sequence">A reliable cleanup sequence<a href="https://xxzkid.github.io/en/2025/npm-install-hang/#a-reliable-cleanup-sequence" class="hash-link" aria-label="Direct link to A reliable cleanup sequence" title="Direct link to A reliable cleanup sequence" translate="no">​</a></h2>
<p>After preserving the original error, a controlled local retry is:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">rm -rf node_modules</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm cache verify</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">npm ci --verbose</span><br></div></code></pre></div></div>
<p>Keep the lockfile unless you intentionally want to update dependencies. In CI, add explicit timeouts and cache keys based on the lockfile so a stalled registry request cannot block a runner indefinitely.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="npm" term="npm"/>
        <category label="javascript" term="javascript"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Build a FreeSWITCH Docker Image]]></title>
        <id>https://xxzkid.github.io/en/2025/freeswitch-docker/</id>
        <link href="https://xxzkid.github.io/en/2025/freeswitch-docker/"/>
        <updated>2025-05-12T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Build a FreeSWITCH container image with selected modules, mounted configuration, SIP and RTP ports, and audio-network troubleshooting.]]></summary>
        <content type="html"><![CDATA[<p>A FreeSWITCH image should be reproducible, minimal, and explicit about compiled modules. Pin the source or package version and separate build dependencies from the runtime image.</p>
<p>Use a multi-stage build: compile FreeSWITCH and required codecs in the builder stage, then copy only runtime libraries, modules, sounds, and binaries into the final image. Run as a non-root user where practical.</p>
<p>Mount configuration, recordings, certificates, and persistent databases deliberately rather than hiding important state inside the container filesystem.</p>
<p>SIP signaling commonly uses ports such as <code>5060</code> and <code>5080</code>, while RTP requires a configured UDP range. Publishing only the SIP port is not enough for two-way audio. Ensure the container, host firewall, cloud security group, NAT, and FreeSWITCH external IP settings agree on the RTP range.</p>
<p>For production, avoid host networking unless justified, protect the event socket and management interfaces, rate-limit unauthenticated traffic, monitor registrations and call quality, and test one-way-audio, codec negotiation, and NAT traversal from external networks.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="freeswitch" term="freeswitch"/>
        <category label="docker" term="docker"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Set Up a Lightweight HTTP Proxy with Tinyproxy]]></title>
        <id>https://xxzkid.github.io/en/2025/http-proxy-with-tinyproxy/</id>
        <link href="https://xxzkid.github.io/en/2025/http-proxy-with-tinyproxy/"/>
        <updated>2025-05-09T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Install Tinyproxy, configure its listening port and access controls, run it in the foreground, and verify proxy traffic with curl.]]></summary>
        <content type="html"><![CDATA[<p>Tinyproxy is a lightweight HTTP proxy suitable for small controlled environments. It is not a VPN and does not automatically encrypt traffic between the client and proxy.</p>
<p>An open proxy can be abused quickly, so restrict source IP addresses, listening interfaces, and firewall rules before exposing the service.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="optional-test-container">Optional test container<a href="https://xxzkid.github.io/en/2025/http-proxy-with-tinyproxy/#optional-test-container" class="hash-link" aria-label="Direct link to Optional test container" title="Direct link to Optional test container" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">docker run -itd --name ubuntu-test -p 8888:8888 ubuntu:22.04</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">docker exec -it ubuntu-test bash</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="install-tinyproxy">Install Tinyproxy<a href="https://xxzkid.github.io/en/2025/http-proxy-with-tinyproxy/#install-tinyproxy" class="hash-link" aria-label="Direct link to Install Tinyproxy" title="Direct link to Install Tinyproxy" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">apt update</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">apt install tinyproxy -y</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="create-a-configuration">Create a configuration<a href="https://xxzkid.github.io/en/2025/http-proxy-with-tinyproxy/#create-a-configuration" class="hash-link" aria-label="Direct link to Create a configuration" title="Direct link to Create a configuration" translate="no">​</a></h2>
<p>Create <code>/tmp/tinyproxy.conf</code>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">Port 8888</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Listen 0.0.0.0</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Timeout 600</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">BindSame yes</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">MaxClients 1024</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">DisableViaHeader Yes</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"># Replace with trusted client networks.</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Allow 192.168.1.0/24</span><br></div></code></pre></div></div>
<p>Do not leave <code>Allow 0.0.0.0/0</code> enabled on a public server.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="start-the-service">Start the service<a href="https://xxzkid.github.io/en/2025/http-proxy-with-tinyproxy/#start-the-service" class="hash-link" aria-label="Direct link to Start the service" title="Direct link to Start the service" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">tinyproxy -d -c /tmp/tinyproxy.conf</span><br></div></code></pre></div></div>
<p>For long-running deployments, use the distribution service unit and store configuration under <code>/etc/tinyproxy/</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="verify-the-proxy">Verify the proxy<a href="https://xxzkid.github.io/en/2025/http-proxy-with-tinyproxy/#verify-the-proxy" class="hash-link" aria-label="Direct link to Verify the proxy" title="Direct link to Verify the proxy" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">export PROXY_IP=203.0.113.10</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">curl --proxy "http://$PROXY_IP:8888" https://httpbin.org/ip</span><br></div></code></pre></div></div>
<p>The response should show the proxy server's public address. If it fails, inspect the Tinyproxy log, firewall, cloud security group, <code>Allow</code> rules, and whether the proxy can resolve DNS and reach the destination.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="proxy" term="proxy"/>
        <category label="tinyproxy" term="tinyproxy"/>
        <category label="http" term="http"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Run Specific Tests with Maven]]></title>
        <id>https://xxzkid.github.io/en/2025/mvn-testcase/</id>
        <link href="https://xxzkid.github.io/en/2025/mvn-testcase/"/>
        <updated>2025-04-17T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Run all tests, one test class, one method, patterns, and selected modules with Maven Surefire options.]]></summary>
        <content type="html"><![CDATA[<p>Maven Surefire accepts the <code>-Dtest</code> property for selecting unit tests.</p>
<p>Run all tests:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">mvn test</span><br></div></code></pre></div></div>
<p>Run one class:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">mvn -Dtest=UserServiceTest test</span><br></div></code></pre></div></div>
<p>Run one method:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">mvn -Dtest=UserServiceTest#shouldCreateUser test</span><br></div></code></pre></div></div>
<p>Run several methods or wildcard patterns:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">mvn -Dtest='UserServiceTest#shouldCreate*' test</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mvn -Dtest='UserServiceTest,OrderServiceTest' test</span><br></div></code></pre></div></div>
<p>For a multi-module project, select a module and build required dependencies:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">mvn -pl service-module -am -Dtest=UserServiceTest test</span><br></div></code></pre></div></div>
<ul>
<li class=""><code>-pl</code> selects projects from the reactor.</li>
<li class=""><code>-am</code> also builds required upstream modules.</li>
<li class=""><code>-DskipTests</code> compiles tests but skips execution.</li>
<li class=""><code>-Dmaven.test.skip=true</code> skips both test compilation and execution.</li>
</ul>
<p>Integration tests commonly run through Maven Failsafe during <code>integration-test</code> and <code>verify</code>, so use the plugin's include properties and lifecycle rather than assuming <code>mvn test</code> runs them.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="maven" term="maven"/>
        <category label="java" term="java"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Common Flutter Development Problems and Fixes]]></title>
        <id>https://xxzkid.github.io/en/2025/flutter-faq/</id>
        <link href="https://xxzkid.github.io/en/2025/flutter-faq/"/>
        <updated>2025-03-31T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Troubleshoot Flutter SDK setup, dependency downloads, slow Gradle builds, mirror configuration, and project creation.]]></summary>
        <content type="html"><![CDATA[<p>Flutter build problems often involve several layers at once: the Flutter SDK, Dart, Gradle, Android build tools, repositories, and package versions. Record <code>flutter doctor -v</code>, the complete error stack, and reproducible steps before changing caches or mirrors.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="download-flutter">Download Flutter<a href="https://xxzkid.github.io/en/2025/flutter-faq/#download-flutter" class="hash-link" aria-label="Direct link to Download Flutter" title="Direct link to Download Flutter" translate="no">​</a></h2>
<p>A Windows stable archive can be downloaded from the official release storage:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">https://storage.googleapis.com/flutter_infra_release/releases/stable/windows/flutter_windows_3.29.2-stable.zip</span><br></div></code></pre></div></div>
<p>Verify the current stable version before installation.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-package-mirrors">Configure package mirrors<a href="https://xxzkid.github.io/en/2025/flutter-faq/#configure-package-mirrors" class="hash-link" aria-label="Direct link to Configure package mirrors" title="Direct link to Configure package mirrors" translate="no">​</a></h2>
<p>In environments where the default endpoints are slow, configure approved mirrors:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">PUB_HOSTED_URL=https://pub.flutter-io.cn</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="diagnose-a-slow-assembledebug">Diagnose a slow <code>assembleDebug</code><a href="https://xxzkid.github.io/en/2025/flutter-faq/#diagnose-a-slow-assembledebug" class="hash-link" aria-label="Direct link to diagnose-a-slow-assembledebug" title="Direct link to diagnose-a-slow-assembledebug" translate="no">​</a></h2>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">cd android</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">.\gradlew.bat clean</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">.\gradlew.bat assembleDebug --info</span><br></div></code></pre></div></div>
<p>Use the verbose output to identify the dependency or repository causing the delay. Avoid manually copying artifacts into Gradle caches unless you fully understand the expected directory and checksum layout.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-the-gradle-distribution">Configure the Gradle distribution<a href="https://xxzkid.github.io/en/2025/flutter-faq/#configure-the-gradle-distribution" class="hash-link" aria-label="Direct link to Configure the Gradle distribution" title="Direct link to Configure the Gradle distribution" translate="no">​</a></h2>
<p>Edit <code>android/gradle/wrapper/gradle-wrapper.properties</code>:</p>
<div class="language-properties codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-properties codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain"># distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.10.2-all.zip</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-a-maven-mirror">Configure a Maven mirror<a href="https://xxzkid.github.io/en/2025/flutter-faq/#configure-a-maven-mirror" class="hash-link" aria-label="Direct link to Configure a Maven mirror" title="Direct link to Configure a Maven mirror" translate="no">​</a></h2>
<p>For Kotlin DSL projects, edit <code>android/build.gradle.kts</code> or the repository-management block used by the project:</p>
<div class="language-kotlin codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-kotlin codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">maven </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> url </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">uri</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-literal singleline string" style="color:rgb(195, 232, 141)">"https://mirrors.tencent.com/nexus/repository/maven-public/"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="create-a-project">Create a project<a href="https://xxzkid.github.io/en/2025/flutter-faq/#create-a-project" class="hash-link" aria-label="Direct link to Create a project" title="Direct link to Create a project" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">flutter create my_app</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">cd my_app</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">flutter run</span><br></div></code></pre></div></div>
<p>Keep Flutter, Android Gradle Plugin, Gradle, Kotlin, and Java versions compatible rather than upgrading them independently.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="flutter" term="flutter"/>
        <category label="android" term="android"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Install ChromeDriver and Match It with Chrome]]></title>
        <id>https://xxzkid.github.io/en/2025/chromedriver-download/</id>
        <link href="https://xxzkid.github.io/en/2025/chromedriver-download/"/>
        <updated>2025-03-15T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Install ChromeDriver, match browser and driver versions, configure PATH, use Selenium Manager, and troubleshoot Chrome startup failures.]]></summary>
        <content type="html"><![CDATA[<p>ChromeDriver connects Selenium to the Chrome browser. Most startup failures come from an incompatible browser/driver combination, an incorrect executable path, or a missing browser binary.</p>
<p>Record the versions of Chrome, ChromeDriver, Selenium, the operating system, and the CPU architecture when troubleshooting. Current Selenium releases can usually manage the driver automatically, which is preferable to maintaining a driver manually.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="check-the-chrome-version">Check the Chrome version<a href="https://xxzkid.github.io/en/2025/chromedriver-download/#check-the-chrome-version" class="hash-link" aria-label="Direct link to Check the Chrome version" title="Direct link to Check the Chrome version" translate="no">​</a></h2>
<p>Open the following page in Chrome:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">chrome://settings/help</span><br></div></code></pre></div></div>
<p>For older ChromeDriver releases, the browser and driver generally had to share the same major version. For current Chrome for Testing releases, use the official version-selection data instead of relying on an old three-part matching rule.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="download-chromedriver">Download ChromeDriver<a href="https://xxzkid.github.io/en/2025/chromedriver-download/#download-chromedriver" class="hash-link" aria-label="Direct link to Download ChromeDriver" title="Direct link to Download ChromeDriver" translate="no">​</a></h2>
<p>Use the official Chrome for Testing page:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">https://googlechromelabs.github.io/chrome-for-testing/</span><br></div></code></pre></div></div>
<p>Download the package for the correct operating system and architecture, extract it, and either add the executable directory to <code>PATH</code> or pass its path explicitly.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="verify-with-selenium">Verify with Selenium<a href="https://xxzkid.github.io/en/2025/chromedriver-download/#verify-with-selenium" class="hash-link" aria-label="Direct link to Verify with Selenium" title="Direct link to Verify with Selenium" translate="no">​</a></h2>
<p>With a modern Selenium version, Selenium Manager can resolve the driver automatically:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> selenium </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> webdriver</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">options </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> webdriver</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">ChromeOptions</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Set this only when Chrome is installed in a non-standard location.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># options.binary_location = "/path/to/chrome"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">driver </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> webdriver</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Chrome</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">options</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">options</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">try</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    driver</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"https://www.example.com"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    driver</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">maximize_window</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">finally</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    driver</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">quit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></div></code></pre></div></div>
<p>For older Selenium versions, create a <code>Service</code> explicitly instead of using the deprecated <code>executable_path</code> argument:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> selenium </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> webdriver</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> selenium</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">webdriver</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">chrome</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">service </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> Service</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">service </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> Service</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"/path/to/chromedriver"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">driver </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> webdriver</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Chrome</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">service</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">service</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">quit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="common-errors">Common errors<a href="https://xxzkid.github.io/en/2025/chromedriver-download/#common-errors" class="hash-link" aria-label="Direct link to Common errors" title="Direct link to Common errors" translate="no">​</a></h2>
<ul>
<li class=""><strong>Session not created:</strong> compare the installed Chrome major version with the selected driver.</li>
<li class=""><strong>Chrome binary not found:</strong> set <code>options.binary_location</code> to the actual browser executable.</li>
<li class=""><strong>Driver executable not found:</strong> fix <code>PATH</code>, file permissions, or the <code>Service</code> path.</li>
<li class=""><strong>Browser exits immediately:</strong> inspect ChromeDriver logs, sandbox restrictions, display availability, and container shared-memory limits.</li>
</ul>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="chromedriver" term="chromedriver"/>
        <category label="selenium" term="selenium"/>
        <category label="java" term="java"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Install Apache ActiveMQ Artemis]]></title>
        <id>https://xxzkid.github.io/en/2025/apache-artemis-install/</id>
        <link href="https://xxzkid.github.io/en/2025/apache-artemis-install/"/>
        <updated>2025-02-17T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Install and start Apache ActiveMQ Artemis, create a broker instance, configure JVM memory, expose the management console, and verify ports and persistence.]]></summary>
        <content type="html"><![CDATA[<p>Apache ActiveMQ Artemis is the next-generation message broker in the Apache ActiveMQ family.</p>
<p>A successful process start is only the first step. You should also verify the management port, protocol ports, persistence directory, user accounts, JVM settings, disk capacity, permissions, and monitoring.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="prerequisites">Prerequisites<a href="https://xxzkid.github.io/en/2025/apache-artemis-install/#prerequisites" class="hash-link" aria-label="Direct link to Prerequisites" title="Direct link to Prerequisites" translate="no">​</a></h2>
<p>Artemis is a Java application. JDK 17 is a suitable baseline for current releases:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">export JAVA_HOME=/usr/local/jdk17</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">export PATH="$JAVA_HOME/bin:$PATH"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">java -version</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="download-and-extract">Download and extract<a href="https://xxzkid.github.io/en/2025/apache-artemis-install/#download-and-extract" class="hash-link" aria-label="Direct link to Download and extract" title="Direct link to Download and extract" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">wget -O apache-artemis-2.39.0-bin.tar.gz \</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  'https://www.apache.org/dyn/closer.cgi?filename=activemq/activemq-artemis/2.39.0/apache-artemis-2.39.0-bin.tar.gz&amp;action=download'</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">tar -zxvf apache-artemis-2.39.0-bin.tar.gz</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">cd apache-artemis-2.39.0</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="create-a-broker-instance">Create a broker instance<a href="https://xxzkid.github.io/en/2025/apache-artemis-install/#create-a-broker-instance" class="hash-link" aria-label="Direct link to Create a broker instance" title="Direct link to Create a broker instance" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">./bin/artemis create broker</span><br></div></code></pre></div></div>
<p>The setup wizard asks for the default administrator username and password. Use a strong password and do not reuse development credentials in production.</p>
<p>Start the broker from the instance directory:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">cd broker</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">./bin/artemis run</span><br></div></code></pre></div></div>
<p>Run it in the background with the service integration appropriate for your operating system.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="optional-configuration">Optional configuration<a href="https://xxzkid.github.io/en/2025/apache-artemis-install/#optional-configuration" class="hash-link" aria-label="Direct link to Optional configuration" title="Direct link to Optional configuration" translate="no">​</a></h2>
<p>Adjust JVM memory in:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">broker/etc/artemis.profile</span><br></div></code></pre></div></div>
<p>Review the <code>JAVA_ARGS</code> or Java options section rather than changing memory values blindly.</p>
<p>To change Jolokia CORS rules, edit:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">broker/etc/jolokia-access.xml</span><br></div></code></pre></div></div>
<p>For example:</p>
<div class="language-xml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-xml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">allow-origin</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain">*://*</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">allow-origin</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div>
<p>Allowing every origin is convenient for testing but unsafe on an Internet-facing console. Restrict origins in production.</p>
<p>To listen on all network interfaces, edit:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">broker/etc/bootstrap.xml</span><br></div></code></pre></div></div>
<div class="language-xml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-xml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">binding</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">name</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">artemis</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">uri</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">http://0.0.0.0:8161</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div>
<p>Expose port <code>8161</code> only to trusted networks and protect it with authentication and firewall rules.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="activemq" term="activemq"/>
        <category label="java" term="java"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Install MySQL 8 from a Binary Tarball on Linux]]></title>
        <id>https://xxzkid.github.io/en/2024/linux-install-mysql8-zip/</id>
        <link href="https://xxzkid.github.io/en/2024/linux-install-mysql8-zip/"/>
        <updated>2024-09-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Install MySQL 8 from an official Linux binary tarball with a dedicated user, data directory, initialization, my.cnf, systemd service, and security checks.]]></summary>
        <content type="html"><![CDATA[<p>A binary tarball installation gives you full control over the MySQL directory and version. Unlike a distribution package, it does not automatically create the system user, configure permissions, install a service, or apply security updates.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-download-and-verify-the-package">1. Download and verify the package<a href="https://xxzkid.github.io/en/2024/linux-install-mysql8-zip/#1-download-and-verify-the-package" class="hash-link" aria-label="Direct link to 1. Download and verify the package" title="Direct link to 1. Download and verify the package" translate="no">​</a></h2>
<p>Choose the archive that matches your CPU architecture and glibc version from the official MySQL downloads page. The example filename below is illustrative:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.39-linux-glibc2.28-x86_64.tar.xz</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">sha256sum mysql-8.0.39-linux-glibc2.28-x86_64.tar.xz</span><br></div></code></pre></div></div>
<p>Compare the checksum with the value published by MySQL. Install required runtime libraries through your operating system package manager.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-create-a-service-account-and-directories">2. Create a service account and directories<a href="https://xxzkid.github.io/en/2024/linux-install-mysql8-zip/#2-create-a-service-account-and-directories" class="hash-link" aria-label="Direct link to 2. Create a service account and directories" title="Direct link to 2. Create a service account and directories" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">sudo groupadd --system mysql</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">sudo useradd --system --gid mysql --shell /usr/sbin/nologin mysql</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">sudo tar -xf mysql-8.0.39-linux-glibc2.28-x86_64.tar.xz -C /opt</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">sudo ln -s /opt/mysql-8.0.39-linux-glibc2.28-x86_64 /opt/mysql</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">sudo mkdir -p /var/lib/mysql /var/log/mysql /run/mysqld</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">sudo chown -R mysql:mysql /var/lib/mysql /var/log/mysql /run/mysqld</span><br></div></code></pre></div></div>
<p>Keep program files owned by root and writable data directories owned by <code>mysql</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-configure-mysql">3. Configure MySQL<a href="https://xxzkid.github.io/en/2024/linux-install-mysql8-zip/#3-configure-mysql" class="hash-link" aria-label="Direct link to 3. Configure MySQL" title="Direct link to 3. Configure MySQL" translate="no">​</a></h2>
<p>Create <code>/etc/my.cnf</code>:</p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">[mysqld]</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">basedir=/opt/mysql</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">datadir=/var/lib/mysql</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">socket=/run/mysqld/mysqld.sock</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">pid-file=/run/mysqld/mysqld.pid</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">log-error=/var/log/mysql/error.log</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">user=mysql</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">bind-address=127.0.0.1</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">character-set-server=utf8mb4</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">[client]</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">socket=/run/mysqld/mysqld.sock</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">default-character-set=utf8mb4</span><br></div></code></pre></div></div>
<p>Binding to localhost is a safe default. If remote clients are required, use a private interface, firewall rules, TLS, and least-privilege database accounts.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-initialize-the-data-directory">4. Initialize the data directory<a href="https://xxzkid.github.io/en/2024/linux-install-mysql8-zip/#4-initialize-the-data-directory" class="hash-link" aria-label="Direct link to 4. Initialize the data directory" title="Direct link to 4. Initialize the data directory" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">sudo -u mysql /opt/mysql/bin/mysqld   --defaults-file=/etc/my.cnf   --initialize</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">sudo grep 'temporary password' /var/log/mysql/error.log</span><br></div></code></pre></div></div>
<p>Save the temporary password securely. Do not use <code>--initialize-insecure</code> on a production server.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-create-a-systemd-unit">5. Create a systemd unit<a href="https://xxzkid.github.io/en/2024/linux-install-mysql8-zip/#5-create-a-systemd-unit" class="hash-link" aria-label="Direct link to 5. Create a systemd unit" title="Direct link to 5. Create a systemd unit" translate="no">​</a></h2>
<p>Create <code>/etc/systemd/system/mysql.service</code>:</p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">[Unit]</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Description=MySQL Server</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">After=network.target</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">[Service]</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Type=notify</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">User=mysql</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Group=mysql</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">ExecStart=/opt/mysql/bin/mysqld --defaults-file=/etc/my.cnf</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">TimeoutStartSec=90</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Restart=on-failure</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">LimitNOFILE=65535</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">RuntimeDirectory=mysqld</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">RuntimeDirectoryMode=0755</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">[Install]</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">WantedBy=multi-user.target</span><br></div></code></pre></div></div>
<p>Load and start it:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">sudo systemctl daemon-reload</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">sudo systemctl enable --now mysql</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">sudo systemctl status mysql</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-finish-hardening">6. Finish hardening<a href="https://xxzkid.github.io/en/2024/linux-install-mysql8-zip/#6-finish-hardening" class="hash-link" aria-label="Direct link to 6. Finish hardening" title="Direct link to 6. Finish hardening" translate="no">​</a></h2>
<p>Connect with the temporary password and set a strong replacement, then run:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">/opt/mysql/bin/mysql_secure_installation</span><br></div></code></pre></div></div>
<p>Remove anonymous accounts and test databases, review root access, configure backups, and monitor disk capacity and replication if used. Add <code>/opt/mysql/bin</code> to a system-wide PATH only after confirming it cannot be modified by untrusted users.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="upgrades-and-rollback">Upgrades and rollback<a href="https://xxzkid.github.io/en/2024/linux-install-mysql8-zip/#upgrades-and-rollback" class="hash-link" aria-label="Direct link to Upgrades and rollback" title="Direct link to Upgrades and rollback" translate="no">​</a></h2>
<p>Never replace the symlink and start a new MySQL binary without reading that release's upgrade procedure. Take a tested backup, stop cleanly, preserve the old binaries, and rehearse the change on a copy of the data. Package-managed installations are usually easier to patch; use tarballs only when their control is worth the additional maintenance.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="linux" term="linux"/>
        <category label="mysql" term="mysql"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Send Email Through NetEase Enterprise Mail with Spring Boot]]></title>
        <id>https://xxzkid.github.io/en/2024/spring-boot-163qy-mail/</id>
        <link href="https://xxzkid.github.io/en/2024/spring-boot-163qy-mail/"/>
        <updated>2024-08-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Configure Spring Boot SMTP for NetEase enterprise mail with TLS, authorization credentials, timeouts, and authentication troubleshooting.]]></summary>
        <content type="html"><![CDATA[<p>Spring Boot sends SMTP mail through <code>JavaMailSender</code>. Use the exact server, port, encryption mode, and authorization credential supplied by the enterprise mailbox administrator.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token key atrule">spring</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">mail</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">host</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> smtp.qiye.163.com</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">port</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">465</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">username</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> user@example.com</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">password</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">MAIL_PASSWORD</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">protocol</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> smtp</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">properties</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">mail.smtp.auth</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">mail.smtp.ssl.enable</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">mail.smtp.connectiontimeout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">10000</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">mail.smtp.timeout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">10000</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">mail.smtp.writetimeout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">10000</span><br></div></code></pre></div></div>
<p>A basic send operation:</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">SimpleMailMessage message = new SimpleMailMessage();</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">message.setFrom("user@example.com");</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">message.setTo("receiver@example.com");</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">message.setSubject("Test message");</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">message.setText("Mail sent by Spring Boot");</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">mailSender.send(message);</span><br></div></code></pre></div></div>
<p>Some accounts require an app-specific authorization code rather than the login password. Authentication failures can also result from an incorrect sender address, blocked SMTP service, TLS/port mismatch, DNS, firewall rules, or provider rate limits. Keep credentials outside source control.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="java" term="java"/>
        <category label="spring-boot" term="spring-boot"/>
        <category label="spring" term="spring"/>
        <category label="mail" term="mail"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Automate Android Screenshots and Swipes with Python ADB]]></title>
        <id>https://xxzkid.github.io/en/2024/python-adb-short-video/</id>
        <link href="https://xxzkid.github.io/en/2024/python-adb-short-video/"/>
        <updated>2024-07-25T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Control your own Android test device with Python and adbutils to capture screenshots, pull files, perform swipes, and add essential safety checks.]]></summary>
        <content type="html"><![CDATA[<p>This example uses ADB from Python to capture a screenshot from an Android device, copy it to the computer, and perform a swipe gesture.</p>
<p>Use ADB automation only on devices and applications you own or are authorized to test. Respect the target platform's rules, verify that the intended device is connected, and add delays and stop conditions so the loop cannot run out of control.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="install-the-dependency">Install the dependency<a href="https://xxzkid.github.io/en/2024/python-adb-short-video/#install-the-dependency" class="hash-link" aria-label="Direct link to Install the dependency" title="Direct link to Install the dependency" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">pip install adbutils==2.7.2</span><br></div></code></pre></div></div>
<p>Enable USB debugging, authorize the computer, and verify the connection:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">adb devices</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="example">Example<a href="https://xxzkid.github.io/en/2024/python-adb-short-video/#example" class="hash-link" aria-label="Direct link to Example" title="Direct link to Example" translate="no">​</a></h2>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> time</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> datetime </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> datetime</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> adbutils</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">main</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">None</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    devices </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> adbutils</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">adb</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">device_list</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">not</span><span class="token plain"> devices</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">raise</span><span class="token plain"> RuntimeError</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"No authorized Android device is connected"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    device </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> devices</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">try</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">while</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">True</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            filename </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> datetime</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">now</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">strftime</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"%Y%m%d%H%M%S"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">+</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">".png"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            remote_path </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"/sdcard/DCIM/screenshot.png"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            device</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">shell</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"screencap -p </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">remote_path</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> encoding</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token boolean" style="color:rgb(255, 88, 116)">None</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            device</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">sync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">pull_file</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">remote_path</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> filename</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"screenshot: </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">filename</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            device</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">shell</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"input swipe 760 1600 760 800 200"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            time</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">2</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">except</span><span class="token plain"> KeyboardInterrupt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Stopped"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> __name__ </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"__main__"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    main</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></div></code></pre></div></div>
<p>The swipe coordinates depend on the screen resolution and orientation. For a reusable script, query the display size first, calculate coordinates proportionally, check command results, and use a bounded loop instead of <code>while True</code>.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="python" term="python"/>
        <category label="android" term="android"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Secure File Uploads with Spring Boot]]></title>
        <id>https://xxzkid.github.io/en/2024/spring-boot-file-upload/</id>
        <link href="https://xxzkid.github.io/en/2024/spring-boot-file-upload/"/>
        <updated>2024-07-17T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Implement secure Spring Boot file uploads with MultipartFile, size limits, generated filenames, path validation, content checks, safe downloads, storage isolation, and cleanup.]]></summary>
        <content type="html"><![CDATA[<p>File upload endpoints accept attacker-controlled bytes, filenames, sizes, and content types. A secure design limits requests early, generates server-side names, stores files outside the web root, validates paths, and serves downloads with controlled headers.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-request-limits">Configure request limits<a href="https://xxzkid.github.io/en/2024/spring-boot-file-upload/#configure-request-limits" class="hash-link" aria-label="Direct link to Configure request limits" title="Direct link to Configure request limits" translate="no">​</a></h2>
<p>Set limits appropriate for the application:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token key atrule">spring</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">servlet</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">multipart</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">max-file-size</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> 20MB</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">max-request-size</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> 25MB</span><br></div></code></pre></div></div>
<p>Also configure limits at the reverse proxy and load balancer. Proxy and application limits should agree so oversized requests are rejected predictably.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="store-uploads-with-generated-names">Store uploads with generated names<a href="https://xxzkid.github.io/en/2024/spring-boot-file-upload/#store-uploads-with-generated-names" class="hash-link" aria-label="Direct link to Store uploads with generated names" title="Direct link to Store uploads with generated names" translate="no">​</a></h2>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">@Service</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">public class FileStorageService {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    private final Path root = Path.of("/srv/myapp/uploads")</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            .toAbsolutePath()</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            .normalize();</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public FileStorageService() throws IOException {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        Files.createDirectories(root);</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public String store(MultipartFile file) throws IOException {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        if (file.isEmpty()) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            throw new IllegalArgumentException("Empty file");</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        String original = Optional.ofNullable(file.getOriginalFilename())</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                .orElse("upload");</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        String extension = safeExtension(original);</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        String storedName = UUID.randomUUID() + extension;</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        Path destination = root.resolve(storedName).normalize();</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        if (!destination.getParent().equals(root)) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            throw new SecurityException("Invalid destination");</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        try (InputStream input = file.getInputStream()) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            Files.copy(input, destination, StandardCopyOption.COPY_ATTRIBUTES);</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        return storedName;</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    private String safeExtension(String filename) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        String base = Path.of(filename).getFileName().toString();</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        int dot = base.lastIndexOf('.');</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        if (dot &lt; 0) return "";</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        String extension = base.substring(dot).toLowerCase(Locale.ROOT);</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        return Set.of(".jpg", ".png", ".pdf").contains(extension)</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                ? extension</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                : "";</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></div></code></pre></div></div>
<p>Never use the client filename as the storage path. Persist the original display name separately after sanitizing control characters.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="validate-actual-content">Validate actual content<a href="https://xxzkid.github.io/en/2024/spring-boot-file-upload/#validate-actual-content" class="hash-link" aria-label="Direct link to Validate actual content" title="Direct link to Validate actual content" translate="no">​</a></h2>
<p>The multipart <code>Content-Type</code> and extension are user-supplied. For sensitive workflows, inspect file signatures with a maintained library, decode images before accepting them, and scan untrusted documents with malware tooling. Reject archives unless the product explicitly needs them; archive extraction introduces zip-slip paths and decompression bombs.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="serve-files-safely">Serve files safely<a href="https://xxzkid.github.io/en/2024/spring-boot-file-upload/#serve-files-safely" class="hash-link" aria-label="Direct link to Serve files safely" title="Direct link to Serve files safely" translate="no">​</a></h2>
<p>Resolve only server-generated identifiers and verify the normalized result remains under the storage root. For downloads, set a controlled content type and use <code>Content-Disposition: attachment</code> for formats that should not execute in the browser.</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">@GetMapping("/files/{id}")</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">public ResponseEntity&lt;Resource&gt; download(@PathVariable String id) throws IOException {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    if (!id.matches("[0-9a-fA-F-]{36}\\.(jpg|png|pdf)")) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        return ResponseEntity.badRequest().build();</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    Path file = root.resolve(id).normalize();</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    if (!file.getParent().equals(root) || !Files.isRegularFile(file)) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        return ResponseEntity.notFound().build();</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    Resource resource = new FileSystemResource(file);</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    return ResponseEntity.ok()</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            .header(HttpHeaders.CONTENT_DISPOSITION,</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                    "attachment; filename=\"" + id + "\"")</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            .body(resource);</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></div></code></pre></div></div>
<p>Authorization must be checked before returning a resource. Do not rely on an unguessable URL as access control.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="operational-safeguards">Operational safeguards<a href="https://xxzkid.github.io/en/2024/spring-boot-file-upload/#operational-safeguards" class="hash-link" aria-label="Direct link to Operational safeguards" title="Direct link to Operational safeguards" translate="no">​</a></h2>
<ul>
<li class="">Store uploads on a separate volume with no execute permission where practical.</li>
<li class="">Apply per-user quotas and rate limits.</li>
<li class="">Record ownership, checksum, size, and upload time in the database.</li>
<li class="">Clean up abandoned temporary files and failed database transactions.</li>
<li class="">Back up metadata and objects consistently.</li>
<li class="">Use object storage and presigned uploads for large-scale systems.</li>
<li class="">Test filename encoding, concurrent uploads, disk-full behavior, and interrupted requests.</li>
</ul>
<p>A correct upload controller is only one layer. Reverse-proxy limits, storage permissions, authentication, antivirus policy, observability, and retention rules complete the security model.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="spring-boot" term="spring-boot"/>
        <category label="spring" term="spring"/>
        <category label="java" term="java"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Find a SQLite Database Handle in an Authorized Windows Debugging Lab]]></title>
        <id>https://xxzkid.github.io/en/2024/pcwechat-sqlite3-handle/</id>
        <link href="https://xxzkid.github.io/en/2024/pcwechat-sqlite3-handle/"/>
        <updated>2024-05-08T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Trace SQLite calls and inspect registers to identify a database connection handle in an authorized Windows test process.]]></summary>
        <content type="html"><![CDATA[<p>A SQLite connection handle is an opaque <code>sqlite3*</code> pointer passed to many SQLite APIs. This article describes how to recognize it while debugging a controlled application that you own or are authorized to test.</p>
<p>Begin with a known call such as <code>sqlite3_open</code>, <code>sqlite3_prepare_v2</code>, or <code>sqlite3_exec</code>. Set a breakpoint at the verified function or wrapper and observe the calling convention for the target architecture. On 32-bit builds, arguments are commonly stack-based; on 64-bit Windows, the first arguments normally arrive in registers.</p>
<p>Follow the handle from the open call's output into later query calls. Validate it through repeated use and expected SQLite return codes rather than assuming any pointer to database-like memory is correct.</p>
<p>ASLR changes absolute addresses, so record module-relative offsets and the exact binary hash. Application and SQLite updates can change wrappers, signatures, and data flow.</p>
<p>Do not dereference arbitrary pointers or modify live database state. Use synthetic records, copies of test databases, and an isolated environment. Avoid logging credentials, keys, or real message content.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="c-cpp" term="c-cpp"/>
        <category label="windows" term="windows"/>
        <category label="sqlite" term="sqlite"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Locate sqlite3_exec in a Windows Application with IDA]]></title>
        <id>https://xxzkid.github.io/en/2024/ida-sqlite3-exec/</id>
        <link href="https://xxzkid.github.io/en/2024/ida-sqlite3-exec/"/>
        <updated>2024-04-30T08:00:00.000Z</updated>
        <summary type="html"><![CDATA[Use IDA string references, call graphs, signatures, module bases, and offsets to locate sqlite3_exec in an authorized Windows analysis target.]]></summary>
        <content type="html"><![CDATA[<p>This article outlines a static-analysis method for locating a SQLite function inside a Windows application. Apply it only to software you own or are explicitly authorized to inspect.</p>
<p>Start with a known SQLite build and identify stable strings, imported symbols, error messages, or nearby wrapper functions associated with <code>sqlite3_exec</code>. Search those strings in IDA and follow cross-references to candidate call sites.</p>
<p>Compare control flow, argument count, call relationships, and surrounding SQLite functions rather than trusting one byte pattern. Compiler optimization, link-time optimization, static linking, and SQLite version changes can alter the generated code substantially.</p>
<p>When the target uses ASLR, distinguish the module-relative virtual address from the runtime absolute address:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">runtime address = module base + relative offset</span><br></div></code></pre></div></div>
<p>Validate the candidate in an isolated test build with synthetic data and a debugger. Record the exact application hash, architecture, module version, image base, and offset. Never reuse an offset across versions without revalidation, and avoid collecting or modifying real user data.</p>]]></content>
        <author>
            <name>Apache Wangye</name>
            <uri>https://github.com/jsbxyyx</uri>
        </author>
        <category label="c-cpp" term="c-cpp"/>
        <category label="windows" term="windows"/>
        <category label="sqlite" term="sqlite"/>
    </entry>
</feed>