Fransys

Tech blog — Architecture, Cloud & DevOps

BlogServicesContactAbout

Follow me

githubGitHublinkedinLinkedinmailMail

© 2026 Fransys • Fransys

Fransys

Categories

  • All posts
  • Tags
  • productivity10
  • nas10
  • ai8
  • security7
  • self-hosting7
  • linux6
  • claude-code6
  • neovim5
  • docker5
  • editor4
  • networking4
  • mcp3
  • vpn3
  • lua2
  • terminal2
naslinuxsecurityssh

Securing SSH with post-quantum algorithms

Published on
January 13, 2026·4 min read
Avatar François GUERLEZFrançois GUERLEZ

Why post-quantum, and why now?

The typical argument: "quantum computers are years away, who cares?" Fair point, maybe. But there's a real threat happening right now: harvest now, decrypt later. Someone captures your encrypted traffic today, archives it, and waits 20 years for quantum computers to exist so they can decrypt it retroactively.

For a personal NAS? The risk is manageable. But if you're building something more serious, might as well develop good habits early. OpenSSH has supported post-quantum algorithms since version 9.x, and Debian 13 ships a recent enough build to use them.

Host keys: cleanup time

First order of business: dump the weak keys. By default, Debian generates ECDSA, Ed25519, and RSA. We're removing ECDSA and DSA (obsolete garbage), keeping only Ed25519 and RSA 4096-bit:

# Remove unwanted host keys
rm -f /etc/ssh/ssh_host_ecdsa_key*
rm -f /etc/ssh/ssh_host_dsa_key*

# Regenerate RSA key at 4096 bits if needed
ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N ""

Then in sshd_config, be explicit:

# /etc/ssh/sshd_config - Host keys
 HostKey /etc/ssh/ssh_host_ed25519_key
 HostKey /etc/ssh/ssh_host_rsa_key
 HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256

Ed25519 up front: small, fast, built on Curve25519 which is solid. RSA 4096 as a fallback for ancient clients.

Post-quantum key exchange

Now it gets interesting. OpenSSH now supports hybrid algorithms that combine a classical exchange (X25519) with a post-quantum one. If the post-quantum algorithm turns out to suck, classical security still holds. And vice versa. It's security hedging.

# /etc/ssh/sshd_config - Key exchange
KexAlgorithms mlkem768x25519-sha256,sntrup761x25519-sha512@openssh.com,curve25519-sha256,diffie-hellman-group16-sha512

Let's break this down:

  • mlkem768x25519-sha256: hybrid ML-KEM 768 (the NIST FIPS 203 standard, formerly CRYSTALS-Kyber) + X25519. Most recent, most recommended.
  • sntrup761x25519-sha512@openssh.com: hybrid NTRU Prime 761 + X25519. In OpenSSH longer, excellent fallback.
  • curve25519-sha256: classical exchange, for clients that don't speak post-quantum yet.
  • diffie-hellman-group16-sha512: classical DH as a last resort.

Ciphers and MACs

For symmetric encryption and authentication codes, stick with proven stuff:

# /etc/ssh/sshd_config - Ciphers
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com

ChaCha20-Poly1305 by default - performant, well-studied. AES-GCM variants for machines with AES-NI acceleration (the Intel N95 supports this). Solid choices.

Hardened authentication

Passwords? Nope. SSH keys only:

# /etc/ssh/sshd_config - Authentication
 PermitRootLogin no
 PasswordAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
MaxAuthTries 3
MaxSessions 5
LoginGraceTime 30

Critical points:

  • PermitRootLogin no: connect as nasadmin, then sudo if needed
  • MaxAuthTries 3: limits brute-force attempts (bots get discouraged quick)
  • LoginGraceTime 30: 30 seconds to auth, no more. Slows down automated attacks.

Access warning banner

Often overlooked, but legally important in many jurisdictions. This banner is sometimes required to prosecute unauthorized access:

# /etc/ssh/sshd_config
Banner /etc/ssh/banner.txt
# /etc/ssh/banner.txt
*************************************************************
WARNING: Unauthorized access to this system is prohibited.
All connections are monitored and recorded.
By connecting, you agree to comply with applicable policies.
*************************************************************

Not just window dressing. Actually matters if compliance is part of your world.

Automation with Ansible

All of this gets deployed via an Ansible role, integrated with the devsec.hardening collection. Applies hundreds of hardening rules based on CIS and NIST benchmarks.

The playbook looks like:

# playbook.yml - excerpt
- name: Harden SSH
  hosts: nas
  roles:
    - role: devsec.hardening.ssh_hardening
      vars:
        ssh_kex:
          - mlkem768x25519-sha256
          - sntrup761x25519-sha512@openssh.com
          - curve25519-sha256
          - diffie-hellman-group16-sha512
        ssh_host_key_algorithms:
          - ssh-ed25519
          - rsa-sha2-512
          - rsa-sha2-256
        ssh_ciphers:
          - chacha20-poly1305@openssh.com
          - aes256-gcm@openssh.com
          - aes128-gcm@openssh.com
        ssh_allow_users: nasadmin
        ssh_max_auth_retries: 3

Ansible's magic: it's idempotent. Run it 50 times, nothing breaks. That's exactly what we want.

Client side: your key

To connect to the NAS, you need an Ed25519 key:

# Generate an Ed25519 key
ssh-keygen -t ed25519 -C "user@workstation"

# Check what your client supports
ssh -Q kex

The ssh -Q kex command shows your client's capabilities. If mlkem768x25519-sha256 appears, you're golden.

Verification

After deployment, validate it works:

# Check negotiated algorithms during a connection
ssh -vv nasadmin@192.168.1.50 2>&1 | grep "kex:"

# Expected output:
# debug1: kex: algorithm: mlkem768x25519-sha256

Done.

Setting up SSH with post-quantum algorithms is straightforward. Zero performance penalty. It's a proactive measure that protects today against tomorrow's threats. With OpenSSH 9.x and Debian 13, everything exists out of the box - just configure the right parameters and let Ansible handle the rest.


Debian NAS from scratch series — This article is part of a complete series on building a Debian NAS.

Previous: Hardening your NAS Linux kernel to CIS Level 2 standards | Next: Secure remote access to your NAS with Tailscale

Previous post

← Configuring Neovim from scratch with Lua and Lazy.nvim

Next post

Native LSP in Neovim 0.11: zero plugins, zero compromises→
← Back to blog

Table of Contents

  • Why post-quantum, and why now?
  • Host keys: cleanup time
  • Post-quantum key exchange
  • Ciphers and MACs
  • Hardened authentication
  • Access warning banner
  • Automation with Ansible
  • Client side: your key
  • Verification