Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

SSH Key Only Auth Setup

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.

Password AuthenticationAttacker BotServer SSHBrute ForceGuessable Credentials + Leaked DBsPhishing / Keylogger RiskShared Passwords Across ServicesSSH Key Only Auth SetupLegitimate UserServer SSHCryptographic ProofPrivate Key Never Leaves MachineImmune to Brute Force AttacksPer-Key Revocation Without Password Reset
Password authentication exposes servers to automated attacks while SSH Key Only Auth Setup provides cryptographic security immune to credential guessing

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
1. Generate KeyLocal Machine2. Deploy Public Keyssh-copy-id3. TEST KEY LOGINNew Terminal Session4. Edit sshd_configDisable Passwords5. Validate Configsshd -t6. Restart sshdsystemctl restart7. VERIFY AGAINThird TerminalCRITICAL SAFETY RULES• Never close original SSH session• Always test BEFORE disabling passwords• Validate config with sshd -t• Keep console access as backup• Document recovery procedure
Safe SSH Key Only Auth Setup workflow emphasizing verification checkpoints before each destructive configuration change

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.

SymptomCauseFix
Key rejected despite correct installationWrong permissions on ~/.ssh or authorized_keyschmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
Authentication falls back to password promptPrivate key not offered or wrong key specifiedUse ssh -v -i /path/to/key to debug; check ~/.ssh/config IdentityFile paths
"Permission denied (publickey)" after config changePubkeyAuthentication misspelled or commented outRun sudo sshd -T | grep pubkeyauthentication to verify effective config
Works for one user, fails for anotherauthorized_keys owned by wrong user or home directory too openchown user:user ~/.ssh/authorized_keys; ensure home dir isn't world-writable
Key accepted locally but rejected remotelySELinux/AppArmor blocking access or NFS-mounted home with root_squashCheck audit.log; restore SELinux context with restorecon -R ~/.ssh
Deployer/GitLab CI fails but manual SSH worksCI runner uses different user/key or StrictHostKeyChecking blocks first connectionAdd 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 learning
  • id_ed25519_client_projectname — Specific client production servers
  • id_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.

Git Repositorykeys/developers/*.pubkeys/deploy/*.pubinventory.ymlAnsible / Puppetauthorized_key moduleIdempotent deploymentAudit trail via commitsProduction Server ALaravel App + DeployerProduction Server BWooCommerce StoreStaging ServerTesting EnvironmentKey Lifecycle Management✓ Onboarding: Add .pub to repo → Run playbook → Access granted✓ Offboarding: Remove .pub from repo → Run playbook → Access revoked instantly✓ Rotation: Generate new key → Add alongside old → Verify → Remove old key
Centralized SSH key distribution architecture enabling team-scale SSH Key Only Auth Setup with version-controlled access management

Key rotation and revocation

Rotate keys annually or when personnel change. The process for safe rotation:

  1. Generate new key pair on local machine
  2. Add new public key to server alongside existing key
  3. Verify new key authenticates successfully
  4. Remove old public key from server
  5. 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.

Frequently Asked Questions

SSH key only auth disables password login entirely, requiring cryptographic key pairs for server access. This eliminates brute-force attacks and automates secure deployments without storing credentials on remote servers.

Zero. OpenSSH is free and included in all Linux distributions. Costs only arise from developer time for initial configuration and ongoing key rotation management across your infrastructure.

Immediately after verifying key-based access works reliably. Never disable passwords before confirming at least two working keys exist to prevent permanent lockout during emergencies or key loss.

Run ssh-keygen -t ed25519 -C "your-email@example.com" on your local machine. Ed25519 keys are faster and more secure than RSA for modern Ubuntu 22/24 servers. Avoid DSA entirely as it is deprecated. Store the private key securely with a strong passphrase and never share it. Copy only the public key content to the server authorized_keys file using ssh-copy-id or manual paste.

Check three common issues in order. First, verify .ssh directory is 700 and authorized_keys is 600 owned by the connecting user. Second, ensure SELinux or AppArmor is not blocking access if enabled. Third, confirm the public key was pasted correctly without line breaks or extra whitespace. Debug with ssh -vvv user@host to see exact failure points. In my experience deploying Laravel apps via Deployer 7, permission drift after automated scripts causes most failures.

Yes, and you should. Configure ~/.ssh/config with Host blocks specifying IdentityFile per project. This prevents accidental credential leakage between client environments. On shared EC2 infrastructure hosting sites like notarykathmandu.com and translationnepal.com, I maintain separate keys per deployment pipeline. Never reuse a single key across unrelated systems. If one key compromises, limit blast radius by isolating access scopes through distinct key pairs and server-side authorized_keys restrictions.

Edit /etc/ssh/sshd_config setting PasswordAuthentication no, ChallengeResponseAuthentication no, and PubkeyAuthentication yes. Always test configuration with sshd -t before restarting sshd service. Keep an active session open during testing to avoid lockout. On Ubuntu 24.04, also check /etc/ssh/sshd_config.d/ for override files that might re-enable passwords. After changes, verify externally with ssh -o PreferredAuthentications=publickey user@host to confirm password prompts are truly disabled before closing your test session.

You lose access permanently if password auth is disabled and no backup key exists. Always maintain at least two authorized keys per server. Store encrypted backups of private keys in a password manager or secure vault. For production systems I manage, I keep a recovery key stored offline with the client. If locked out, console access through cloud provider or physical datacenter becomes necessary. Prevention through redundant keys costs nothing compared to emergency recovery downtime.

Add new public keys to authorized_keys first, verify they work, then remove old keys. Never delete before confirming replacement functionality. For automated deployments using Deployer 7 or GitLab CI, update runner configurations simultaneously. Schedule rotations during low-traffic windows. Document which keys belong to which team members or services. On legal-tech portals handling sensitive documents, I rotate keys quarterly and immediately upon staff departure. Test thoroughly after each rotation before considering the task complete.

Keys alone resist brute force but lack second-factor verification if stolen. For highest security, combine keys with FIDO2 hardware tokens via PAM or use certificate-based SSH. However, key-only auth still vastly outperforms password-only setups against automated attacks. In Nepal where hardware token availability is limited, key-only with strict file permissions and regular rotation provides practical security for most business applications. Reserve MFA requirements for systems handling financial transactions or highly regulated legal data.

Prefix the public key in authorized_keys with command="restricted-command" or restrict options like no-port-forwarding,no-agent-forwarding. This limits what authenticated users can execute. Useful for deployment keys that should only run git pull or specific scripts. For SFTP-only access, use internal-sftp subsystem with ChrootDirectory. On eCommerce servers processing payments, I restrict CI/CD keys to deployment paths only. Always test restrictions thoroughly as syntax errors silently fail open or deny all access depending on SSHD version.

Yes, this is their primary authentication method. Configure agent forwarding or specify key paths in deployment configs. For Deployer 7, set identity_file in deploy.php host definitions. Ensure deployment keys have minimal required permissions. Never use personal keys for automation. Create dedicated service accounts with restricted shell access. On GitLab CI runners deploying Laravel applications, I use project-specific deploy keys stored as CI variables. Rotate these independently from human operator keys to maintain separation of concerns and audit trails.

Review /home/*/.ssh/authorized_keys and /root/.ssh/authorized_keys systematically. Count keys, identify owners, and verify each is still needed. Remove orphaned entries from departed staff or decommissioned services. Log authorized_keys modifications via auditd or file integrity monitoring. On multi-tenant servers hosting directories like Ajako Deal, I audit monthly. Document key fingerprints alongside owner names. Consider centralized key management tools for larger fleets. Regular audits prevent credential creep that undermines key-only security posture over time.

Prefer Ed25519 for all new deployments. It offers better performance and security than RSA at smaller key sizes. Use RSA-4096 only when connecting to legacy systems lacking Ed25519 support. Avoid ECDSA due to potential implementation vulnerabilities and DSA because it is obsolete. OpenSSH 8.x+ on Ubuntu 22/24 fully supports Ed25519. When integrating with older payment gateways or legacy Magento installations, test compatibility first. Standardize on Ed25519 across your infrastructure unless specific compatibility requirements dictate otherwise.

Access the server through cloud console, IPMI, or physical interface. Re-enable PasswordAuthentication yes temporarily in sshd_config, restart sshd, then fix key issues. Once key access is restored and verified, disable passwords again. If no console access exists, contact hosting provider for rescue mode. Prevention beats recovery: always keep an active root session while modifying SSH config, maintain emergency password-enabled accounts with complex passphrases, and test changes before applying globally. Lockouts during Friday deployments taught me this discipline early in my career.

Share this article

Quick Contact Options
Choose how you want to connect me: