<?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: Alexandr Litvinov</title>
    <description>The latest articles on DEV Community by Alexandr Litvinov (@alexandr_litvinov).</description>
    <link>https://dev.to/alexandr_litvinov</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%2F3991572%2Faaa276b0-9bf9-4f1b-91fd-8f0bd66279ec.jpg</url>
      <title>DEV Community: Alexandr Litvinov</title>
      <link>https://dev.to/alexandr_litvinov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alexandr_litvinov"/>
    <language>en</language>
    <item>
      <title>A complete tour of Qeli: a self-hosted, post-quantum VPN in Rust</title>
      <dc:creator>Alexandr Litvinov</dc:creator>
      <pubDate>Thu, 18 Jun 2026 22:29:05 +0000</pubDate>
      <link>https://dev.to/alexandr_litvinov/a-complete-tour-of-qeli-a-self-hosted-post-quantum-vpn-in-rust-2681</link>
      <guid>https://dev.to/alexandr_litvinov/a-complete-tour-of-qeli-a-self-hosted-post-quantum-vpn-in-rust-2681</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/litvinovtd/qeli" rel="noopener noreferrer"&gt;Qeli&lt;/a&gt; is an open-source VPN you run on your own server. No third-party service, no account with someone else, no telemetry - the server is yours, the keys are yours, and the software itself sends nothing to me or anyone else. The core and server are written in Rust. This is a full tour: what it is, how it is built, how to stand one up, and where it honestly stands today.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model: your server, your keys
&lt;/h2&gt;

&lt;p&gt;Commercial VPNs route your traffic through infrastructure you do not control. Qeli is the opposite: you deploy the server on a box you own or rent, and your devices connect only to it. There is no middleman who could log, sell, or hand over your traffic. If you already rent a VPS, you can have your own private VPN on it.&lt;/p&gt;

&lt;p&gt;It is a &lt;strong&gt;full VPN&lt;/strong&gt;, not a proxy: the client brings up a TUN interface and routes the whole device through an encrypted channel to your server - not just one app or one browser tab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;One Rust binary is three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;the server&lt;/strong&gt; - terminates client tunnels, routes traffic, enforces per-user limits;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;the CLI&lt;/strong&gt; - &lt;code&gt;qeli server&lt;/code&gt;, &lt;code&gt;qeli add-client&lt;/code&gt;, &lt;code&gt;qeli list-clients&lt;/code&gt;, &lt;code&gt;qeli set-bandwidth&lt;/code&gt;, &lt;code&gt;qeli kick&lt;/code&gt;, and more;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;an admin web panel&lt;/strong&gt; - manage users, bandwidth and identity from a browser, served over its own built-in TLS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clients are native on every major platform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Linux&lt;/strong&gt; - Rust&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows&lt;/strong&gt; - C# / .NET&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;macOS&lt;/strong&gt; - C# / Avalonia&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Android&lt;/strong&gt; - Kotlin&lt;/li&gt;
&lt;li&gt;iOS and a Keenetic router build are in progress.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cryptography
&lt;/h2&gt;

&lt;p&gt;This is where Qeli does something most self-host VPNs do not yet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Post-quantum by default.&lt;/strong&gt; The inner handshake is a &lt;em&gt;hybrid&lt;/em&gt; X25519 + ML-KEM-768 (FIPS 203) key exchange. A classical and a post-quantum secret are both mixed into the KDF, so a recorded session stays safe unless &lt;em&gt;both&lt;/em&gt; are broken - protection against "harvest now, decrypt later". I wrote a separate &lt;a href="https://dev.to$deep"&gt;deep dive on the handshake&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data plane:&lt;/strong&gt; ChaCha20-Poly1305.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key derivation:&lt;/strong&gt; HKDF-SHA256. &lt;strong&gt;Password-derived secrets:&lt;/strong&gt; Argon2id.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The post-quantum core lives in Rust and is shared with the C# and Kotlin clients over FFI/JNI, so every platform speaks the same wire format.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transports
&lt;/h2&gt;

&lt;p&gt;Qeli has its own L4 protocol with several interchangeable transports - &lt;code&gt;plain&lt;/code&gt;, &lt;code&gt;fake-tls&lt;/code&gt;, &lt;code&gt;obfs&lt;/code&gt;, &lt;code&gt;reality&lt;/code&gt;, &lt;code&gt;reality-tls&lt;/code&gt;, &lt;code&gt;quic&lt;/code&gt; - so you can pick what suits your server and network. The flagship, &lt;code&gt;reality-tls&lt;/code&gt;, terminates a genuine TLS 1.3 session: the tunnel runs inside a real, modern HTTPS channel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operations
&lt;/h2&gt;

&lt;p&gt;Management is built in, not bolted on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;per-user accounts and accounting&lt;/li&gt;
&lt;li&gt;per-user bandwidth limits&lt;/li&gt;
&lt;li&gt;a kill switch on the clients&lt;/li&gt;
&lt;li&gt;per-user device tracking&lt;/li&gt;
&lt;li&gt;human-readable &lt;code&gt;qeli://&lt;/code&gt; config links (and QR) to onboard a client in seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Standing one up
&lt;/h2&gt;

&lt;p&gt;On a Debian/Ubuntu server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; ./qeli_0.7.1_amd64.deb
&lt;span class="nb"&gt;sudo cp&lt;/span&gt; /etc/qeli/server.conf.example /etc/qeli/server.conf   &lt;span class="c"&gt;# edit it&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; qeli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add a client and hand it the generated &lt;code&gt;qeli://&lt;/code&gt; link (or QR):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qeli add-client alice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Point the desktop or mobile client at that link and you are connected. Prebuilt binaries for Linux, Windows, macOS and Android are on the &lt;a href="https://github.com/litvinovtd/qeli/releases" rel="noopener noreferrer"&gt;releases page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it compares
&lt;/h2&gt;

&lt;p&gt;WireGuard is excellent and I still use it - but it is a single fixed transport, has no post-quantum story yet, and ships no user management. OpenVPN is flexible but heavy and dated. Qeli trades some of WireGuard's minimalism for &lt;strong&gt;batteries-included self-hosting&lt;/strong&gt;: several transports, a web panel, per-user controls, and post-quantum from day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest status
&lt;/h2&gt;

&lt;p&gt;Qeli is &lt;strong&gt;0.7.1 - beta&lt;/strong&gt;. The 1.0 line will be the first I would call stable, after more testing and user feedback. There are nearly 200 unit tests and I have triaged two external code audits, but it has &lt;strong&gt;not&lt;/strong&gt; had a professional cryptographic audit, so do not put anything life-critical on it yet. The handshake and transport code is exactly where I would most value outside scrutiny.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code&lt;/strong&gt; (AGPL-3.0 core, MPL-2.0 clients): &lt;a href="https://github.com/litvinovtd/qeli" rel="noopener noreferrer"&gt;https://github.com/litvinovtd/qeli&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Site:&lt;/strong&gt; &lt;a href="https://qeli.ru" rel="noopener noreferrer"&gt;https://qeli.ru&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Releases and builds:&lt;/strong&gt; &lt;a href="https://github.com/litvinovtd/qeli/releases" rel="noopener noreferrer"&gt;https://github.com/litvinovtd/qeli/releases&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community (Telegram):&lt;/strong&gt; &lt;a href="https://t.me/qeli_vpn" rel="noopener noreferrer"&gt;https://t.me/qeli_vpn&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you self-host, give it a spin and tell me where it breaks - issues and feedback are very welcome.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>vpn</category>
      <category>selfhosted</category>
      <category>security</category>
    </item>
    <item>
      <title>Adding a post-quantum hybrid handshake to a Rust VPN</title>
      <dc:creator>Alexandr Litvinov</dc:creator>
      <pubDate>Thu, 18 Jun 2026 22:13:48 +0000</pubDate>
      <link>https://dev.to/alexandr_litvinov/adding-a-post-quantum-hybrid-handshake-to-a-rust-vpn-pk8</link>
      <guid>https://dev.to/alexandr_litvinov/adding-a-post-quantum-hybrid-handshake-to-a-rust-vpn-pk8</guid>
      <description>&lt;p&gt;I maintain &lt;a href="https://github.com/litvinovtd/qeli" rel="noopener noreferrer"&gt;Qeli&lt;/a&gt;, a self-hosted VPN whose core and server are written in Rust. For the 0.7.x line I added a &lt;strong&gt;hybrid post-quantum key exchange&lt;/strong&gt; to the inner handshake, and wired the same primitive into the non-Rust clients. Here is how it is built and what bit me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why hybrid, not pure PQ
&lt;/h2&gt;

&lt;p&gt;The threat is "harvest now, decrypt later": traffic captured today, decrypted once a large quantum computer exists. Classical X25519 does not survive that; pure ML-KEM is young, and I do not want one new primitive to be the only thing between you and plaintext. So the handshake runs &lt;strong&gt;both&lt;/strong&gt; and mixes the results - you are safe unless &lt;em&gt;both&lt;/em&gt; X25519 and ML-KEM-768 fall.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape of the handshake
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Classical:&lt;/strong&gt; X25519 ephemeral ECDH.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post-quantum:&lt;/strong&gt; ML-KEM-768 (FIPS 203), via the RustCrypto stack - one side encapsulates to the other's ephemeral KEM public key.&lt;/li&gt;
&lt;li&gt;The two shared secrets are concatenated and run through &lt;strong&gt;HKDF-SHA256&lt;/strong&gt; to derive the session keys. The data plane is &lt;strong&gt;ChaCha20-Poly1305&lt;/strong&gt;; password-derived secrets use &lt;strong&gt;Argon2id&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mixing both secrets in the KDF (instead of picking one) is what makes it hybrid: an attacker has to break &lt;em&gt;both&lt;/em&gt; to recover the key.&lt;/p&gt;

&lt;h2&gt;
  
  
  One PQ core across Rust, C# and Kotlin
&lt;/h2&gt;

&lt;p&gt;Qeli has native clients on Windows/macOS (C#) and Android (Kotlin). Rather than reimplement ML-KEM three times, the Rust implementation is the single source of truth, and the other clients call into a small native core over &lt;strong&gt;FFI&lt;/strong&gt; (C#) and &lt;strong&gt;JNI&lt;/strong&gt; (Android). Same wire format everywhere, and the PQ code gets reviewed once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things that bit me
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Wire compatibility.&lt;/strong&gt; Turning on PQ changed the handshake bytes. I kept it wire-compatible &lt;em&gt;within&lt;/em&gt; 0.7.x, but it is a breaking change versus older clients - versioning the handshake from day one would have saved pain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Message sizes.&lt;/strong&gt; ML-KEM-768 public keys and ciphertexts are ~1.1 KB, far larger than X25519's 32 bytes. Worth accounting for in your framing and MTU assumptions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the classical path.&lt;/strong&gt; It is tempting to drop X25519 once PQ works, but hybrid is the whole point - the KDF step has to bind both.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Code is open (AGPL-3.0 core, MPL-2.0 clients): &lt;a href="https://github.com/litvinovtd/qeli" rel="noopener noreferrer"&gt;https://github.com/litvinovtd/qeli&lt;/a&gt; - and there is a project site at &lt;a href="https://qeli.ru" rel="noopener noreferrer"&gt;https://qeli.ru&lt;/a&gt;. Feedback on the handshake and transport code is very welcome.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>cryptography</category>
      <category>security</category>
      <category>privacy</category>
    </item>
  </channel>
</rss>
