
August 15, 2026
11 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
Password-based server access remains one of the most common attack vectors I encounter during security audits for Nepal-based businesses and international clients. Implementing a proper SSH Key Only Auth Setup eliminates brute-force vulnerabilities entirely by replacing guessable credentials with cryptographic proof of identity. This guide walks you through the exact configuration I use on production Ubuntu 22.04 and 24.04 servers running Laravel applications, legal-tech portals, and eCommerce systems.
Why is SSH Key Only Auth Setup essential for production servers?
Every internet-facing server with password authentication enabled will face automated brute-force attacks within hours of deployment. On client projects ranging from Laravel application hosting to legal-tech portals, I consistently see fail2ban logs showing hundreds of daily login attempts against password-enabled SSH services. These aren't targeted attacks — they're opportunistic bots cycling through common usernames and leaked credential databases.
Public key cryptography solves this problem fundamentally. Instead of verifying something you know (a password that can be guessed, phished, or leaked), the server verifies something you possess (a private key that never leaves your machine). Even if an attacker knows your username and has unlimited computational resources, they cannot authenticate without the corresponding private key.
Beyond security, key-based authentication enables practical workflow improvements. Automated deployment tools like Deployer 7 — which I use across multiple client sites sharing GitLab CI pipelines — require non-interactive authentication. You cannot script password entry reliably or securely. Keys also allow granular access control: revoke a single developer's access by removing their public key without changing passwords for everyone else.
How do you generate secure SSH keys for SSH Key Only Auth Setup?
Modern OpenSSH supports ED25519 keys, which provide stronger security than RSA at smaller key sizes and faster operations. Generate keys on your local machine, never on the server itself.
Generate an ED25519 key pair
ssh-keygen -t ed25519 -C "kokil@production-server-2026" -f ~/.ssh/id_ed25519_prod The -C flag adds a comment identifying the key's purpose. The -f flag specifies a custom filename — avoid reusing default key names across different servers or clients. When prompted for a passphrase, always set one. This encrypts the private key at rest, protecting it even if your laptop is compromised.
Verify key generation
ls -la ~/.ssh/id_ed25519_prod*
# Expected output:
# -rw------- 1 user user 411 Aug 16 10:30 id_ed25519_prod
# -rw-r--r-- 1 user user 97 Aug 16 10:30 id_ed25519_prod.pub The private key must have permissions 600 (owner read/write only). The public key can be world-readable since it's designed to be shared. If permissions are wrong, SSH will refuse to use the key.
Legacy system compatibility
If you're connecting to older servers that don't support ED25519 (rare in 2026 but possible on legacy infrastructure), generate RSA-4096 instead:
ssh-keygen -t rsa -b 4096 -o -a 100 -C "legacy-server" -f ~/.ssh/id_rsa_legacy The -o flag uses OpenSSH's newer key format, and -a 100 increases KDF rounds for better passphrase protection. Avoid DSA keys entirely — they're deprecated and limited to 1024 bits.
How do you deploy public keys and configure sshd_config for SSH Key Only Auth Setup?
This is where mistakes cause lockouts. Follow this sequence exactly, and never close your existing SSH session until you've verified key-based authentication works.
Step 1: Copy the public key to the server
While password authentication is still enabled, use ssh-copy-id to append your public key safely:
ssh-copy-id -i ~/.ssh/id_ed25519_prod.pub username@server-ip This command creates ~/.ssh/authorized_keys if missing, sets correct permissions (700 for .ssh, 600 for authorized_keys), and appends rather than overwrites existing keys. Manual copying risks permission errors that silently break authentication.
Step 2: Test key authentication before disabling passwords
Open a new terminal window and connect explicitly using your key:
ssh -i ~/.ssh/id_ed25519_prod -o BatchMode=yes username@server-ip The BatchMode=yes option prevents SSH from prompting for a password. If this connection succeeds without any password prompt, your key is correctly installed. If it fails, diagnose the issue now while password fallback still exists. Check /var/log/auth.log on the server for specific error messages.
Step 3: Harden sshd_config
Edit the SSH daemon configuration on the server:
sudo nano /etc/ssh/sshd_config Set these directives (uncomment and modify existing lines or add new ones):
# Enable public key authentication
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
# Disable all password-based methods
PasswordAuthentication no
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no
UsePAM yes
# Disable root login entirely (use sudo from regular user)
PermitRootLogin no
# Limit authentication attempts
MaxAuthTries 3
LoginGraceTime 30
# Restrict to specific users (optional but recommended)
AllowUsers username deployer
# Use strong ciphers and MACs only
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256
PubkeyAcceptedAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256 Step 4: Validate configuration syntax
Before restarting, verify your changes don't contain syntax errors:
sudo sshd -t No output means success. Any errors must be fixed before proceeding — a malformed config can prevent sshd from starting, locking you out completely.
Step 5: Restart the SSH daemon
sudo systemctl restart sshd On Ubuntu 22.04/24.04, this applies changes immediately without dropping existing connections. Your current session remains active.
Step 6: Final verification
Open yet another new terminal and confirm key-only authentication works:
ssh -i ~/.ssh/id_ed25519_prod -o BatchMode=yes username@server-ip Also verify password authentication is rejected:
ssh -o PubkeyAuthentication=no username@server-ip
# Should fail immediately with "Permission denied" Only after both tests pass should you close your original safety-net session.
What are common SSH Key Only Auth Setup failures and how do you troubleshoot them?
Even experienced engineers encounter issues during implementation. Here are the problems I've diagnosed repeatedly on production servers, ordered by frequency.
| Symptom | Cause | Fix |
|---|---|---|
| Key rejected despite correct installation | Wrong permissions on ~/.ssh or authorized_keys | chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys |
| Authentication falls back to password prompt | Private key not offered or wrong key specified | Use ssh -v -i /path/to/key to debug; check ~/.ssh/config IdentityFile paths |
| "Permission denied (publickey)" after config change | PubkeyAuthentication misspelled or commented out | Run sudo sshd -T | grep pubkeyauthentication to verify effective config |
| Works for one user, fails for another | authorized_keys owned by wrong user or home directory too open | chown user:user ~/.ssh/authorized_keys; ensure home dir isn't world-writable |
| Key accepted locally but rejected remotely | SELinux/AppArmor blocking access or NFS-mounted home with root_squash | Check audit.log; restore SELinux context with restorecon -R ~/.ssh |
| Deployer/GitLab CI fails but manual SSH works | CI runner uses different user/key or StrictHostKeyChecking blocks first connection | Add StrictHostKeyChecking=accept-new to CI SSH options; verify deploy user's authorized_keys |
Verbose logging is your primary diagnostic tool. Connect with maximum verbosity to see exactly where authentication fails:
ssh -vvv -i ~/.ssh/id_ed25519_prod username@server-ip 2>&1 | grep -E "(Offering|Authenticated|debug1: Will attempt)" On the server side, temporarily increase log level in sshd_config:
LogLevel DEBUG Then monitor /var/log/auth.log while attempting connection. Remember to revert to INFO after troubleshooting — DEBUG logging generates significant noise and may expose sensitive data in logs.
Recovery when locked out
If you disable password authentication before verifying key access and lose connectivity, you'll need out-of-band access. For cloud servers on AWS EC2, DigitalOcean, or similar providers, use the web console or VNC access. For physical servers or VPS without console access, contact your hosting provider. This is why I always recommend testing in a separate session and maintaining console access during initial server security hardening.
How do you manage SSH keys across teams and automate SSH Key Only Auth Setup?
Individual key management scales poorly beyond solo developers. On projects with multiple contributors — like the legal-tech portals and eCommerce platforms I maintain — structured key management prevents chaos.
Organize keys by purpose and environment
Create distinct keys for different contexts rather than reusing one key everywhere:
id_ed25519_personal— Personal projects and learningid_ed25519_client_projectname— Specific client production serversid_ed25519_deploy— Automated deployment systems (Deployer, CI/CD)id_ed25519_backup— Backup and maintenance scripts
Configure ~/.ssh/config to select keys automatically based on hostname:
Host production-client.example.com
HostName 203.0.113.50
User deployer
IdentityFile ~/.ssh/id_ed25519_client_projectname
IdentitiesOnly yes
Port 22
Host *.internal.example.com
User admin
IdentityFile ~/.ssh/id_ed25519_internal
IdentitiesOnly yes The IdentitiesOnly yes directive prevents SSH from offering other keys, avoiding "too many authentication failures" errors when you have many keys loaded.
Centralized key distribution for teams
For teams managing multiple servers, consider configuration management tools over manual ssh-copy-id calls. Ansible's authorized_key module, Puppet's ssh_authorized_key resource, or Salt's ssh_auth.present state allow declarative key management tied to version-controlled inventories. This ensures consistent access across environments and simplifies onboarding/offboarding.
Key rotation and revocation
Rotate keys annually or when personnel change. The process for safe rotation:
- Generate new key pair on local machine
- Add new public key to server alongside existing key
- Verify new key authenticates successfully
- Remove old public key from server
- Securely delete old private key locally (
shred -u ~/.ssh/old_key)
Never reuse compromised keys. If a private key may have been exposed, treat every server it accessed as potentially compromised and rotate all credentials, not just SSH keys.
Integrating with CI/CD pipelines
For automated deployments using Deployer 7 or GitLab CI, store deploy keys as encrypted CI/CD variables rather than committing them to repositories. In GitLab, add the private key as a masked, file-type variable and reference it in your pipeline:
deploy:
script:
- mkdir -p ~/.ssh
- echo "$DEPLOY_SSH_KEY" > ~/.ssh/id_ed25519_deploy
- chmod 600 ~/.ssh/id_ed25519_deploy
- ssh-keyscan -H production.example.com >> ~/.ssh/known_hosts
- vendor/bin/dep deploy production This pattern keeps secrets out of version control while enabling reliable non-interactive authentication. I use this exact approach across sister sites sharing the same Deployer 7 + GitLab CI pipeline infrastructure.
Implementing SSH Key Only Auth Setup for long-term server security
Disabling password authentication is a foundational security control, not a complete solution. Combine SSH Key Only Auth Setup with defense-in-depth measures: fail2ban for rate limiting connection attempts, UFW firewall rules restricting SSH to known IP ranges where possible, regular audit of authorized_keys files to detect unauthorized additions, and monitoring /var/log/auth.log for anomalous patterns even when passwords are disabled.
Document your key management procedures before you need them under pressure. Include recovery steps for lost keys, onboarding checklists for new team members, and offboarding procedures that ensure departed colleagues' access is revoked promptly. For Nepal-based businesses operating with lean teams, having written runbooks prevents knowledge silos that become critical when the sole administrator is unavailable.
If you're securing production infrastructure for a Laravel application, eCommerce platform, or legal-tech portal and want hands-on assistance implementing hardened SSH configurations alongside comprehensive server security, reach out to discuss your infrastructure needs. Proper authentication hygiene pays dividends far beyond the initial setup effort.

