Automating WordPress uploads using SSH

WordPress allows automated updates of plugins and the program itself, but it requires FTP or FTPS on the server. I did not want to add an FTP server to my host, and didn’t want to be sending my id/password to my shell account over the net in clear text either.

But then I found out through a few web pages that one can add SSH access to PHP on the server and use that.

All seemed straight forward except my host has password logins via SSH disabled. Must use a private/public key. I tried to carefully follow the instructions in each of the pages above and kept hitting failures.

So this blog entry is to rehash how to do this using private/public keys and how to work around an apparent bug in WordPress 2.7.1 with specifics for Centos 5.

Server Software

  1. Installed ssh2. Since I have rpmforge set up as a yum repository I just had to yum install libssh2 and libssh2-devel
  2. To get ssh2 support added to PHP I had to add a few more packages:  php-size and php-devel
  3. I then installed ssh2 via the command :  pecl install -f ssh2
  4. Edited /etc/php.ini and added “” to the  Dynamic Extensions section.
  5. Restarted apache

OK, so far this matches up with the blog entries above (which have far more detail on the steps).

Then came the confusion. I had to create a special ssh2 private and public key because I didn’t want to use the one I use to log on to my shell. I used ssh-keygen to generate a pair with an esoteric name and no passphrase.

The key files need to be stored somewhere where the web server process can get to them. But you absolutely do not want someone being able to download your private key from the webserver, else they can use it to log into your shell via ssh since it has no pass phrase. So stash it somewhere outside the normal DocumentRoot for your web server. Some suggest stashing it in your own home directory and chmod it open. That’s not the best idea either.

The other consideration is the web server needs to log into a user account via ssh that has r/w access to all files that need to update. So whatever user owns all your wordpress files (which probably should NOT be the webserver username) is the one who will be used to log on for automatic updates.

So the final step is to append the contents of the ssh .pub file to the ~/.ssh/authorized_keys file of the owner of the wordpress files.

Now comes the bug which drove me nuts. The password does not work. Hence why I had to create a key without one. But leaving the password field blank does not work either. You have to enter something into that field. Anything. Then it should work.

Finally, if you don’t want to fill in the key locations, username, host, etc, everytime you do an update, you can define the values in wp-config.php file.  Example:

define('FTP_BASE', '/var/www/wp/');
define('FTP_CONTENT_DIR', '/var/www/wp/wp-content/');
define('FTP_PLUGIN_DIR ', '/var/www/wp/wp-content/plugins/');
define('FTP_PUBKEY', '/var/www/.secret/');
define('FTP_PRIKEY', '/var/www/.secret/id--wp');
define('FTP_USER', 'username');
define('FTP_PASS', 'foobar');
define('FTP_HOST', '');

The CODEX page has the private key define wrong as FTP_PRIVKEY when it should be FTP_PRIKEY — which also tripped me up.

Additional Security Steps

If the private key is obtained your wordpress account is compromised. Ensure that the file can’t be downloaded from the web server. You can also delete the public key from the authorized_keys file and only append it when you’re going to do automated site maintenance. That minimizes the window of time the private key could work even if it was obtained.

4 thoughts on “Automating WordPress uploads using SSH”

  1. You could also put from=”localhost”,no-port-forwarding,no-pty in your authorized keys file. It should go before ssh-rsa. That will ensure the private key can only be used locally. Although, chmod’ing the private key file open and shut as you need it couldn’t hurt either.

  2. Woah, thanks. That’s much better! Had no idea that that was doable! Then in that case the host in FTP_HOST has to be localhost too.

    I did have to change the from to localhost.localdomain due to this syslog error.

    May 28 21:53:56 catzilla sshd[1316]: Authentication tried for weave with correct key but not from a permitted host (host=localhost.localdomain, ip=


  3. I made the update to the codex so it doesn’t show PRIVKEY anymore, but that it reflects the correct value of PRIKEY. I made the update because I saw your article and realized you were correct, that the codex had the wrong value.

    Thanks for the heads up.

    It’s tough to write a tutorial that fits every circumstance, so it’s great that people, like yourself, like spin-off tutorials so that other people can benefit from other people’s experiences.

Leave a Reply

Your email address will not be published. Required fields are marked *