Wordpress dev clone (Ubuntu)
This article describes how to create a fully operational development clone of your WordPress site. You will need to install a web server and database software and edit some configuration files to make it work. Note: Follow this article by Abhijit Menon-Sen (ams@toroid.org) if you want to use git to keep the live site in sync with your development version.
Installing MySQL, Apache and PHP
First we install MySQL, Apache and PHP on the local Ubuntu machine. And enable the userdir and url-rewrite modules.
$ sudo apt-get install apache2 php5 php5-mysql mysql-server php5-mysql phpmyadmin
$ sudo a2enmod userdir rewrite
Configure Apache
To enable per-user web directories you will have also have to edit the /etc/apache2/mods-enabled/php5.conf file. Comment out or remove the following part:
$ cat /etc/apache2/mods-enabled/php5.conf
...
<IfModule mod_userdir.c>
<Directory /home/*/public_html>
php_admin_value engine Off
</Directory>
</IfModule>
If you want to use symlinks in public_html , for example to link to a git repo (see this article), you will have to make sure that the user privileges are correct. In doubt run the following commands:
$ chmod -R a+rwx ~/path/of/symlink
$ chmod +rx ~/path/of/symlink
$ chmod +rx ~/path/of
$ chmod +rx ~/path
Your web server is now set up correctly.
Database synchronisation
Export the remote database and import it locally. The simplest is to use the same database name, username and password.
The following script will let you pull or push the database between the remote and local machine.
#!/bin/sh
# Copyright (C) 2013 Uco Mesdag
# Usage: database-sync.sh [OPTIONS] [USER@HOST]
# --push, --pull pull: overwrite local mysql datasbase with
# remote database
# push: overwrite remote mysql datasbase with
# local database
# --db=DATABASE use if local and remote mysql database have
# the same name
# --mysql-user=USERNAME use if local and remote mysql database have
# the same username
# --mysql-password=PASSWORD use if local and remote mysql database have
# the same password
# --local-db=DATABASE local mysql database name
# --local-mysql-user=USERNAME local mysql username
# --local-mysql-password=PASSWORD local mysql database password
# --remote-db=DATABASE remote mysql database name
# --remote-mysql-user=USERNAME remote mysql database username
# --remote-mysql-password=PASSWORD remote mysql database password
# Instructions: you can also set all parameters in this script self,
# so you can run "database-sync.sh" without arguments.
# User configuration
REMOTE=
USER=
ACTION=pull # default action 'push' or 'pull'
MYSQL_REMOTE_USER=root
MYSQL_REMOTE_PASSWORD=
REMOTE_DB_NAME=
MYSQL_LOCAL_USER=root
MYSQL_LOCAL_PASSWORD=
LOCAL_DB_NAME=
#
#
#
BASEDIR="$( cd $(dirname "$0") ; pwd )"
OPTS=`getopt -a -l push,pull,db:,remote-db:,local-db:,mysql-user:,remote-mysql-user:,local-mysql-user:,mysql-password:,remote-mysql-password:,local-mysql-password: -o "" -- "$@"`
ACTION=pull
usage() {
echo "Usage: $(basename "$0") [OPTIONS] [USER@HOST]" >/dev/stdout
echo " --push, --pull pull: overwrite local mysql datasbase with" >/dev/stdout
echo " remote database" >/dev/stdout
echo " push: overwrite remote mysql datasbase with" >/dev/stdout
echo " local database" >/dev/stdout
echo " --db=DATABASE use if local and remote mysql database have" >/dev/stdout
echo " the same name" >/dev/stdout
echo " --mysql-user=USERNAME use if local and remote mysql database have" >/dev/stdout
echo " the same username" >/dev/stdout
echo " --mysql-password=PASSWORD use if local and remote mysql database have" >/dev/stdout
echo " the same password" >/dev/stdout
echo " --local-db=DATABASE local mysql database name" >/dev/stdout
echo " --local-mysql-user=USERNAME local mysql username" >/dev/stdout
echo " --local-mysql-password=PASSWORD local mysql database password" >/dev/stdout
echo " --remote-db=DATABASE remote mysql database name" >/dev/stdout
echo " --remote-mysql-user=USERNAME remote mysql database username" >/dev/stdout
echo " --remote-mysql-password=PASSWORD remote mysql database password" >/dev/stdout
echo "" >/dev/stdout
echo "Instuctions: you can also set all parameters in this script self," >/dev/stdout
echo " so you can run \"$(basename "$0")\" without arguments." >/dev/stdout
}
password() {
if [ "$MYSQL_REMOTE_PASSWORD" = "" ]; then
echo ""
read -p " Enter the mysql password for $MYSQL_REMOTE_USER on $REMOTE: " MYSQL_REMOTE_PASSWORD
fi
if [ "$MYSQL_LOCAL_PASSWORD" = "" ]; then
echo ""
read -p " Enter the local mysql password for $MYSQL_LOCAL_USER: " MYSQL_LOCAL_PASSWORD
fi
echo ""
}
if [ $? != 0 ]; then
usage
exit 1
fi
if [ "$( echo $1 | grep '.*\(help\|\?\)$' )" ]; then
usage
exit 0
fi
setopt() {
if [ "$( echo $2 | grep '[[:alnum:]]\+@[[:alnum:]\.]\+' )" ]; then
ARGS="$@"
IFS="@"
set -- $2
if [ $# -ne 2 ]; then
echo "invalid remote" >/dev/stderr
exit 1
fi
USER="$1"
REMOTE="$2"
if ! dig @8.8.8.8 $REMOTE | grep "ANSWER: [1-9][0-9]*" >/dev/null; then
echo "invalid domain" >/dev/stderr
exit 1
fi
unset IFS
shift
setopt "$@"
else
if [ "$( echo $1 | grep '.*\(pull\|push\)$' )" ]; then
ACTION="$( echo $1 | sed 's/^--\(pull\|push\)$/\1/' | grep '\(pull\|push\)$' )"
shift
setopt "$@"
else
if [ -n "$1" -a -n "$2" ]; then
OPTNAME=OPT_${1#--}
OPTNAME="$( echo $OPTNAME | sed 's/\-/_/g' )"
OPTVAL="\"$2\""
eval $OPTNAME="$OPTVAL"
shift
shift
setopt "$@"
fi
fi
fi
}
eval setopt $OPTS
if [ "$OPT_db" ]; then
LOCAL_DB_NAME="$OPT_db"
REMOTE_DB_NAME="$OPT_db"
fi
if [ "$OPT_local_db" ]; then
LOCAL_DB_NAME="$OPT_local_db"
fi
if [ "$OPT_remote_db" ]; then
REMOTE_DB_NAME="$OPT_remote_db"
fi
if [ "$OPT_mysql_user" ]; then
MYSQL_REMOTE_USER="$OPT_mysql_user"
MYSQL_LOCAL_USER="$OPT_mysql_user"
fi
if [ "$OPT_remote_mysql_user" ]; then
MYSQL_LOCAL_USER="$OPT_remote_mysql_user"
fi
if [ "$OPT_local_mysql_user" ]; then
MYSQL_LOCAL_USER="$OPT_local_mysql_user"
fi
if [ "$OPT_mysql_password" ]; then
MYSQL_REMOTE_PASSWORD="$OPT_passw"
MYSQL_LOCAL_PASSWORD="$OPT_passw"
fi
if [ "$OPT_remote_mysql_password" ]; then
MYSQL_LOCAL_PASSWORD="$OPT_lpassw"
fi
if [ "$OPT_local_mysql_password" ]; then
MYSQL_LOCAL_PASSWORD="$OPT_rpassw"
fi
if [ ! "$REMOTE" ] || [ ! "$USER" ] || [ ! "$LOCAL_DB_NAME" ] || [ ! "$REMOTE_DB_NAME" ] || [ ! "$MYSQL_REMOTE_USER" ] || [ ! "$MYSQL_LOCAL_USER" ]; then
usage
exit 1
fi
if [ ! "$MYSQL_LOCAL_PASSWORD" ] || [ ! "$MYSQL_REMOTE_PASSWORD" ]; then
password
fi
pull() {
echo "Dumping database $REMOTE_DB_NAME on $REMOTE..."
ssh $USER@$REMOTE \
"mysqldump -u$MYSQL_REMOTE_USER -p$( echo "'"$MYSQL_REMOTE_PASSWORD"'" ) $REMOTE_DB_NAME > /home/$USER/$REMOTE_DB_NAME.sql && \
gzip -f /home/$USER/$REMOTE_DB_NAME.sql && \
chown $USER /home/$USER/$REMOTE_DB_NAME.sql.gz" || exit 1
echo "Receiving $REMOTE_DB_NAME.sql.gz from $USER@$REMOTE..."
scp $USER@$REMOTE:"/home/$USER/$REMOTE_DB_NAME.sql.gz" "$BASEDIR/" || exit 1
echo ""
if [ -f "$BASEDIR/$REMOTE_DB_NAME.sql.gz" ]; then
echo "Replacing database tables..."
mysqldump -u$MYSQL_LOCAL_USER -p$MYSQL_LOCAL_PASSWORD --add-drop-table --no-data $LOCAL_DB_NAME | grep ^DROP | mysql -u$MYSQL_LOCAL_USER -p$MYSQL_LOCAL_PASSWORD $LOCAL_DB_NAME || exit 1
gzip -dc < "$BASEDIR/$REMOTE_DB_NAME.sql.gz" | mysql -u$MYSQL_LOCAL_USER -p$MYSQL_LOCAL_PASSWORD $LOCAL_DB_NAME || exit 1
fi
}
push() {
echo "Dumping database $LOCAL_DB_NAME on localhost..."
mysqldump -u$MYSQL_LOCAL_USER -p$MYSQL_LOCAL_PASSWORD $LOCAL_DB_NAME > "$BASEDIR/$LOCAL_DB_NAME.sql" && \
gzip -f "$BASEDIR/$LOCAL_DB_NAME.sql" || exit 1
echo "Sending $LOCAL_DB_NAME.sql.gz to $USER@$REMOTE..."
scp "$BASEDIR/$LOCAL_DB_NAME.sql.gz" $USER@$REMOTE:"/home/$USER/" || exit 1
echo ""
ssh $USER@$REMOTE \
"if [ -f """/home/$USER/$LOCAL_DB_NAME.sql.gz""" ]; then echo """Replacing database tables...""" && \
mysqldump -u$MYSQL_REMOTE_USER -p$( echo "'"$MYSQL_REMOTE_PASSWORD"'" ) --add-drop-table --no-data $REMOTE_DB_NAME | grep ^DROP | mysql -u$MYSQL_REMOTE_USER -p$( echo "'"$MYSQL_REMOTE_PASSWORD"'" ) $REMOTE_DB_NAME && \
gzip -dc < """/home/$USER/$LOCAL_DB_NAME.sql.gz""" | mysql -u$MYSQL_REMOTE_USER -p$( echo "'"$MYSQL_REMOTE_PASSWORD"'" ) $REMOTE_DB_NAME; fi" || exit 1
}
echo ""
if [ "$ACTION" = "pull" ]; then
pull
fi
if [ "$ACTION" = "push" ]; then
push
fi
echo "Done..."
echo ""
exit 0
Edit the WordPress setup
Add the following to your wp-config.php so all uri’s get redirected to the local site.
$ cat wp-config.php
<?php
if( in_array($_SERVER['HTTP_HOST'], array('localhost', '127.0.0.1')) ){
define('WP_SITEURL', 'http://localhost/~user/');
define('WP_HOME', 'http://localhost/~user/');
define('FS_METHOD','direct');
}
/**
* The base configurations of the WordPress.
...
Finally
Add the following to your .htaccess so all media uri’s get redirected to the live site where all the original media lives.
$ cat .htaccess
...
redirect /~user/wp-content/uploads/ http://yourdomain.com/wp-content/uploads/
If you get the error: "Permission denied: /home/*/public_html/.htaccess pcfg_openfile: unable to check htaccess file, ensure it is readable"
, when directing your browser to http://localhost/~user
then do the following: sudo chmod +rx /home/*/public_html