{"id":440,"date":"2026-10-14T10:11:33","date_gmt":"2026-10-14T10:11:33","guid":{"rendered":"http:\/\/www.scmgalaxy.com\/tutorials\/2015\/10\/14\/steps-to-perform-ssh-login-without-password-using-ssh-keygen-and-ssh-copy-id\/"},"modified":"2026-10-14T10:11:33","modified_gmt":"2026-10-14T10:11:33","slug":"steps-to-perform-ssh-login-without-password-using-ssh-keygen-and-ssh-copy-id","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/steps-to-perform-ssh-login-without-password-using-ssh-keygen-and-ssh-copy-id\/","title":{"rendered":"SSH Passwordless Login with ssh-keygen and ssh-copy-id (Step-by-Step)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><em>Originally published on 2015-10-14; fully revised and updated.<\/em><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" src=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2015\/10\/ssh-login-without-password.png\" alt=\"SSH Login Without Password\" \/><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Key-based SSH login lets you connect to remote Linux or Unix hosts without typing the account password on every login. This guide shows how to generate a key pair, install the public key with <code>ssh-copy-id<\/code>, verify access, use <code>ssh-agent<\/code>, and apply optional SSH hardening.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How passwordless SSH login works<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">SSH uses a <strong>public\/private key pair<\/strong>. Your private key stays on your local machine, while the public key is added to the remote user\u2019s <code>~\/.ssh\/authorized_keys<\/code>. During login, the server validates cryptographic proof from your private key instead of prompting for the remote account password.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Workflow overview<\/h2>\n\n\n\n<pre class=\"mermaid\">\nflowchart TD\n    A[Generate key pair] --> B[Install public key on server]\n    B --> C[Test SSH login]\n    C --> D{Prompt is only key passphrase}\n    D -- yes --> E[Optional ssh-agent setup]\n    D -- no --> F[Fix permissions and SSH settings]\n    F --> B\n    E --> G[Optional server hardening]\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Generate an SSH key pair<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Run <code>ssh-keygen<\/code> on your local machine. If you do not pass options, OpenSSH will create a default key type. If your environment specifically requires RSA, generate it explicitly.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\"><span class=\"hljs-comment\"># Default key generation<\/span>\nssh-keygen\n\n<span class=\"hljs-comment\"># Explicit Ed25519 key<\/span>\nssh-keygen -t ed25519 -C <span class=\"hljs-string\">\"your_name@your_laptop\"<\/span>\n\n<span class=\"hljs-comment\"># Explicit RSA key (compatibility-focused environments)<\/span>\nssh-keygen -t rsa -b <span class=\"hljs-number\">4096<\/span> -C <span class=\"hljs-string\">\"your_name@your_laptop\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Set a <strong>strong passphrase<\/strong> when prompted to protect your private key at rest.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Copy the public key to the remote host<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The easiest method is <code>ssh-copy-id<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\"><span class=\"hljs-comment\"># Copy your default public key<\/span>\nssh-copy-id user@hostname.example.com\n\n<span class=\"hljs-comment\"># Copy a specific public key file<\/span>\nssh-copy-id -i ~\/.ssh\/id_rsa.pub user@hostname.example.com<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">If <code>ssh-copy-id<\/code> is not available, you can append the key manually over SSH:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript language-bash\">cat ~<span class=\"hljs-regexp\">\/.ssh\/i<\/span>d_ed25519.pub | ssh user@<span class=\"hljs-number\">123.45<\/span><span class=\"hljs-number\">.56<\/span><span class=\"hljs-number\">.78<\/span> <span class=\"hljs-string\">\"mkdir -p ~\/.ssh &amp;&amp; chmod 700 ~\/.ssh &amp;&amp; cat &gt;&gt; ~\/.ssh\/authorized_keys &amp;&amp; chmod 600 ~\/.ssh\/authorized_keys\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">As noted in the original post, when keys are loaded into <code>ssh-agent<\/code>, <code>ssh-copy-id<\/code> can use agent-provided identities if you do not pass <code>-i<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Test login<\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css language-bash\"><span class=\"hljs-selector-tag\">ssh<\/span> <span class=\"hljs-selector-tag\">user<\/span><span class=\"hljs-keyword\">@hostname<\/span>.example.com<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">If configured correctly, you should not be prompted for the remote account password. You may still be asked for your key passphrase unless an agent is handling it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Optional: Use ssh-agent for passphrase caching<\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\"><span class=\"hljs-comment\"># Start agent in current shell (if needed)<\/span>\n<span class=\"hljs-keyword\">eval<\/span> <span class=\"hljs-string\">\"$(ssh-agent -s)\"<\/span>\n\n<span class=\"hljs-comment\"># Add private key to agent<\/span>\nssh-add ~\/.ssh\/id_rsa\n\n<span class=\"hljs-comment\"># Show loaded public keys<\/span>\nssh-add -L<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Command and method comparison<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Method<\/th><th>Best for<\/th><th>Example<\/th><th>Notes<\/th><\/tr><\/thead><tbody><tr><td><code>ssh-copy-id user@host<\/code><\/td><td>Standard setup<\/td><td>Install default local public key<\/td><td>Fast and usually least error-prone<\/td><\/tr><tr><td><code>ssh-copy-id -i ~\/.ssh\/id_rsa.pub user@host<\/code><\/td><td>Multiple keys<\/td><td>Install a specific key<\/td><td>Useful when default key is not desired<\/td><\/tr><tr><td>Manual key append over SSH<\/td><td>No <code>ssh-copy-id<\/code> installed<\/td><td><code>cat ~\/.ssh\/id_ed25519.pub | ssh user@host \"...\"<\/code><\/td><td>Works broadly, but permissions must be correct<\/td><\/tr><tr><td><code>ssh -i ~\/.ssh\/key user@host<\/code><\/td><td>Troubleshooting identity selection<\/td><td>Force a specific private key for login<\/td><td>Helpful when several keys exist locally<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Optional server hardening (after successful key login)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Only harden SSH after confirming a non-root user can log in with keys. Older examples often show <code>PermitRootLogin without-password<\/code>; many modern OpenSSH setups use <code>PermitRootLogin prohibit-password<\/code> for the same intent.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-ini\"><span class=\"hljs-comment\"># \/etc\/ssh\/sshd_config<\/span>\nPermitRootLogin prohibit-password\nPasswordAuthentication no\nPubkeyAuthentication yes<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\"><span class=\"hljs-comment\"># Validate config, then reload service<\/span>\nsudo sshd -t\nsudo systemctl reload sshd\n\n<span class=\"hljs-comment\"># On some distributions, service name is ssh<\/span>\nsudo systemctl reload ssh<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Troubleshooting quick checks<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>Verify remote permissions: <code>~\/.ssh<\/code> should typically be <code>700<\/code> and <code>~\/.ssh\/authorized_keys<\/code> should typically be <code>600<\/code>.<\/li><li>Confirm you are connecting as the correct remote user.<\/li><li>Use verbose output to diagnose authentication: <code>ssh -v user@hostname.example.com<\/code>.<\/li><li>If multiple keys are present locally, test explicitly with <code>ssh -i ~\/.ssh\/your_key user@hostname.example.com<\/code>.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Original and related references<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"http:\/\/community.scmgalaxy.com\/blog\/view\/40844\/how-to-scp-ssh-and-rsync-without-prompting-for-password-using-openssh\">How to SCP, SSH and rsync without prompting for password using OpenSSH<\/a><\/li><li><a href=\"http:\/\/manpages.ubuntu.com\/manpages\/lucid\/man1\/ssh-copy-id.1.html\">ssh-copy-id man page (Ubuntu mirror)<\/a><\/li><li><a href=\"http:\/\/www.scmgalaxy.com\/Forum\/34-shell-script\/501-file-copying-and-transfer-between-two-machine.html\">File copying and transfer between two machines<\/a><\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Best practices<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>Use passphrase-protected keys and store private keys only on trusted endpoints.<\/li><li>Prefer least-privilege users with <code>sudo<\/code> over direct root SSH access.<\/li><li>Test key-based login in a separate session before disabling password authentication.<\/li><li>Keep a rollback path (console or out-of-band access) before SSH hardening changes.<\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to configure SSH key-based authentication so you can log in without typing the remote account password each time. This updated guide covers setup, verification, ssh-agent usage, and safe hardening options.<\/p>\n","protected":false},"author":1,"featured_media":3069,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[49],"tags":[545,897,534,901,896,898,902,900,899,732],"class_list":["post-440","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-general","tag-how","tag-login","tag-password","tag-remote-machine","tag-ssh","tag-ssh-login","tag-ssh-login-without-password","tag-ssh-copy-id","tag-ssh-keygen","tag-steps"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/440","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=440"}],"version-history":[{"count":3,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/440\/revisions"}],"predecessor-version":[{"id":79313,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/440\/revisions\/79313"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media\/3069"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=440"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=440"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=440"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}