<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andrew</title>
    <description>The latest articles on DEV Community by Andrew (@devandrew).</description>
    <link>https://dev.to/devandrew</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3988223%2F2c9a6de7-f82c-4e1a-b675-44305f64a52e.png</url>
      <title>DEV Community: Andrew</title>
      <link>https://dev.to/devandrew</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devandrew"/>
    <language>en</language>
    <item>
      <title>Stop Routing to IPs: How Iroh 1.0 Uses Cryptographic Keys for P2P Networking</title>
      <dc:creator>Andrew</dc:creator>
      <pubDate>Mon, 22 Jun 2026 12:24:33 +0000</pubDate>
      <link>https://dev.to/devandrew/stop-routing-to-ips-how-iroh-10-uses-cryptographic-keys-for-p2p-networking-879</link>
      <guid>https://dev.to/devandrew/stop-routing-to-ips-how-iroh-10-uses-cryptographic-keys-for-p2p-networking-879</guid>
      <description>&lt;h2&gt;
  
  
  The Problem with IP-Based Networking
&lt;/h2&gt;

&lt;p&gt;IP addresses make for inherently fragile identifiers. They change whenever a device switches from Wi-Fi to cellular, reboots, or updates its DHCP lease. In modern network environments, where devices are frequently trapped behind multiple layers of NAT or CGNAT, these shifts break existing connections. Historically, developers have relied on complex or centralized solutions like STUN, TURN, or stateful VPN overlays to manage connectivity, all of which introduce latency or maintenance overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Iroh 1.0: Identity Through Keys
&lt;/h2&gt;

&lt;p&gt;Released in June 2026, Iroh 1.0 shifts the focus from IP addresses to cryptographic public keys. By treating the public key as the stable identifier for a node, Iroh allows the network layer to handle the routing details. This ensures that even if the underlying IP changes, the connection remains authenticated and persistent.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Iroh Stacks Up
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Connection Lifecycle:&lt;/strong&gt; Iroh attempts a direct QUIC-based UDP hole punch first, which succeeds in roughly 90% of cases. When direct connectivity fails—often due to symmetric NAT—it falls back to a stateless relay.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Efficient Infrastructure:&lt;/strong&gt; By leveraging QUIC with TLS 1.3, Iroh ensures end-to-end encryption. Because the relay servers are stateless and merely forward encrypted packets, they are significantly cheaper and easier to scale than stateful WebRTC TURN servers.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Standardization:&lt;/strong&gt; Iroh adopts QUIC-NAT-Traversal (QNT), an IETF standard that integrates hole punching directly into the QUIC stack. This allows for better congestion control and cleaner connection handoffs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Using Iroh is straightforward across multiple languages. Here is a minimal implementation in Rust using the &lt;code&gt;iroh&lt;/code&gt; crate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;iroh&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Accepting side&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;N0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;.accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ECHO_ALPN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EchoHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.spawn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="nf"&gt;.online&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="nf"&gt;.node_addr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Connecting side&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;N0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="nf"&gt;.connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ECHO_ALPN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="nf"&gt;.open_bi&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="nf"&gt;.write_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;b"hello iroh"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="nf"&gt;.finish&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Trade-offs and Use Cases
&lt;/h2&gt;

&lt;p&gt;Unlike WebRTC or libp2p, Iroh prioritizes practical connectivity over extreme decentralization. It avoids the bloat of ICE/SDP and the complexity of Kademlia DHTs. While Iroh is excellent for direct peer-to-peer data, it is not a web server. If your application requires handling webhooks or providing a standard HTTPS interface for external clients, you will still need a public entry point.&lt;/p&gt;

&lt;p&gt;For local development or demoing web-facing components of your P2P app, you can use &lt;code&gt;ssh&lt;/code&gt; to expose a local port:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-p&lt;/span&gt; 443 &lt;span class="nt"&gt;-R0&lt;/span&gt;:localhost:8080 free.pinggy.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;By splitting your architecture-Iroh for the P2P data plane and a tunnel for the public HTTP ingress, you get the best of both worlds: decentralization where performance matters and web standard compatibility where accessibility matters.&lt;/p&gt;
&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://pinggy.io/blog/iroh_1_0_dial_keys_not_ips/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpinggy.io%2Fimages%2Firoh_1_0_dial_keys_not_ips%2Fbanner.webp" height="450" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://pinggy.io/blog/iroh_1_0_dial_keys_not_ips/" rel="noopener noreferrer" class="c-link"&gt;
            Iroh 1.0: Dial Keys, Not IPs

          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Iroh 1.0 ships a stable P2P networking library that connects devices by cryptographic key instead of IP address. QUIC under the hood, 90% hole-punch success, 200M+ endpoints/month, and now stable language bindings for Python, Node.js, Swift, and Kotlin.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpinggy.io%2Fassets%2Ffavicon2.ico" width="75" height="75"&gt;
          pinggy.io
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;a href="https://github.com/n0-computer/iroh" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://github.com/n0-computer/iroh" rel="noopener noreferrer"&gt;https://github.com/n0-computer/iroh&lt;/a&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>p2p</category>
      <category>rust</category>
      <category>quic</category>
      <category>networking</category>
    </item>
    <item>
      <title>Self-Hosting High-Fidelity TTS: Deploying VoxCPM2 with a Public Pinggy Tunnel</title>
      <dc:creator>Andrew</dc:creator>
      <pubDate>Fri, 19 Jun 2026 08:32:21 +0000</pubDate>
      <link>https://dev.to/devandrew/self-hosting-high-fidelity-tts-deploying-voxcpm2-with-a-public-pinggy-tunnel-gm</link>
      <guid>https://dev.to/devandrew/self-hosting-high-fidelity-tts-deploying-voxcpm2-with-a-public-pinggy-tunnel-gm</guid>
      <description>&lt;p&gt;If you are tired of paying per-character fees for TTS services, you can now run OpenBMB’s VoxCPM2 locally. This 2-billion-parameter model drops traditional audio tokenization, opting instead for a diffusion autoregressive architecture that produces 48 kHz, studio-quality audio. It supports 30 languages and offers advanced features like zero-shot voice design.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmzv37dmmoksjk6h77d8f.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmzv37dmmoksjk6h77d8f.webp" alt="Blog Image" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Technical Advantage
&lt;/h3&gt;

&lt;p&gt;Unlike two-stage models like F5-TTS or Kokoro that encode text into discrete audio tokens before decoding, VoxCPM2 stays within the latent space of a learned audio VAE. This approach preserves nuances like breath patterns and mid-sentence emotional shifts that are usually lost during quantization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;To run this efficiently, ensure your environment meets these requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.10 or 3.11&lt;/li&gt;
&lt;li&gt;CUDA 12.0+&lt;/li&gt;
&lt;li&gt;PyTorch 2.5.0+&lt;/li&gt;
&lt;li&gt;8 GB VRAM (bfloat16 precision)&lt;/li&gt;
&lt;li&gt;FFmpeg installed on your path&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Setup and Inference
&lt;/h3&gt;

&lt;p&gt;Start by creating a virtual environment, then install the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv voxcpm-env
&lt;span class="nb"&gt;source &lt;/span&gt;voxcpm-env/bin/activate
pip &lt;span class="nb"&gt;install &lt;/span&gt;voxcpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test your installation and pull the model weights, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"from voxcpm import VoxCPM2; m = VoxCPM2(); print('ready')"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Serving via OpenAI-Compatible API
&lt;/h3&gt;

&lt;p&gt;VoxCPM2 supports &lt;code&gt;vLLM-Omni&lt;/code&gt;, which exposes a &lt;code&gt;/v1/audio/speech&lt;/code&gt; endpoint. This allows you to swap your existing OpenAI SDK base URL to point at your local GPU:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"vllm==0.19.0"&lt;/span&gt; vllm-omni
vllm serve openbmb/VoxCPM2 &lt;span class="nt"&gt;--omni&lt;/span&gt; &lt;span class="nt"&gt;--port&lt;/span&gt; 8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exposing via Pinggy
&lt;/h3&gt;

&lt;p&gt;Since your local port 8000 isn't public, use Pinggy to create a secure tunnel without complex firewall configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-p&lt;/span&gt; 443 &lt;span class="nt"&gt;-R0&lt;/span&gt;:localhost:8000 free.pinggy.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command returns a public HTTPS URL. You can even secure this endpoint with basic auth if you are sharing it with a small team:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-p&lt;/span&gt; 443 &lt;span class="nt"&gt;-R0&lt;/span&gt;:localhost:8000 a.pinggy.io &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="s2"&gt;"b:myuser:mypassword"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Integration
&lt;/h3&gt;

&lt;p&gt;Once the tunnel is active, call your local instance from any environment just as you would with a cloud provider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://your-pinggy-url/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;not-needed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;speech&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openbmb/VoxCPM2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;voice&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Local GPU deployment is live!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stream_to_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output.mp3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pinggy.io/blog/run_voxcpm2_locally_expose_api_with_pinggy/" rel="noopener noreferrer"&gt;Self-Host Free Voice AI with VoxCPM2 and Pinggy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>voiceai</category>
      <category>python</category>
      <category>vllm</category>
      <category>selfhosting</category>
    </item>
    <item>
      <title>NPM v12 Is Changing Everything: How to Secure Your Install Pipeline Now</title>
      <dc:creator>Andrew</dc:creator>
      <pubDate>Wed, 17 Jun 2026 04:23:21 +0000</pubDate>
      <link>https://dev.to/devandrew/npm-v12-is-changing-everything-how-to-secure-your-install-pipeline-now-lca</link>
      <guid>https://dev.to/devandrew/npm-v12-is-changing-everything-how-to-secure-your-install-pipeline-now-lca</guid>
      <description>&lt;h3&gt;
  
  
  The Shift in Supply Chain Security
&lt;/h3&gt;

&lt;p&gt;On June 3, 2026, a sophisticated supply chain attack known as "Phantom Gyp" compromised 57 npm packages in under two hours. The exploit was simple but deadly: it bypassed standard malware scanners by hiding malicious payloads within &lt;code&gt;binding.gyp&lt;/code&gt; files—a mechanism used for compiling native addons. Because these files trigger &lt;code&gt;node-gyp&lt;/code&gt; during installation, the code executed automatically without ever being flagged as a traditional &lt;code&gt;preinstall&lt;/code&gt; or &lt;code&gt;postinstall&lt;/code&gt; script.&lt;/p&gt;

&lt;p&gt;In response, GitHub announced a massive overhaul coming in &lt;strong&gt;npm v12&lt;/strong&gt; (expected July 2026). The era of blind trust for dependencies is ending. Here is how you can prepare.&lt;/p&gt;

&lt;h3&gt;
  
  
  What npm v12 Changes for You
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Lifecycle Scripts Become Opt-In:&lt;/strong&gt; &lt;code&gt;preinstall&lt;/code&gt;, &lt;code&gt;install&lt;/code&gt;, and &lt;code&gt;postinstall&lt;/code&gt; scripts from your &lt;code&gt;node_modules&lt;/code&gt; will be blocked by default. You must explicitly approve them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git &amp;amp; Remote URL Restrictions:&lt;/strong&gt; Dependencies loaded via Git or raw tarball URLs now require specific opt-in flags (&lt;code&gt;--allow-git&lt;/code&gt; or &lt;code&gt;--allow-remote&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native Addon Control:&lt;/strong&gt; Any package using &lt;code&gt;binding.gyp&lt;/code&gt; will now be treated like a script, meaning implicit native builds are no longer automatic.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Audit Your Dependencies Today
&lt;/h3&gt;

&lt;p&gt;Don't wait until July to discover your build is broken. You can test your project against v12 rules right now using npm 11.16.0+.&lt;/p&gt;

&lt;p&gt;First, upgrade your npm version:&lt;br&gt;
&lt;code&gt;npm install -g npm@latest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Perform a dry-run audit to see which packages currently execute scripts:&lt;br&gt;
&lt;code&gt;npm approve-scripts --allow-scripts-pending&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Migration Workflow
&lt;/h3&gt;

&lt;p&gt;To keep your pipeline running smoothly, you need to manage an &lt;code&gt;allowScripts&lt;/code&gt; block in your &lt;code&gt;package.json&lt;/code&gt;. You can approve your current dependency tree with a single command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm approve-scripts --all&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro-tip for CI/CD:&lt;/strong&gt; While you might be permissive on your local machine, enforce strict security in CI. Use the &lt;code&gt;--strict-allow-scripts&lt;/code&gt; flag in your production pipelines. This forces the build to fail if an unapproved dependency attempts to execute a script, providing an immediate circuit breaker against potential supply chain attacks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing Integrations
&lt;/h3&gt;

&lt;p&gt;If your app relies on webhooks, you don't need a formal staging environment to verify them after your migration. You can expose your local environment to the public internet securely using Pinggy:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ssh -p 443 -R0:localhost:3000 free.pinggy.io&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This provides a temporary HTTPS URL for testing webhooks from providers like Stripe or GitHub directly against your local code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read more about this from &lt;a href="https://pinggy.io/blog/npm_v12_install_scripts_disabled/" rel="noopener noreferrer"&gt;Blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>npm</category>
      <category>node</category>
      <category>cybersecurity</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
