├── .gitignore ├── README.md ├── config.php ├── hooks.php ├── paths.php ├── remote.php ├── scm.php ├── stages.php ├── tasks ├── BackupPlugins.php ├── DBPull.php ├── DBPush.php ├── Permissions.php ├── RestorePlugins.php ├── RetainPlugins.php ├── UploadsPull.php ├── UploadsPush.php └── WPConfig.php └── templates └── wp-config.tpl.php /.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Important! 2 | 3 | This is a raw-ass file I used for my private use at WCSTL and still needs some TLC. Opening up for anyone who might be eager enough to use this as a starting point. 4 | 5 | *Eventually* I will circle back and edit the tight coupling specific to what I was working with :) 6 | 7 | ## Things you will need to edit 8 | - scm.php 9 | - remote.php(wp_content_director, domain_name, db, permissions specific to your setup) 10 | - config.php(connections, local) 11 | 12 | ### Notes 13 | - This setup expects WordPress to be installed the /wp directory and all wp-content to be in the /content directory. I used YeoPress to bootstrap my install and set WordPress as a submodule "wp" 14 | - Be sure to edit the mysql_path in the local config array to match your local setup 15 | - run commands as root 16 | - point the config to your local ssh key 17 | - remember to generate an ssh key on your server and add to your repositories deploy keys so it has access to pull down 18 | -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | function ($rocketeer) { 8 | return sprintf('%s-%s-%s.log', $rocketeer->getConnection(), $rocketeer->getStage(), date('Ymd')); 9 | }, 10 | 11 | // Remote access 12 | // 13 | // You can either use a single connection or an array of connections 14 | //////////////////////////////////////////////////////////////////// 15 | 16 | // The default remote connection(s) to execute tasks on 17 | 'default' => array('production'), 18 | 19 | // The various connections you defined 20 | // You can leave all of this empty or remove it entirely if you don't want 21 | // to track files with credentials : Rocketeer will prompt you for your credentials 22 | // and store them locally 23 | 'connections' => array( 24 | 'production' => array( 25 | 'host' => 'wcstl.elemenopea.com', 26 | 'username' => 'root', 27 | 'password' => '', 28 | 'key' => '/Users/myke/.ssh/id_rsa', 29 | 'keyphrase' => '', 30 | ), 31 | ), 32 | 33 | // Contextual options 34 | // 35 | // In this section you can fine-tune the above configuration according 36 | // to the stage or connection currently in use. 37 | // Per example : 38 | // 'stages' => array( 39 | // 'staging' => array( 40 | // 'scm' => array('branch' => 'staging'), 41 | // ), 42 | // 'production' => array( 43 | // 'scm' => array('branch' => 'master'), 44 | // ), 45 | // ), 46 | //////////////////////////////////////////////////////////////////// 47 | 48 | 'on' => array( 49 | 50 | // Stages configurations 51 | 'stages' => array( 52 | ), 53 | 54 | // Connections configuration 55 | 'connections' => array( 56 | ), 57 | 58 | ), 59 | 60 | 'local' => array( 61 | 'domain_name' => 'wcstl.dev', 62 | 'db' => array( 63 | 'host' => 'localhost', 64 | 'user' => 'root', 65 | 'password' => 'password', 66 | 'name' => 'wcstl', 67 | ), 68 | 'mysql_path' => '/Applications/MAMP/Library/bin/' // Optional. May need supply a path in the event you use something like MAMP - EX: /Applications/MAMP/Library/bin/ 69 | ), 70 | 71 | ); 72 | -------------------------------------------------------------------------------- /hooks.php: -------------------------------------------------------------------------------- 1 | array( 17 | 'setup' => array(), 18 | 'deploy' => array('BackupPlugins'), 19 | 'cleanup' => array() 20 | ), 21 | 22 | // Tasks to execute after the core Rocketeer Tasks 23 | 'after' => array( 24 | 'setup' => array(), 25 | 'deploy' => array( 26 | 'Permissions', 27 | 'WPConfig' 28 | ), 29 | 'cleanup' => array(), 30 | ), 31 | 32 | // Custom Tasks to register with Rocketeer 33 | 'custom' => array( 34 | 'Permissions', 35 | 'BackupPlugins', 36 | 'RestorePlugins', 37 | 'DBPull', 38 | 'DBPush', 39 | 'WPConfig', 40 | 'UploadsPull', 41 | 'UploadsPush' 42 | ), 43 | 44 | ); 45 | -------------------------------------------------------------------------------- /paths.php: -------------------------------------------------------------------------------- 1 | '', 15 | 16 | // Path to Composer 17 | 'composer' => '', 18 | 19 | // Path to the Artisan CLI 20 | 'artisan' => '', 21 | 22 | ); 23 | -------------------------------------------------------------------------------- /remote.php: -------------------------------------------------------------------------------- 1 | array( 9 | 'directory_separator' => '/', 10 | 'line_endings' => "\n", 11 | ), 12 | 13 | // The root directory where your applications will be deployed 14 | 'root_directory' => '/var/www/', 15 | 'wp_content_director' => 'content', // relative to site root 16 | 'domain_name' => 'wcstl.elemenopea.com', 17 | 18 | // DB connection details used for pull/push as well ad wp-config generation 19 | 'db' => array( 20 | 'host' => 'localhost', 21 | 'user' => 'root', 22 | 'password' => 'password', 23 | 'name' => 'wcstl', 24 | ), 25 | 26 | // The name of the application to deploy 27 | // This will create a folder of the same name in the root directory 28 | // configured above, so be careful about the characters used 29 | 'application_name' => 'wcstl', 30 | 31 | // The number of releases to keep at all times 32 | 'keep_releases' => 4, 33 | 34 | // A list of folders/file to be shared between releases 35 | // Use this to list folders that need to keep their state, like 36 | // user uploaded data, file-based databases, etc. 37 | 'shared' => array( 38 | 'content/uploads', 39 | ), 40 | 41 | 'permissions' => array( 42 | 43 | // The folders and files to set as web writable 44 | // You can pass paths in brackets, so {path.public} will return 45 | // the correct path to the public folder 46 | 'files' => array( 47 | 'content/uploads', 48 | 'content/plugins', 49 | ), 50 | 51 | // Here you can configure what actions will be executed to set 52 | // permissions on the folder above. The Closure can return 53 | // a single command as a string or an array of commands 54 | 'callback' => function ($task, $file) { 55 | return array( 56 | sprintf('chown -R www-data:www-data %s', $file), 57 | sprintf('chmod -R g+w %s', $file), 58 | ); 59 | }, 60 | 61 | ), 62 | 63 | ); 64 | -------------------------------------------------------------------------------- /scm.php: -------------------------------------------------------------------------------- 1 | 'git', 8 | 9 | // The SSH/HTTPS address to your repository 10 | // Example: https://github.com/vendor/website.git 11 | 'repository' => 'git@github.com:mykebates/wcstl.git', 12 | 13 | // The repository credentials : you can leave those empty 14 | // if you're using SSH or if your repository is public 15 | // In other cases you can leave this empty too, and you will 16 | // be prompted for the credentials on deploy 17 | 'username' => '', 18 | 'password' => '', 19 | 20 | // The branch to deploy 21 | 'branch' => 'master', 22 | 23 | // Whether your SCM should do a "shallow" clone of the repository 24 | // or not – this means a clone with just the latest state of your 25 | // application (no history) 26 | // If you're having problems cloning, try setting this to false 27 | 'shallow' => true, 28 | 29 | ); 30 | -------------------------------------------------------------------------------- /stages.php: -------------------------------------------------------------------------------- 1 | array('production'), 12 | 13 | // The default stage to execute tasks on when --stage is not provided 14 | 'default' => 'production', 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /tasks/BackupPlugins.php: -------------------------------------------------------------------------------- 1 | rocketeer->getHomeFolder().'/'.$this->rocketeer->getStage().'/current'; 9 | $content_dir = $this->rocketeer->getOption('remote.wp_content_director'); 10 | $backup_directory = $this->rocketeer->getHomeFolder().'/'.$this->rocketeer->getStage().'/backup/plugins'; 11 | 12 | 13 | 14 | $this->command->info('Copying existing plugins to a safe location'); 15 | 16 | if(!$this->fileExists($backup_directory)) 17 | { 18 | $this->command->info('Initializing backup folder'); 19 | $this->remote->run('mkdir -p '.$backup_directory); 20 | } 21 | 22 | //$this->command->info($root_directory); 23 | 24 | $this->remote->run(array( 25 | 'cd '.$root_directory, 26 | 'cp -rf '.$content_dir.'/plugins/* '.$backup_directory 27 | )); 28 | 29 | } 30 | } 31 | ?> -------------------------------------------------------------------------------- /tasks/DBPull.php: -------------------------------------------------------------------------------- 1 | rocketeer->getStage(); 9 | 10 | $random = substr( "abcdefghijklmnopqrstuvwxyz", mt_rand(0, 25) , 1) .substr( md5( time() ), 1); 11 | $root_directory = $this->rocketeer->getHomeFolder().'/'.$this->rocketeer->getStage(); 12 | $backup_directory = $root_directory.'/'.'backup/database'; 13 | 14 | // Set DB & Remote data 15 | $local_db_host = $this->rocketeer->getOption('config.local.db.host'); 16 | $local_db_user = $this->rocketeer->getOption('config.local.db.user'); 17 | $local_db_password = $this->rocketeer->getOption('config.local.db.password'); 18 | $local_db_name = $this->rocketeer->getOption('config.local.db.name'); 19 | $local_domain_name = $this->rocketeer->getOption('config.local.domain_name'); 20 | $local_mysql_path = $this->rocketeer->getOption('config.local.mysql_path'); 21 | 22 | $remote_db_host = $this->rocketeer->getOption('remote.db.host'); 23 | $remote_db_user = $this->rocketeer->getOption('remote.db.user'); 24 | $remote_db_password = $this->rocketeer->getOption('remote.db.password'); 25 | $remote_db_name = $this->rocketeer->getOption('remote.db.name'); 26 | $remote_login_user = $this->rocketeer->getOption('config.connections.'.$stage.'.username'); 27 | $remote_login_host = $this->rocketeer->getOption('config.connections.'.$stage.'.host'); 28 | $remote_domain_name = $this->rocketeer->getOption('remote.domain_name'); 29 | 30 | $this->command->info('Dumping remote data'); 31 | 32 | if(!$this->fileExists($backup_directory)) 33 | { 34 | $this->command->info('Initializing backup folder'); 35 | $this->remote->run('mkdir -p '.$backup_directory); 36 | } 37 | 38 | 39 | $this->remote->run(array( 40 | 'touch '.$backup_directory.'/tmp.sql', 41 | 'rm '.$backup_directory.'/*.sql', 42 | 'mysqldump -u'.$remote_db_user.' -p'.$remote_db_password.' -h'.$remote_db_host.' '.$remote_db_name.' > '.$backup_directory.'/'.$random.'.sql' 43 | )); 44 | 45 | // Run locally 46 | $this->command->info('Importing on local database'); 47 | 48 | exec('mkdir -p tmp'); 49 | exec('rsync -avzO '.$remote_login_user.'@'.$remote_login_host.':'.$backup_directory.'/'.$random.'.sql tmp/dbbackup.sql'); 50 | exec("sed -i '' 's/".$remote_domain_name."/".$local_domain_name."/g' tmp/dbbackup.sql"); 51 | exec($local_mysql_path.'mysql -p'.$local_db_password.' -u '.$local_db_user.' '.$local_db_name.' < tmp/dbbackup.sql'); 52 | exec('rm -rf tmp'); 53 | } 54 | } 55 | ?> -------------------------------------------------------------------------------- /tasks/DBPush.php: -------------------------------------------------------------------------------- 1 | rocketeer->getStage(); 9 | 10 | $random = substr( "abcdefghijklmnopqrstuvwxyz", mt_rand(0, 25) , 1) .substr( md5( time() ), 1); 11 | $root_directory = $this->rocketeer->getHomeFolder().'/'.$this->rocketeer->getStage(); 12 | $backup_directory = $root_directory.'/'.'backup/database'; 13 | 14 | // Set DB & Remote data 15 | $local_db_host = $this->rocketeer->getOption('config.local.db.host'); 16 | $local_db_user = $this->rocketeer->getOption('config.local.db.user'); 17 | $local_db_password = $this->rocketeer->getOption('config.local.db.password'); 18 | $local_db_name = $this->rocketeer->getOption('config.local.db.name'); 19 | $local_domain_name = $this->rocketeer->getOption('config.local.domain_name'); 20 | $local_mysql_path = $this->rocketeer->getOption('config.local.mysql_path'); 21 | 22 | $remote_db_host = $this->rocketeer->getOption('remote.db.host'); 23 | $remote_db_user = $this->rocketeer->getOption('remote.db.user'); 24 | $remote_db_password = $this->rocketeer->getOption('remote.db.password'); 25 | $remote_db_name = $this->rocketeer->getOption('remote.db.name'); 26 | $remote_login_user = $this->rocketeer->getOption('config.connections.'.$stage.'.username'); 27 | $remote_login_host = $this->rocketeer->getOption('config.connections.'.$stage.'.host'); 28 | $remote_domain_name = $this->rocketeer->getOption('remote.domain_name'); 29 | 30 | $this->command->info('Dumping local data'); 31 | 32 | // Make sure there is backup folder on the remote server 33 | if(!$this->fileExists($backup_directory)) 34 | { 35 | $this->command->info('Initializing backup folder'); 36 | $this->remote->run('mkdir -p '.$backup_directory); 37 | } 38 | 39 | // Dump Local 40 | exec('mkdir -p tmp'); 41 | exec('rm -rf tmp/*.sql'); 42 | exec($local_mysql_path.'mysqldump -u'.$local_db_user.' -p'.$local_db_password.' -h'.$local_db_host.' '.$local_db_name.' > tmp/'.$random.'.sql'); // dump local db 43 | exec("sed -i '' 's/".$local_domain_name."/".$remote_domain_name."/g' tmp/".$random.".sql"); // find&replace domain name 44 | exec('rsync -avzO tmp/'.$random.'.sql '.$remote_login_user.'@'.$remote_login_host.':'.$backup_directory.'/import.sql'); // send to server 45 | 46 | // Import 47 | $this->command->info('Importing on remote database'); 48 | 49 | $this->remote->run(array( 50 | 'mysql -p'.$remote_db_password.' -u '.$remote_db_user.' '.$remote_db_name.' < '.$backup_directory.'/import.sql', 51 | 'rm '.$backup_directory.'/*.sql' 52 | )); 53 | } 54 | } 55 | ?> -------------------------------------------------------------------------------- /tasks/Permissions.php: -------------------------------------------------------------------------------- 1 | rocketeer->getOption('config.connections.'.$stage.'.username'); 9 | $root_directory = $this->rocketeer->getHomeFolder().'/'.$this->rocketeer->getStage().'/current'; 10 | $content_dir = $this->rocketeer->getOption('remote.wp_content_director'); 11 | 12 | $this->command->info('Setting Permissions'); 13 | // Setting up this space for potentially greater permissions handling 14 | //$this->runForCurrentRelease('chown -R www-data:www-data ../../shared/content/uploads'); 15 | 16 | } 17 | } 18 | ?> -------------------------------------------------------------------------------- /tasks/RestorePlugins.php: -------------------------------------------------------------------------------- 1 | rocketeer->getHomeFolder().'/'.$this->rocketeer->getStage().'/current'; 11 | $content_dir = $this->rocketeer->getOption('remote.wp_content_director'); 12 | $backup_directory = $this->rocketeer->getHomeFolder().'/'.$this->rocketeer->getStage().'/backup/plugins'; 13 | 14 | 15 | 16 | $this->command->info('Restoring plugins to current release'); 17 | 18 | $currentRelease = $this->releasesManager->getCurrentRelease(); 19 | $currentReleasePath = $this->releasesManager->getPathToRelease($currentRelease); 20 | 21 | if($this->fileExists($backup_directory)) 22 | { 23 | $this->remote->run(array( 24 | 'cd '.$currentReleasePath, 25 | 'cp -rf '.$backup_directory.'/* '.$content_dir.'/plugins', 26 | 'chown www-data:www-data '.$content_dir.'/plugins -R' 27 | )); 28 | } 29 | 30 | else 31 | { 32 | $this->command->info('Nothing to restore'); 33 | } 34 | 35 | } 36 | } 37 | ?> -------------------------------------------------------------------------------- /tasks/RetainPlugins.php: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /tasks/UploadsPull.php: -------------------------------------------------------------------------------- 1 | rocketeer->getStage(); 9 | 10 | $root_directory = $this->rocketeer->getHomeFolder().'/'.$this->rocketeer->getStage(); 11 | $content_dir = $this->rocketeer->getOption('remote.wp_content_director'); 12 | 13 | $remote_login_user = $this->rocketeer->getOption('config.connections.'.$stage.'.username'); 14 | $remote_login_host = $this->rocketeer->getOption('config.connections.'.$stage.'.host'); 15 | 16 | // Run locally 17 | // might still need to do some checking here to see if directoris exist before running 18 | $this->command->info('Pulling uploads'); 19 | exec('rsync -avzhkO '.$remote_login_user.'@'.$remote_login_host.':'.$root_directory.'/current/'.$content_dir.'/uploads '.$content_dir.'/'); 20 | } 21 | } 22 | ?> -------------------------------------------------------------------------------- /tasks/UploadsPush.php: -------------------------------------------------------------------------------- 1 | rocketeer->getStage(); 9 | 10 | $root_directory = $this->rocketeer->getHomeFolder().'/'.$this->rocketeer->getStage().'/current'; 11 | $content_dir = $this->rocketeer->getOption('remote.wp_content_director'); 12 | 13 | $remote_login_user = $this->rocketeer->getOption('config.connections.'.$stage.'.username'); 14 | $remote_login_host = $this->rocketeer->getOption('config.connections.'.$stage.'.host'); 15 | 16 | // Run locally 17 | // might still need to do some checking here to see if directoris exist before running 18 | $this->command->info('Pushing uploads'); 19 | 20 | exec('rsync --update -avzhLK --progress --omit-dir-times '.$content_dir.'/uploads '.$remote_login_user.'@'.$remote_login_host.':'.$root_directory.'/'.$content_dir.'/'); // send to server 21 | 22 | 23 | 24 | // Hope to find a way around not using sudo here, but when syncing the files up it is important to not get any of the file owndership residue 25 | // For now, leaving as is 26 | //$this->command->info('Updating permissions'); 27 | // $this->remote->run(array( 28 | // 'cd '.$root_directory.'/'.$content_dir, 29 | // 'chown -R '.$remote_login_user.':www-data uploads', 30 | // )); 31 | $this->runForCurrentRelease('chown -R www-data:www-data ../../shared/content/uploads'); 32 | 33 | 34 | $this->command->info('Complete'); 35 | } 36 | } 37 | ?> 38 | -------------------------------------------------------------------------------- /tasks/WPConfig.php: -------------------------------------------------------------------------------- 1 | rocketeer->getStage(); 9 | $remote_db_host = $this->rocketeer->getOption('remote.db.host'); 10 | $remote_db_user = $this->rocketeer->getOption('remote.db.user'); 11 | $remote_db_password = $this->rocketeer->getOption('remote.db.password'); 12 | $remote_db_name = $this->rocketeer->getOption('remote.db.name'); 13 | $remote_login_user = $this->rocketeer->getOption('config.connections.'.$stage.'.username'); 14 | $remote_login_host = $this->rocketeer->getOption('config.connections.'.$stage.'.host'); 15 | $remote_domain_name = $this->rocketeer->getOption('remote.domain_name'); 16 | 17 | $root_directory = $this->rocketeer->getHomeFolder().'/'.$this->rocketeer->getStage().'/current'; 18 | 19 | $this->command->info('Generating wp-config.php'); 20 | 21 | exec('rsync -avzkO .rocketeer/templates/wp-config.tpl.php '.$remote_login_user.'@'.$remote_login_host.':'.$root_directory.'/wp-config.php'); // send to server 22 | 23 | $this->remote->run(array( 24 | 'cd '.$root_directory, 25 | "sed -i 's/{{DB_NAME}}/".$remote_db_name."/g' wp-config.php", 26 | "sed -i 's/{{DB_USER}}/".$remote_db_user."/g' wp-config.php", 27 | "sed -i 's/{{DB_PASSWORD}}/".$remote_db_password."/g' wp-config.php", 28 | "sed -i 's/{{DB_HOST}}/".$remote_db_host."/g' wp-config.php" 29 | )); 30 | } 31 | } 32 | ?> -------------------------------------------------------------------------------- /templates/wp-config.tpl.php: -------------------------------------------------------------------------------- 1 | +E@J;9];,V[e5Z-BH=> %J*&g!G!k]UM]n.=(m`%u$)='); 58 | define('LOGGED_IN_KEY', 'su-?W-GX6-dJ9e%#|CSx7g/Y=7OLy-7*{:1qfah-thQ|8|0nA#Qc!h@x1Nj|4E4p'); 59 | define('NONCE_KEY', 'jFdq UdiPg)Xw=XCu28.*x69yn*5&+57[)6O9co.,o7!^X(|D7QXXDI|:h^V@*]M*V%l$^75ww|UR]r:E0#8S3a!Cx{R@7_X!oux(:m='); 61 | define('SECURE_AUTH_SALT', 'k0%f5g/OsN=4-EM+.&{8O77. Z;WQbv(%26j]s|XbX# hSB.wC1#E7Z4PFJJ]*)l'); 62 | define('LOGGED_IN_SALT', '&/_2-=[RPS[|a-bP@}y?04x:=ts0!VZ^B1f=hf2+Dhngwjp?|qzNQg3x3p5c@G0}'); 63 | define('NONCE_SALT', '6C`TX)NMIjZIs4V!|CQAl88$/GO%~Doc~X,r#y/hr9JlH~w>|f)@K:jIfV8w0_~~'); 64 | 65 | /**#@-*/ 66 | 67 | /** 68 | * WordPress Database Table prefix. 69 | * 70 | * You can have multiple installations in one database if you give each a unique 71 | * prefix. Only numbers, letters, and underscores please! 72 | */ 73 | $table_prefix = 'wp_'; 74 | 75 | /** 76 | * WordPress Localized Language, defaults to English. 77 | * 78 | * Change this to localize WordPress. A corresponding MO file for the chosen 79 | * language must be installed to wp-content/languages. For example, install 80 | * de_DE.mo to wp-content/languages and set WPLANG to 'de_DE' to enable German 81 | * language support. 82 | */ 83 | define('WPLANG', ''); 84 | 85 | /** 86 | * Set custom paths 87 | * 88 | * These are required because wordpress is installed in a subdirectory. 89 | */ 90 | if (!defined('WP_SITEURL')) { 91 | define('WP_SITEURL', 'http://' . $_SERVER['SERVER_NAME'] . '/wp'); 92 | } 93 | if (!defined('WP_HOME')) { 94 | define('WP_HOME', 'http://' . $_SERVER['SERVER_NAME'] . ''); 95 | } 96 | if (!defined('WP_CONTENT_DIR')) { 97 | define('WP_CONTENT_DIR', dirname(__FILE__) . '/content'); 98 | } 99 | if (!defined('WP_CONTENT_URL')) { 100 | define('WP_CONTENT_URL', 'http://' . $_SERVER['SERVER_NAME'] . '/content'); 101 | } 102 | 103 | 104 | /** 105 | * For developers: WordPress debugging mode. 106 | * 107 | * Change this to true to enable the display of notices during development. 108 | * It is strongly recommended that plugin and theme developers use WP_DEBUG 109 | * in their development environments. 110 | */ 111 | if (!defined('WP_DEBUG')) { 112 | define('WP_DEBUG', false); 113 | } 114 | 115 | /* That's all, stop editing! Happy blogging. */ 116 | 117 | /** Absolute path to the WordPress directory. */ 118 | if ( !defined('ABSPATH') ) 119 | define('ABSPATH', dirname(__FILE__) . '/'); 120 | 121 | /** Sets up WordPress vars and included files. */ 122 | require_once(ABSPATH . 'wp-settings.php'); 123 | --------------------------------------------------------------------------------