WordPress Tutorial: Using SSH to Install/Upgrade


This tutorial will guide you step by step on how to setup your server so you can install new plugins and upgrade existing plugins using an SSH2 layer in PHP and WordPress.

What is WordPress?
WordPress started in 2003 with a single bit of code to enhance the typography of everyday writing and with fewer users than you can count on your fingers and toes. Since then it has grown to be the largest self-hosted blogging tool in the world, used on hundreds of thousands of sites and seen by tens of millions of people every day.

What is SSH[2]?
SSH (Secure Shell) is a protocol allowing a secure channel to be established between a web server and a client’s local machine. Many web hosting companies now offer SSH for greater security.

Tutorial Pre-requisites

There are a few things that need to be in place before you can actually use this tutorial.

The first thing to do is make sure you have SSH2 installed via pecl. If it’s not installed or you’re not sure, run this command: pecl install ssh2

note: If your case is where the installed version of SSh2 is beta, run this command instead: pecl install channel://pecl.php.net/ssh2-0.11.0

If you don’t feel comfortable running these commands yourself and you know of a server administrator that can help, or you’re paying for managed services, ask them to install this for you.

After SSH2 is installed, follow these instructions to ensure that the SSH2 extension is enabled in PHP. Again, if you are using managed services, simply ask them to do this for you.

cd /etc/php5/conf.d; echo “extension=ssh2.so” > ssh2.ini
/etc/init.d/apache2 restart
Red Hat, CentOS, Fedora
cd /etc/php.d; echo “extension=ssh2.so” > ssh2.ini
/etc/init.d/httpd restart

Step 1: Generating the server-side RSA keys


Generating public/private rsa key pair.
Enter file in which to save the key (/home/user1/.ssh/id_rsa):
Created directory ‘/home/user1/.ssh’.
Enter passphrase (empty for no passphrase): (just hit enter, no need for a password)
Enter same passphrase again: (same thing, hit enter again)
Your identification has been saved in /home/user1/.ssh/id_rsa.
Your public key has been saved in /home/user1/.ssh/id_rsa.pub.
The key fingerprint is:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx user1@server1.example.com

The xx:xx:xx etc. will be replaced with your actual fingerprint.

Step 2: Creating an ‘authorized_keys’ file

cd .ssh
cp id_rsa.pub authorized_keys

Step 3: Setting the proper file permissions

cd ~/
chmod 755 .ssh
chmod 644 .ssh/*

Step 4: Choosing the ‘SSH’ option

In this tutorial, I opted not to use a password, so you do not need to enter a password.

Step 5: Click “Proceed”

The last step is to click the proceed button and it will install a new plugin or upgrade an existing plugin via the integrated SSH layer in WordPress. You should see results something like this…

== Optional ==

If you want to automate the process a bit more, there are a few more things you can do to make it even easier.

If you open up your wp-config.php and add these lines, it will make the process smoother.


Now, when you click “upgrade” or “install” on a new plugin, it will bypass the first screen you saw above asking for the details. It will automatically go into the process and start the install/upgrade.

Thank you

A huge thanks to Dion Hulse and Matt Martz for helping me with creating this tutorial.

42 thoughts on “WordPress Tutorial: Using SSH to Install/Upgrade

  1. I had a devil of a time to get this work with a public/private key, but finally got it working.

    First off, the page at http://codex.wordpress.org/Editing_wp-config.php has a horrible error in that it says to use FTP_PRIVKEY and not FTP_PRIKEY — you have it right on your page, but I had previously edited the file using info from the Codex and didn’t catch it for hours.

    Second, my passphrase is empty but keeping password blank didn’t work. I had to put SOMETHING in it, didn’t matter what. Bizarre.

    Finally, a suggestion, no need to open up your .ssh dir to be readable by all. Just append the appropriate .pub contents to the accounts authorized_keys file, then park both the private and public key in some obscure place that the apache process can read.

    Thanks for the post. It was very helpful — unfortunately I trusted the wordpress codex page 🙁

  2. I’m getting an error after pressing “proceed”:

    “Public and Private keys incorrent for (my username)”

    I’ve checked and double checked my paths and permissions. The hostname and username matches those listed in the id_rsa file. I am completely stumped as to what the issue is.

    Any thoughts?

    1. I absolutely agree giving “Other” read access to your private key is a huge security issue. Unfortunately it seems like the WordPress Developers require you to keep this “private” key accessible by apache!

      What does this mean? It means that anyone with access to your server, legitimate or otherwise, will now have access to login to the user which has access to your WordPress directory and your WordPress SQL Database username, password, and location.

      What should I do? It almost seems like FTP could be more secure in this case, but if you really want to use SSH here are my recommendations:

      First: USE A PASSPHRASE, and make it strong (1), this way anyone who finds your “private” key won’t instantly have access to your server.

      Second: Don’t change the permissions of your .ssh folder, apache only needs access to these two files, put them somewhere else, but NOT IN A WEB DIRECTORY! The .ssh folder should be 700 and files 600 (2).

      Third: Don’t keep id_rsa readable by everyone when it doesn’t need to be. If you need to upgrade wordpress change its permissions to 644, upgrade, and then change it back to 600.

      Fourth: (security through obscurity) Don’t keep the file named id_rsa. If I were a hacker with unprivileged access to a wordpress server, after reading this article (and others like it), my first command would be:

      find / -name id_rsa 2>/dev/null

      Which would point me to any files named id_rsa on the server.

      Rick, in the post below, mentions that CentOS’s Apache install won’t let itself view ~/.ssh/ and that’s because CentOS knows this is a horrible idea!

      Instead of all of this, why not just setup an FTP daemon that only accepts traffic from localhost?

      1) http://www.utexas.edu/its/secure/articles/keep_safe_with_strong_passwords.php
      2) http://www.linuxforums.org/articles/file-permissions_94.html

  3. I could not get Apache (Centos 5.3) to allow the key files to be read when left in the given user’s home directory. I had to create a new directory in /var/www and copy the files there to be read. So I have:


    Other than that, it works perfectly.

  4. @Weave, Thanks for the note. I corrected it on codex.wordpress.org so it’s correct now.

    Even if it’s readable by all, the webserver can’t access it because it’s outside of the readable directory of public_html for the good majority of users. I’ll take it into consideration when I write a second version of this tutorial, Thanks Weave!

    @Tony, alright. If they’re such terrible permissions, what do you recommend? It would be a lot more helpful to everyone if you offer a suggestion instead of just saying they’re bad. Saying they’re bad doesn’t help anyone.

    @Rick, thanks for the tip! I wrote this tutorial based on what I had access to, so I haven’t tested it in too many environments yet. I’ll add your details when I write a second version.

    Thanks everyone for the tips and suggestions and feedback, glad you guys are liking the tutorial!

  5. I haven’t been able to get this working… as far as I can tell, it’s silently dying while unzipping a plugin package. I’m pretty sure I have the key file issues ironed out (thanks to your post), because wp-content/upgrade/ is getting created. The plugin’s update page loads for a long while, and then hangs, with an incompletely rendered menu on the left and blank content. Any ideas where I should look? I poked around in the PHP, but didn’t see anything immediately obvious, and no error is being returned.

    1. What web server are you running? What version of PHP? Do you have the SSH2 installed in Apache?

      Try to give me as many details as possible and I’d be happy to help you try to debug it.

      1. Came back to this after a long hiatus (and just doing manual updates).

        The error the upgrade tool gives is “There was an error connecting to the server, Please verify the settings are correct.”

        I’ve confirmed that my public key works from the command line by doing:

        sudo su www-data
        ssh -i /path/to/private/id_rsa user@host

        (Although first I had to give www-data write permissions to /var/www/.ssh/known_hosts.)

        If I run with FTP_PASS empty, I get the error from the upgrade page and nothing in /var/log/auth.log. If I run with a random FTP_PASS, I get “Did not receive identification string from”.

        Version info:

        Server version: Apache/2.2.14 (Debian)
        Server built: Jan 2 2010 23:02:48
        OpenSSH_5.3p1 Debian-1, OpenSSL 0.9.8k 25 Mar 2009

        I have /etc/php5/conf.d/ssh2.ini set up as per your instructions.

  6. Hi!, thanks for the tutorial 😉
    It worked fine, for updating plugins but there was a bug for updating the core.
    I left the time pass but now, i get an error

    Unable to locate WordPress directory.
    Installation Failed

    Which is weird, because now even plugins has the same error when upgrading ;(.
    Any idea of what causes that?

  7. @Alberto, I’ve seen that issues before and when I experienced it, it was directly related to the permissions. Make sure the permissions are set properly on the .ssh folder itself and the files inside of .ssh

    Run through the tutorial again to ensure you didn’t make any mistakes along the way.

  8. Hey,

    I’ve run through this tutorial many times.

    I have ssh2 installed, but I don’t think php is loading the module because when I run the following script I get the message ssh2 is not installed:

    When viewing WordPress’ upgrade page, I see the option for FTP and not SSH, even though my wp-config has ssh information as per your tutorial. Very odd

    1. Calvin,

      My tutorial on installing SSH2 isn’t very in-depth, although I may try to include a few more options in the future. Right now, I’d suggest just doing a Google search to see if that can help you out. Google -> “installing ssh2 apache” might help you.

  9. If you already use SSH keys (like many do) simply run this line instead:

    `cat id_rsa.pub >> authorized_keys`

    You also will want to enable the extension in apache2, which you can do with:

    `cd /etc/php5/apache2/conf.d; echo “extension=ssh2.so” > ssh2.ini`

  10. If there is not already a directory ‘authorized_keys’ in the .ssh folder (as was the case with me), the command ‘cp id_rsa.pub authorized_keys’ will create a file called ‘authorized_keys’ instead of copying the file ‘d_rsa.pub’ to the ‘authorized_keys’ directory.

  11. hello

    Thanks for this tutorial. I a
    I am already using ssh authentification through public/private key files to log into my dedicated server.
    It means that only the public key file is stored on my server while the private key file remains on the client I am connecting from.

    Thus I am surprised to see that, with this method, both the private and the public key files are stored on the remote directory.

    Does not it create a security issue ?

    1. I haven’t seen any security issues with it since the folder where the keys reside are not web server accessible.

      If you see any security problems with it, I’m open to suggestions and/or corrections. So if you have something to contribute to it, please do.

  12. I already try this, and nothing error message show up. But when I try to insert you code at wp-config.php, at my Connection Information there no SSH at my type Connection. If I remove the code from my wp-config.php, everytime I insert my password, the error say : Failed to connect to FTP Server xxx.xxx.xxx.xxx:22

    Please advice

    1. I already try again and it running well. I can upgrade all my plugins. But it still can’t upgrade the wordpress core. Always show error :

      Downloading update from http://wordpress.org/wordpress-2.8.6.zip.

      Unpacking the update.

      Could not copy file: /home/stikomedu/public_html/wp-content/upgrade/wordpress-2.8.6/wordpress/wp-includes/js/codepress/engines/khtml.js

      Installation Failed

      Please help me.

      Thank you

      1. Prazetvo, this happens from time to time, it’s a weird bug. I haven’t been able to figure it out yet. I just upload normally and then the next time, it works just fine. I haven’t been able to consistently reproduce the bug yet.

  13. I have been looking online for some description to how the plugin upgrade process works so I can understand it better. The main reason is that I do not understand why this process is necessary. When I click the upgrade button shouldn’t PHP (wordpress) be able to download the plugin, extract it, and drop it into the plugin folder without the need for all this? Is it that php is running under the apache user and people do not want to make the plugin folder writable to the apache user?

    1. Nate, the reason for this is because now all web hosts are setup properly to do that. Some web hosts, what you described works just fine. Often, it will not, for security reasons. If permissions are too open, someone could hack your site — so these are security precautions in place to prevent that.

      I’ll be writing a follow-up post soon about permissions and users, making it even easier to upgrade.

        1. Sorry, nope, no follow-up on this.

          WordPress 3.2 actually made HUGE improvements to the upgrade system so it should be easier to follow and setup now.

  14. Quick note, I see that libssh2-php is packaged in Ubuntu, so you can install that and skip the PEAR step if you have access to apt. It handles everything you listed, just reload apache after installing it.

  15. Second note, giving your private key world read permission is VEEEERY not good. Anyone else with access to the server will be able to read it. I’m also not clear on why you need both the private and public key.

    While I don’t like the idea of consultants / experts demanding people point out how to fix it or shut up, I’ll take a stab at it.

    1. Read http://wiki.hands.com//howto/passphraseless-ssh/ . Not all of it can be applied, but it’s good to start with best practices.
    2. Determine the task that needs to be done; I gather the purpose is to transfer from wp-uploads to wp-content in situations where the web server is running with insufficient permissions.
    3. Restrict the SSH key to ‘from=localhost.’
    4. Perhaps write a local script to do this, and restrict the key to only that script with command=.
    5. Perhaps change the group key to something relevant; debian uses www-data as a group for webserver users.

  16. @ jldugger I removed the read permission for the world on the private key (kept user and group permission) and seems to work fine still.

  17. Have you tried with the FS_METHOD in wp_config.php? I use SSH for automatic upgrades and set the FS_METHOD to “direct”. No login and still uses SSH…

  18. You may want to indicate that most people will NOT have libssh2 installed, which means that simplistic looking pecl update will fail.

    error: The required libssh2 library was not found. You can obtain that package from http://sourceforge.net/projects/libssh2/
    ERROR: `/root/tmp/pear/ssh2/configure –with-ssh2′ failed

    How does one install libssh2?

  19. It’s extremely dangerous to make your private key mode 644.

    Advising users to do this is terrifically bad security-wise.

    Making a copy of the key and making that key readable by the user that the web server runs as is marginally more secure, but still not a great solution.

    One option would be to create a new set of keys (outside of .ssh) readable only by the web server user, and adding that key to the authorized_keys file of the user you are trying to log in as.

  20. What should I do if I get stuck at unpacking updates? I did get the SFTP radio to show up, so I think things installed correctly.

    1. I’ve had that issue before, I would try just refreshing the page. I haven’t seen a refresh, do any harm. But still be careful.

      As always, backup backup backup, before doing any upgrades.

  21. I’ve had this page bookmarked for years, but have recently been switching to nginx on my VPS’. Can you add a new post or add a section for doing this using nginx?

    1. Hi Mike,

      Thanks for the comment. No plans as of right now to develop any code for Nginx.

Comments are closed.