├── .ebextensions └── project.config ├── .gitignore ├── Dockerfile ├── README.md ├── build.local.properties.sample ├── build.properties ├── build.xml ├── composer.json ├── data ├── README.md └── db │ └── README.md ├── docker-compose.yml ├── nginx ├── conf.d │ └── default.conf └── conf │ └── nginx.conf ├── php ├── php.ini └── upload.ini ├── scripts └── htaccess-no-bot.sh ├── tests ├── behat.local.yml.sample ├── behat.params.yml ├── behat.params.yml.sample ├── behat.yml └── features │ ├── bootstrap │ └── FeatureContext.php │ └── homepage.feature ├── wp-content ├── plugins │ └── README.md └── themes │ └── README.md └── wp-root ├── .htaccess ├── README.md └── wp-config.php /.ebextensions/project.config: -------------------------------------------------------------------------------- 1 | files: 2 | "/etc/php.d/wordpress.ini" : 3 | mode: "000644" 4 | owner: root 5 | group: root 6 | content: | 7 | upload_max_filesize = 128M 8 | post_max_size = 64M 9 | 10 | files: 11 | "/opt/elasticbeanstalk/hooks/appdeploy/pre/99_wp_setup.sh": 12 | mode: "000755" 13 | owner: root 14 | group: root 15 | content: | 16 | #!/usr/bin/env bash 17 | su - webapp -s /bin/bash -c "env ; id ; cd /var/app/ondeck ; ./vendor/bin/phing setup" 18 | container_commands: 19 | SetupWp: 20 | command: "/opt/elasticbeanstalk/hooks/appdeploy/pre/99_wp_setup.sh" 21 | ignoreErrors: false 22 | leader_only: true 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | nbproject 2 | ._* 3 | .~lock.* 4 | .buildpath 5 | .DS_Store 6 | .idea 7 | .project 8 | .settings 9 | vendor/ 10 | public/vendor/ 11 | .vagrant 12 | build.local.properties 13 | phinx.yml 14 | composer.phar 15 | wp-admin/ 16 | wp-includes/ 17 | wp/* 18 | !wp-config.php 19 | xmlrpc.php 20 | license.txt 21 | readme.html 22 | wp/ 23 | data/*.sql 24 | updraft 25 | wp-content/plugins 26 | wp-content/themes 27 | *.local.* 28 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.0-fpm 2 | RUN docker-php-ext-install mysqli && docker-php-ext-install pdo_mysql 3 | RUN sed -ri 's/^www-data:x:33:33:/www-data:x:1000:50:/' /etc/passwd 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://status.continuousphp.com/git-hub/continuousdemo/wordpress-eb-demo?token=685bd047-749e-40c5-9678-7dc1048c2308)](https://continuousphp.com/git-hub/continuousdemo/wordpress-eb-demo) 2 | 3 | # WordPress Docker Development with Deployment on AWS Elastic Beanstalk 4 | 5 | - [Introduction](#introduction) 6 | - [Requirements](#requirements) 7 | - [Set-up your Development environment](#set-up-your-development-environment) 8 | - [Prepare your WordPress Repository](#prepare-your-wordpress-repository) 9 | - [Dependencies management with composer](#dependencies-management-with-composer) 10 | - [Phing environment variables](#phing-environment-variables) 11 | - [Configuring Wordpress](#configuring-wordpress) 12 | - [Starting docker-compose](#starting-docker-compose) 13 | - [Initializing the Database](#initializing-the-database) 14 | - [WordPress Base Install](#wordpress-base-install) 15 | - [Configuring your development environment](#configuring-your-development-environment) 16 | - [Plugin Installation](#plugin-installation) 17 | - [Running the behat tests](#running-behat-tests) 18 | - [Themes Installation](#themes-installation) 19 | - [Developing a dumy plugin](#developing-a-dumy-plugin) 20 | - [Set-up AWS Elastic BeanStalk Staging environment](#set-up-aws-elastic-beanstalk-staging-environment) 21 | - [Set-up the AWS environment accounts](#set-up-the-aws-environment-accounts) 22 | - [Set-up the WordPress backup S3 bucket](#set-up-the-wordpress-backup-s3-bucket) 23 | - [Set-up the WordPress backup S3 bucket IAM policy](#set-up-the-wordpress-backup-s3-bucket-iam-policy) 24 | - [Configuring the UpdraftPlus WordPress plugin](#configuring-the-updraftplus-wordpress-plugin) 25 | - [Creating the EC2 Key Pair](#creating-the-ec2-key-pair) 26 | - [Creating the MySQL DB Instance](#creating-the-mysql-db-instance) 27 | - [Set-up your Elastic BeanStalk Application](#set-up-your-elastic-beanstalk-application) 28 | - [Create your Staging Application Environment](#create-your-staging-application-environment) 29 | - [Configuring the DocumentRoot](#configuring-the-documentroot) 30 | - [Configuring the WordPress Site URL](#configuring-the-wordpress-site-url) 31 | - [Adding the EC2 Security Group to your RDS Database](#Adding-the-ec2-security-group-to-your-rds-database) 32 | - [Set up the IAM permissions](#set-up-the-iam-permissions) 33 | - [Set-up continuousphp](#set-up-continuousphp) 34 | - [Application Project Set-up in continuousphp](#application-project-set-up-in-continuousphp) 35 | - [Deployment pipeline Configuration](#deployment-pipeline-configuration) 36 | - [Deploying Wordpress](#deploying-wordpress) 37 | - [Notes](#notes) 38 | 39 | ## Introduction 40 | 41 | Have you ever been scared on clicking on that WordPress or plugins update button ? 42 | 43 | Have you ever wanted to have a staging environement for the validation of your latest development by your customers and to update the production with one push upon validation ? 44 | 45 | Have you ever wanted to have automated test to ensure proper site function before deployments ? 46 | 47 | The goal of this project is to have a WordPress environment that let you develop, test, package and deploy an immutable WordPress on different environments like staging and production. 48 | 49 | It is based on docker-compose for the local development, [continuousphp](https://continuousphp.com) for building, testing and deploying on AWS Elastic BeanStalk Infrastructure environments. 50 | 51 | So let's start! 52 | 53 | ## Requirements 54 | 55 | * docker 56 | * docker-compose 57 | * composer 58 | * AWS account 59 | 60 | ## Set-up your Development environment 61 | 62 | ### Prepare your WordPress Repository 63 | 64 | Fork and clone the [WordPress Elastic BeanStalk Demo](https://github.com/continuousdemo/wordpress-eb-demo). 65 | 66 | Because we are going to configure continuousphp in staging environment, we need to create a develop branch, for which we will create a deployment pipeline. 67 | 68 | Create the **develop** branch: 69 | 70 | ```bash 71 | git checkout -B develop 72 | git push origin develop 73 | ``` 74 | 75 | This WordPress Repository include the following files: 76 | 77 | * [composer.json](https://github.com/continuousdemo/wordpress-eb-demo/blob/master/composer.json) with our WordPress dependencies 78 | * [build.xml](https://github.com/continuousdemo/wordpress-eb-demo/blob/master/build.xml) with the phing targets 79 | * [build.properties](https://github.com/continuousdemo/wordpress-eb-demo/blob/master/build.properties) with our Phing property file 80 | * [scripts](https://github.com/continuousdemo/wordpress-eb-demo/blob/master/scripts/) with our provisioning scripts 81 | * [wp-content](https://github.com/continuousdemo/wordpress-eb-demo/blob/master/wp-content/) with our custom WordPress content 82 | * [wp-root](https://github.com/continuousdemo/wordpress-eb-demo/blob/master/wp-root/) with our root configuration WordPress content 83 | * [.ebextensions/project.config](https://github.com/continuousdemo/wordpress-eb-demo/blob/master/.ebextensions/project.config) with the Elastic BeanStalk provisioning script. 84 | * [Dockerfile](https://github.com/continuousdemo/wordpress-eb-demo/blob/master/Dockerfile) with our Docker file 85 | * [docker-compose.yml](https://github.com/continuousdemo/wordpress-eb-demo/blob/master/docker-compose.yml) with docker-compose configuration file 86 | * [nginx](https://github.com/continuousdemo/wordpress-eb-demo/blob/master/nginx/) with nginx configuration files 87 | * [php](https://github.com/continuousdemo/wordpress-eb-demo/blob/master/php/) with php configuration files 88 | * [behat.yml](https://github.com/continuousdemo/wordpress-eb-demo/blob/master/tests/behat.yml) with the Behat configuration 89 | 90 | These are key files to set-up your WordPress installation, development and deployment environement. Feel free to take a look at them to get a better understanding. 91 | 92 | ### Dependencies management with composer 93 | 94 | Install Wordpress and plugins using composer like: 95 | 96 | ``` 97 | composer.phar install 98 | ``` 99 | 100 | ### Phing environment variables 101 | 102 | To set your local development environment copy the **build.local.properties.sample** to **build.local.properties**. 103 | 104 | ``` 105 | cp build.local.properties.sample build.local.properties 106 | ``` 107 | 108 | ### Create the develop symlinks 109 | 110 | Create the symlinks to enable plugins and themes in development mode: 111 | 112 | ``` 113 | ./vendor/bin/phing wp-symlink-plugins 114 | ./vendor/bin/phing wp-symlink-themes 115 | ``` 116 | 117 | Most of the WP plugins can be found on [wordpress packagist](https://wpackagist.org/), add them to your composer.json like: 118 | 119 | ``` 120 | "require": { 121 | "php": ">=7.0", 122 | "johnpbloch/wordpress": ">=4.7.2", 123 | "composer/installers": "~1.0", 124 | "wpackagist-plugin/contact-form-7": "4.6.1", 125 | "wpackagist-plugin/business-profile": "1.1.1", 126 | "robmorgan/phinx": "~0.6.0", 127 | "wp-cli/wp-cli": "^1.0", 128 | "phing/phing": "~2.14" 129 | }, 130 | ``` 131 | 132 | ### Configuring Wordpress 133 | 134 | ``` 135 | cp wp/wp-config-sample.php wp/wp-config.php 136 | ``` 137 | Edit the wp/wp-config.php file and set WP configuration variables using $_SERVER environment variables as below, we do this to be able to provision the WP configuration for the differents environments like develop, staging and production. 138 | 139 | ``` 140 | /** The name of the database for WordPress */ 141 | define('DB_NAME', $_SERVER["MYSQL_ADDON_DB"]); 142 | 143 | /** MySQL database username */ 144 | define('DB_USER', $_SERVER["MYSQL_ADDON_USER"]); 145 | 146 | /** MySQL database password */ 147 | define('DB_PASSWORD', $_SERVER["MYSQL_ADDON_PASSWORD"]); 148 | 149 | /** MySQL hostname */ 150 | define('DB_HOST', $_SERVER["MYSQL_ADDON_HOST"]); 151 | 152 | /** Database Charset to use in creating database tables. */ 153 | define('DB_CHARSET', 'utf8'); 154 | 155 | /** The Database Collate type. Don't change this if in doubt. */ 156 | define('DB_COLLATE', ''); 157 | ``` 158 | 159 | and add: 160 | 161 | ``` 162 | define('AUTH_KEY', $_SERVER["AUTH_KEY"]); 163 | define('SECURE_AUTH_KEY', $_SERVER["SECURE_AUTH_KEY"]); 164 | define('LOGGED_IN_KEY', $_SERVER["LOGGED_IN_KEY"]); 165 | define('NONCE_KEY', $_SERVER["NONCE_KEY"]); 166 | define('AUTH_SALT', $_SERVER["AUTH_SALT"]); 167 | define('SECURE_AUTH_SALT', $_SERVER["SECURE_AUTH_SALT"]); 168 | define('LOGGED_IN_SALT', $_SERVER["LOGGED_IN_SALT"]); 169 | define('NONCE_SALT', $_SERVER["NONCE_SALT"]); 170 | ``` 171 | 172 | Once finished, copy the wp/wp-config.php in the wp-root/ folder, we will need it for the deployment provisioning. 173 | 174 | ``` 175 | cp wp/wp-config.php wp-root/ 176 | ``` 177 | 178 | Let's export the environment variables for our development environment: 179 | 180 | ``` 181 | export MYSQL_ADDON_HOST=192.168.99.100 182 | export MYSQL_ADDON_DB=wordpress 183 | export MYSQL_ADDON_PASSWORD=password 184 | export MYSQL_ADDON_USER=root 185 | export S3_BACKUP_URL= 186 | export S3_MEDIA_URL= 187 | export environment=develop 188 | ``` 189 | 190 | If you plan to use the WordPress Security Keys (which we recommend), [generate the keys](https://api.wordpress.org/secret-key/1.1/salt/) and export them: 191 | 192 | ``` 193 | export AUTH_KEY="" 194 | export SECURE_AUTH_KEY="" 195 | export LOGGED_IN_KEY="" 196 | export NONCE_KEY="" 197 | export AUTH_SALT="" 198 | export SECURE_AUTH_SALT="" 199 | export LOGGED_IN_SALT="" 200 | export NONCE_SALT="" 201 | ``` 202 | 203 | Keep those keys in a safe place. 204 | 205 | ### Starting docker-compose 206 | 207 | ``` 208 | docker-compose up 209 | ``` 210 | 211 | Note: if you don't daemonize the docker-compose, you will need to open a new terminal, don't forget to export again your environment variables. 212 | 213 | #### Initializing the Database 214 | 215 | Now let's initialize our WP database. 216 | 217 | ``` 218 | ./vendor/bin/phing reset-db 219 | ``` 220 | 221 | #### WordPress Base Install 222 | 223 | Open in your browser http://192.168.99.100/wp-admin/install.php to install your WordPress. 224 | 225 | Complete the information: 226 | 227 | * Site Title: Your site title 228 | * Username: **admin** 229 | * Search Engine Visibility: Check discourage search engines from indexing this site 230 | * Click **Install WordPress** 231 | 232 | Your WordPress is now ready to be customized. 233 | 234 | Note: you may recieve a 500 Error because a phpmailerException, just refresh the page. 235 | 236 | ### Configuring your development environment 237 | 238 | ``` 239 | ./vendor/bin/phing setup-dev 240 | ``` 241 | 242 | Note: don't worry about the wp-get-s3-backup and wp-get-s3-media target that fail, we will use them later on. 243 | 244 | #### Plugin Installation 245 | 246 | We are going to add a few plugins. 247 | 248 | * Updraftplus to backup our wordpress assets on S3. 249 | * The w3-total-cache Search Engine and Performance Optimization plugin 250 | 251 | For this we add the "wpackagist-plugin/updraftplus" and "wpackagist-plugin/w3-total-cache" dependencies in our composer.json file like: 252 | 253 | ``` 254 | "require": { 255 | "php": ">=7.0", 256 | "johnpbloch/wordpress": ">=4.7.2", 257 | "composer/installers": "~1.0", 258 | "wpackagist-plugin/contact-form-7": "4.6.1", 259 | "wpackagist-plugin/business-profile": "1.1.1", 260 | "wpackagist-plugin/updraftplus": "1.12.32", 261 | "wpackagist-plugin/w3-total-cache": "0.9.5.1", 262 | "robmorgan/phinx": "~0.6.0", 263 | "wp-cli/wp-cli": "^1.0", 264 | "phing/phing": "~2.14" 265 | }, 266 | ``` 267 | 268 | Edit the **build.properties** and add our new plugins into the wp.plugins variables, this varibales is used by the Phing target wp-plugins-activate. 269 | 270 | ``` 271 | wp.plugins=business-profile,contact-form-7,updraftplus,w3-total-cache 272 | ``` 273 | 274 | Do the same to your **build.local.properties**. 275 | 276 | Run a composer update to install the plugin. 277 | 278 | ``` 279 | composer.phar update 280 | ``` 281 | 282 | Then activate the plugins: 283 | 284 | ``` 285 | ./vendor/bin/phing wp-plugins-activate 286 | ``` 287 | 288 | Open in your browser http://192.168.99.100/wp-admin/plugins.php the updraftplus plugin is installed and activated. Note that the password for the **admin** user is **password**, we have updated it so we can run automated test. 289 | 290 | Notice all the plugin are installed and activated, but wait a minute, we W3 Total Cache that require an update, let's edit our composer.json and bump the version. 291 | 292 | Get the latest version at [WordPress Packagist](https://wpackagist.org/search?q=w3-total-cache&type=any&search=) 293 | 294 | ``` 295 | "wpackagist-plugin/w3-total-cache": "0.9.5.2", 296 | ``` 297 | 298 | Run composer update and refresh the plugin page, our plugin is up to date! 299 | 300 | ``` 301 | composer.phar update 302 | ``` 303 | 304 | If you need to install a Plugin which isn't available on WordPress Packagist or that you have to build a custom plugin, add it into the project root in wp-content folder, it is symlinked into the WordPress install, so you can develop or make it available to WordPress. 305 | 306 | #### Running the behat tests 307 | 308 | To run the behat test locally first, copy the **behat.local.yml.sample** to **behat.local.yml** 309 | 310 | ``` 311 | cp tests/behat.local.yml.sample tests/behat.local.yml 312 | ``` 313 | 314 | Then run behat with: 315 | 316 | ``` 317 | ./vendor/bin/behat -c tests/behat.local.yml 318 | ``` 319 | 320 | #### Themes Installation 321 | 322 | Now let's install a theme, we do the same, adding it to our **composer.json** and run ```composer update```. 323 | 324 | ``` 325 | "wpackagist-theme/vanilla": "1.3.5" 326 | ``` 327 | 328 | Update the theme in the **build.properties** and **build.local.properties** 329 | 330 | ``` 331 | wp.theme=vanilla 332 | ``` 333 | 334 | And let's activate it: 335 | 336 | ``` 337 | ./vendor/bin/phing wp-theme-activate 338 | ``` 339 | 340 | Let's change our behat test by editing the **tests/features/homepage.feature** file with: 341 | 342 | ``` 343 | @home 344 | Feature: As a visitor I should be able to load the home page 345 | 346 | Scenario: Home page loads 347 | Given I am on the homepage 348 | Then I should see **"Just another WordPress site"** 349 | ``` 350 | 351 | and run behat again: 352 | 353 | ``` 354 | ./vendor/bin/behat -c tests/behat.local.yml 355 | ``` 356 | 357 | We have now "Just another WordPress site"! 358 | 359 | Now, let's develop a dummy-plugin. 360 | 361 | #### Developing a dumy plugin 362 | 363 | Let's develop a dumy plugin to show how it works, for this we create a dumy-plugin plugin into the root wp-content/plugins. 364 | 365 | ``` 366 | mkdir ./wp-content/plugins/dumy-plugin 367 | cd ./wp-content/plugins/dumy-plugin 368 | ``` 369 | 370 | And add a **dumy-plugin.php** file with the following: 371 | 372 | ``` 373 | 383 | ``` 384 | 385 | Open your browser to http://192.168.99.100/wp-admin/plugins.php and your plugin is displayed. 386 | 387 | Add it to your **build.properties** and **build.local.properties**: 388 | 389 | ``` 390 | wp.plugins=business-profile,contact-form-7,updraftplus,w3-total-cache,wordpress-https,dumy-plugin 391 | ``` 392 | 393 | And let's activate it: 394 | 395 | ``` 396 | ./vendor/bin/phing wp-plugins-activate 397 | ``` 398 | 399 | Same apply to the theme development. **Be sure to only commit your themes and plugins of the root wp-content folder, not the ones installed by composer**. 400 | 401 | So we have our base WordPress development ready, now we are going to create our staging environment on AWS Elastic BeanStalk. 402 | 403 | ## Set-up AWS Elastic BeanStalk Staging environment 404 | 405 | ### Set-up the AWS environment accounts 406 | 407 | AWS recommends the separation of responsibilities, and therefore you should create a separate AWS account for every environment you might require. 408 | 409 | This tutorial explains Wordpress deployment in a **staging** environment. 410 | 411 | So let's start and create an AWS account for your staging environment. 412 | 413 | **Set up a new account:** 414 | 415 | 1. Open [https://aws.amazon.com/](https://aws.amazon.com/), and then choose *Create an AWS Account*. 416 | 2. Follow the online instructions. 417 | 418 | ### Set-up the WordPress backup S3 bucket 419 | 420 | Let's first create an S3 bucket for your WP backup. 421 | 422 | **Create the backup bucket** 423 | 424 | 1. Sign-in to the AWS Management Console and open the Amazon S3 console at https://console.aws.amazon.com/s3. 425 | 2. Click *Create Bucket*. 426 | 3. In the *Create a Bucket* dialog box, fill in the *Bucket Name*. In this example we will use **"my-wordpress-site-backup"**. 427 | 4. In the *Region* box, select a region from the drop-down list. 428 | 5. Click Create. 429 | 430 | When Amazon S3 has successfully created your bucket, the console displays your empty bucket **"my-wordpress-site-backup"** in the Bucket panel. 431 | 432 | Let's configure the Bucket Polocy. 433 | 434 | **Configuring the bucket policy** 435 | 436 | 1. Open the **my-wordpress-site-backup** bucket properties. 437 | 2. Goto **Permissions** 438 | 3. Select the **Bucket Policy** and add: 439 | 440 | ``` 441 | { 442 | "Version": "2012-10-17", 443 | "Statement": [ 444 | { 445 | "Sid": "PublicReadGetObject", 446 | "Effect": "Allow", 447 | "Principal": { 448 | "AWS": "*" 449 | }, 450 | "Action": "s3:GetObject", 451 | "Resource": "arn:aws:s3:::my-wordpress-site-backup/*" 452 | } 453 | ] 454 | } 455 | ``` 456 | 457 | Note: To get your account ID goto on the AWS My Account. 458 | 459 | ### Set-up the WordPress backup S3 bucket IAM policy 460 | 461 | Let's create an IAM policy to grant UpdraftPlus plugin the permission to upload the backups to your backup S3 bucket. 462 | 463 | **Create the policy** 464 | 465 | 1. Sign-in to the IAM console at https://console.aws.amazon.com/iam/ with your user that has administrator permissions. 466 | 2. In the navigation pane, choose *Policies*. 467 | 3. In the content pane, choose *Create Policy*. 468 | 4. Next to *Create Your Own Policy*, choose *Select*. 469 | 5. As *Policy Name*, type **my-wordpress-site-backup**. 470 | 6. As *Policy Document*, paste the following policy. 471 | 472 | ``` 473 | { 474 | "Version": "2012-10-17", 475 | "Statement": [ 476 | { 477 | "Effect": "Allow", 478 | "Action": [ 479 | "s3:ListBucket", 480 | "s3:GetBucketLocation", 481 | "s3:ListBucketMultipartUploads" 482 | ], 483 | "Resource": "arn:aws:s3:::my-wordpress-site-backup", 484 | "Condition": {} 485 | }, 486 | { 487 | "Effect": "Allow", 488 | "Action": [ 489 | "s3:AbortMultipartUpload", 490 | "s3:DeleteObject", 491 | "s3:DeleteObjectVersion", 492 | "s3:GetObject", 493 | "s3:GetObjectAcl", 494 | "s3:GetObjectVersion", 495 | "s3:GetObjectVersionAcl", 496 | "s3:PutObject", 497 | "s3:PutObjectAcl", 498 | "s3:PutObjectAclVersion" 499 | ], 500 | "Resource": "arn:aws:s3:::my-wordpress-site-backup/*", 501 | "Condition": {} 502 | }, 503 | { 504 | "Effect": "Allow", 505 | "Action": "s3:ListAllMyBuckets", 506 | "Resource": "*", 507 | "Condition": {} 508 | } 509 | ] 510 | } 511 | ``` 512 | 7\. Choose *Validate Policy* and ensure that no errors display in a red box at the top of the screen. Correct any that are reported. 513 | 514 | 8\. Choose *Create Policy*. 515 | 516 | Now let's create an IAM user with an Access Key and attach the policy we've just created. 517 | 518 | **Create a new User and attach the User policy** 519 | 520 | 1. Sign-in to the Identity and Access Management (IAM) console at https://console.aws.amazon.com/iam/. 521 | 2. In the navigation pane, choose *Users* and then choose *Create New Users*. 522 | 3. Enter the following user: **my-wordpress-site-backup** 523 | 4. Select **Programmatic access** then click Next 524 | 5. Select **Attach existing policies directly** 525 | 6. Search for the policy we just made: **my-wordpress-site-backup** 526 | 7. Click Next the Create User 527 | 8. **Save the generated access key in a safe place**. 528 | 9. Choose *Close*. 529 | 530 | ### Configuring the UpdraftPlus WordPress plugin 531 | 532 | We are now going to configure the UpdraftPlus WordPress plugin. We use this plugin to keep a backup of our database and media files, so we can restore any of our environment from any backup. 533 | 534 | Open your browser to http://192.168.99.100/wp-admin/plugins.php 535 | 536 | 1. Open the settings page of the UpdraftPlus plugin 537 | 2. Goto the Settings Tab and configure the Backup settings: 538 | * File Backup schedule: Daily and retain this many scheduled backups: 15 Days 539 | * Database backup schedule: Daily and retain this many scheduled backups: 15 Days 540 | * Remote storage: Amazon S3 541 | * S3 access key: \ 542 | * S3 secret key: \ 543 | * S3 location: my-wordpress-site-backup/ 544 | 3. Click on **Test S3 Settings** 545 | 4. Click on **Save Changes** 546 | 5. Goto the Current Status Tab 547 | 6. Click on **Backup Now**, ensure all checks are checked. 548 | 549 | Note: If you have an error with updraft folder is not writtable, create the folder and give it permission: ```mkdir wp/wp-content/updraft ; chmod 777 wp/wp-content/updraft``` 550 | 551 | UpdraftPlus Backup ensure we keep your WordPress state up to date on all environments and be able to restore a version if needed. 552 | 553 | Let's open our S3 Backup Bucket my-wordpress-site-backup and get the latest DB backup filename to set our **build.local.properties** file with the s3_backup_url value. 554 | 555 | ``` 556 | s3_backup_url=s3://my-wordpress-site-backup/backup_2017-02-16-1006_My_WP_site_1437f9fb506f-db.gz 557 | ``` 558 | 559 | Let's configure our AWS cli profile using the S3 Bucket user: 560 | 561 | ``` 562 | aws configure --profile=my-wordpress-site 563 | AWS Access Key ID [None]: XXXXXXXXXXXXXXXXXX 564 | AWS Secret Access Key [None]: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 565 | Default region name [None]: eu-central-1 566 | Default output format [None]: 567 | ``` 568 | 569 | And let's rebuild our development environment: 570 | 571 | ``` 572 | AWS_DEFAULT_PROFILE=my-wordpress-site ./vendor/bin/phing setup-dev 573 | ``` 574 | 575 | As you can see now the wp-get-s3-backup get our backup and reinstall our WordPress database with the db-migration target, this enable us to make changes to our WordPress, make a backup and restore its state for all our environments. 576 | 577 | Let's do a test, add a page to our WordPress, make a backup, update the build.local.properties with the new WordPress database backup url and run the **setup-dev** phing target. 578 | 579 | Now let's continue to set our AWS Elastic BeanStalk environment. 580 | 581 | ### Creating the EC2 Key Pair 582 | 583 | To create your key pair using the Amazon EC2 console 584 | 585 | 1. Open the Amazon EC2 console at https://console.aws.amazon.com/ec2/. 586 | 2. In the navigation pane, under *NETWORK & SECURITY*, choose *Key Pairs*. 587 | 3. Enter a name for the new key pair in the Key pair name field of the *Create Key Pair* dialog box, and then choose *Create*. 588 | The private key file is automatically downloaded by your browser. The base file name is the name you specified as the name of your key pair, and the file name extension is *.pem*. Save the private key file in a safe place. 589 | 4. If you will use an SSH client on a Mac or Linux computer to connect to your Linux instance, use the following command to set the permissions of your private key file so that only you can read it : 590 | 591 | ```bash 592 | chmod 400 my-key-pair.pem 593 | ``` 594 | 595 | ### Creating the MySQL DB Instance 596 | 597 | 1. Sign in to the AWS Management Console and open the Amazon RDS console at https://console.aws.amazon.com/rds/. 598 | 2. In the top right corner of the Amazon RDS console, choose the region in which you want to create the DB instance. 599 | 3. In the navigation pane, choose Instances. 600 | 4. Choose Launch DB Instance. The Launch DB Instance Wizard opens on the Select Engine page. 601 | 5. On the Select Engine page, choose the MySQL icon and then choose Select for the MySQL DB engine for Dev/Test. 602 | 6. On the Specify DB Details page, specify your DB instance information. 603 | * DB Instance Class: db.t2.micro 604 | * Multi-AZ Deployment: No (We are in staging) 605 | * Allocated Storage: 5 GB 606 | * Storage Type: Magnetic 607 | * DB Instance Identifier: staging-my-wordpress-site-db 608 | * Master Username: wordpress_userdb 609 | * Master Password: \ 610 | * VPC: Select the default VPC 611 | * Publicly Accessible: No 612 | * VPC Security Group(s): Create New Security Group 613 | * Database Name: staging_my_wordpress_site_db 614 | * Backup Retention Period: 1 615 | * Auto Minor Version Upgrade: Yes 616 | 7. Click on **Launch DB Instance** 617 | 618 | ### Set-up your Elastic BeanStalk Application 619 | 620 | **To create a new application** 621 | 622 | 1. Open the Elastic Beanstalk console. 623 | 2. Choose Create New Application. 624 | 3. Enter the name of the application: **my-wordpress-site** 625 | 4. Then click Create. 626 | 627 | ### Create your Staging Application Environment 628 | 629 | **To launch an environment** 630 | 631 | 1. Open the Elastic Beanstalk console. 632 | 2. Choose our application: **my-wordpress-site** 633 | 3. In the upper right corner, choose Create New Environment from the Actions menu. 634 | 4. Choose **Web server** environment types. 635 | 5. For Platform: PHP 636 | 6. For App code, choose Sample application. 637 | 7. Choose Configure more options. 638 | 8. Configuration presets: Custom configuration 639 | 9. Select **Environment settings** and fill in the following: 640 | *. Name: Staging 641 | *. Domain: staging-my-wordpress-site 642 | 10. Select **Software settings** and fill in the following **Environment properties**: 643 | * environment: staging 644 | * MYSQL_ADDON_DB: staging_my_wordpress_site_db 645 | * MYSQL_ADDON_HOST: staging-my-wordpress-site-db.ce7wdtyntw8p.\.rds.amazonaws.com 646 | * MYSQL_ADDON_USER: wordpress_userdb 647 | * MYSQL_ADDON_PASSWORD: \ 648 | * S3_BACKUP_URL: \ 649 | * S3_MEDIA_URL: 650 | 11. Optionally if you have configured the WP Security Keys, set the following variables as well: 651 | * AUTH_KEY: 652 | * AUTH_SALT: 653 | * LOGGED_IN_KEY: 654 | * LOGGED_IN_SALT: 655 | * NONCE_KEY: 656 | * NONCE_SALT: 657 | * SECURE_AUTH_KEY: 658 | * SECURE_AUTH_SALT: 659 | 12. Select **Instances** and fill in the following: 660 | 1. Root volume type: General Purpose (SSD) 661 | 2. Size: 10 GB 662 | 13. Select **Security** 663 | 1. EC2 key pair: \ 664 | 14. Select **Notifications** 665 | 1. Email: \ 666 | 15. Select **Network** 667 | 1. Select your default VPC in the Virtual private cloud (VPC) 668 | 2. Select all the Instance subnets 669 | 3. Instance security groups select: 670 | * rds-launch-wizard 671 | 16. Do not configure the Database settings. 672 | 17. Choose Create environment. 673 | 674 | ### Configuring the DocumentRoot 675 | 676 | When the environment has been created, let's configure your DocumentRoot. 677 | 678 | 1. Goto your Elastic Beanstalk application **my-wordpress-site** 679 | 2. Select your environment **Staging** 680 | 3. Goto Configuration 681 | 4. Select **Software Configuration**, and fill in the following: 682 | * Document root: /wp 683 | 684 | Now let's configure the WordPress Site URL. 685 | 686 | ### Configuring the WordPress Site URL 687 | 688 | Still in the **Software Configuration** you will add the SERVER_HOSTNAME variable, but before let's get the URL of our Elastic BeanStalk URL available at the top of the page near the environment name, copy it and add the variable: 689 | 690 | * SERVER_HOSTNAME: http://staging-my-wordpress-site.eu-central-1.elasticbeanstalk.com/ 691 | 692 | Note: if you configure a Route53 alias to your Elastic Load Balancer, use that domain name instead. 693 | 694 | ### Adding the EC2 Security Group to your RDS Database 695 | 696 | In order to let the EC2 communicate with your WordPress RDS Database you need to add the EC2 Security Group to your RDS Database Security Group, for this: 697 | 698 | 1. Sign-in to the IAM console at https://console.aws.amazon.com/ec2/ with your user that has administrator permissions. 699 | 2. Goto Security Groups 700 | 3. Select the rds-launch-wizard Security Group 701 | 4. Goto Inbound and Edit 702 | 5. Add in Inboud Rule with: 703 | * Type: MySQL/Aurora 704 | * Protocol: TCP/IP 705 | * Port Range: 3306 706 | * Source: \ 707 | 708 | To find the EC2 Security Group Id, find the Security Group Name called **my-wordpress-site** 709 | 710 | ## Set up the IAM permissions 711 | 712 | Let's create an IAM policy to grant continuousphp the permission to upload the package to your Elastic BeanStalk bucket and communicate with Elastic BeanStalk to deploy it. 713 | 714 | **Create the policy** 715 | 716 | 1. Sign-in to the IAM console at https://console.aws.amazon.com/iam/ with your user that has administrator permissions. 717 | 2. In the navigation pane, choose *Policies*. 718 | 3. In the content pane, choose *Create Policy*. 719 | 4. Next to *Create Your Own Policy*, choose *Select*. 720 | 5. As *Policy Name*, type **eb-deploy-staging**. 721 | 6. As *Policy Document*, paste the following policy. 722 | 723 | ```json 724 | { 725 | "Version": "2012-10-17", 726 | "Statement": [ 727 | { 728 | "Action": [ 729 | "autoscaling:*", 730 | "cloudformation:*", 731 | "ec2:*" 732 | ], 733 | "Effect": "Allow", 734 | "Resource": [ 735 | "*" 736 | ] 737 | }, 738 | { 739 | "Action": [ 740 | "elasticbeanstalk:*" 741 | ], 742 | "Effect": "Allow", 743 | "Resource": [ 744 | "arn:aws:elasticbeanstalk:*::solutionstack/*", 745 | "arn:aws:elasticbeanstalk:::application/my-wordpress-site", 746 | "arn:aws:elasticbeanstalk:::applicationversion/my-wordpress-site/*", 747 | "arn:aws:elasticbeanstalk:::environment/my-wordpress-site/*", 748 | "arn:aws:elasticbeanstalk:::template/my-wordpress-site/*" 749 | ] 750 | }, 751 | { 752 | "Action": [ 753 | "s3:Get*" 754 | ], 755 | "Effect": "Allow", 756 | "Resource": [ 757 | "arn:aws:s3:::elasticbeanstalk-*/*" 758 | ] 759 | }, 760 | { 761 | "Action": [ 762 | "s3:CreateBucket", 763 | "s3:DeleteObject", 764 | "s3:GetBucketPolicy", 765 | "s3:GetObjectAcl", 766 | "s3:ListBucket", 767 | "s3:PutBucketPolicy", 768 | "s3:PutObject", 769 | "s3:PutObjectAcl" 770 | ], 771 | "Effect": "Allow", 772 | "Resource": [ 773 | "arn:aws:s3:::elasticbeanstalk--", 774 | "arn:aws:s3:::elasticbeanstalk--/*" 775 | ] 776 | }, 777 | { 778 | "Action": [ 779 | "iam:PassRole" 780 | ], 781 | "Effect": "Allow", 782 | "Resource": [ 783 | "arn:aws:iam:::role/aws-elasticbeanstalk-ec2-role" 784 | ] 785 | }, 786 | { 787 | "Action": [ 788 | "elasticloadbalancing:DescribeLoadBalancers" 789 | ], 790 | "Effect": "Allow", 791 | "Resource": [ 792 | "*" 793 | ] 794 | }, 795 | { 796 | "Action": [ 797 | "elasticloadbalancing:RegisterInstancesWithLoadBalancer" 798 | ], 799 | "Effect": "Allow", 800 | "Resource": [ 801 | "arn:aws:elasticloadbalancing:::loadbalancer", 802 | "arn:aws:elasticloadbalancing:::loadbalancer/*" 803 | ] 804 | }, 805 | { 806 | "Effect": "Allow", 807 | "Action": "sns:*", 808 | "Resource": "arn:aws:sns:::*" 809 | } 810 | ] 811 | } 812 | ``` 813 | 814 | 7\. Choose *Validate Policy* and ensure that no errors display in a red box at the top of the screen. Correct any that are reported. 815 | 816 | 8\. Choose *Create Policy*. 817 | 818 | Now let's create an IAM user with an Access Key and attach the policy we've just created. 819 | 820 | **Create a new User and attach the User policy** 821 | 822 | 1. Sign-in to the Identity and Access Management (IAM) console at https://console.aws.amazon.com/iam/. 823 | 2. In the navigation pane, choose *Users* and then choose *Create New Users*. 824 | 3. Enter the following user: **staging-wordpress-deploy** 825 | 4. Select **Programmatic access** then click Next 826 | 5. Select **Attach existing policies directly** 827 | 6. Search for the policy we just made: **eb-deploy-staging** 828 | 7. Click Next the Create User 829 | 8. Save the generated access key in a safe place. 830 | 9. Choose *Close*. 831 | 832 | ## Set-up continuousphp 833 | 834 | ### WordPress Project Set-up in continuousphp 835 | 836 | **Set-up our WordPress project in continuousphp** 837 | 838 | 1. Type in the omnibar the name of the application: **wordpress-eb** 839 | 2. The fork should appear in the Project List (if not please wait a little that projects list update or simply logout/login) 840 | 3. Click on **Setup** 841 | 4. Click on **Setup Repository** 842 | 5. Click on **+** to add a deployment pipeline 843 | 6. Select the **develop** branch 844 | 845 | ### Deployment pipeline Configuration 846 | 847 | **To configure your deployment pipeline** 848 | 849 | 1. In the Build Settings (Step 1): 850 | 1. In the **PHP VERSIONS**, select the PHP versions: **7.1** 851 | 2. Set the Document Root to: wp 852 | 3. In the **CREDENTIALS**, click on the **+**, add the AWS IAM Credential **deployment.staging** User Access Key and Secret Key we created in step [Set-up the IAM permissions](#set-up-the-iam-permissions) 853 | * Name: deployment.staging 854 | * Region: \ 855 | * Access Key: \ 856 | * Secret Key: \ 857 | 4. Still in the **CREDENTIALS**, click on the **+**, add the AWS IAM Credential **my-wordpress-site-backup** User Access Key and Secret Key we created in step [Set-up the WordPress backup S3 bucket IAM policy](#set-up-the-wordpress-backup-s3-bucket-iam-policy) 858 | * Name: my-wordpress-site-backup 859 | * Region: \ 860 | * Access Key: \ 861 | * Secret Key: \ 862 | 5. In the **PHING** section, add the following Phing Target: **wp-composer-plugins-update** 863 | 6. Uncheck the **Enable caching of Composer packages** 864 | 6. Click on **Next** to move to the Test Settings 865 | 2. In the Test Settings (Step 2): 866 | 1. continuousphp automatically discovers that you have a `behat.yml` and `phpunit.xml` in your repository and creates the testing configuration for you. 867 | 2. Click on the **Behat** configuration panel. In the **PHING** section, select the following Phing Targets: **reset-db** and **setup-test** 868 | 3. Still in the **PHING** section, add the following variables: 869 | * environment: develop 870 | 4. Set the environment variables, Click on the + Next to **ENVIRONMENT VARIABLES** 871 | * MYSQL_ADDON_HOST: 127.0.0.1 872 | * MYSQL_ADDON_DB: wordpress 873 | * MYSQL_ADDON_USER: root 874 | * MYSQL_ADDON_PASSWORD: 875 | * S3_BACKUP_URL: \ 876 | * S3_MEDIA_URL: 877 | * SERVER_HOSTNAME: http://localhost/ 878 | * AUTH_KEY: 879 | * AUTH_SALT: 880 | * SECURE_AUTH_KEY: 881 | * LOGGED_IN_KEY: 882 | * NONCE_KEY: 883 | * SECURE_AUTH_SALT: 884 | * LOGGED_IN_SALT: 885 | * NONCE_SALT: 886 | 5. Click on **Next** to move to the Package Settings 887 | 3. In the Package Settings (Step 3): 888 | 1. Select **AWS ElasticBeanstalk** 889 | 2. In the **PHING** section, add the following Phing Target: **wp-composer-plugins-update** 890 | 3. Click on **Next** to move to the Deployment Settings 891 | 4. In the Deployment Settings (Step 4): 892 | 1. Click on **+** on the **DESTINATIONS** panel 893 | 2. Complete the destination: 894 | * Name: staging 895 | * Apply to: push 896 | * IAM Profile: The profile we created in Step 1.2 897 | * Application: my-wordpress-site 898 | * Environment: Staging 899 | * S3 Bucket: Sign-in to the AWS Management Console and open the Amazon S3 console at https://console.aws.amazon.com/s3, look for a bucket called elasticbeanstalk-\-\ and add **/package** 900 | 3. Check the **enable deployment for successful builds** checkbox 901 | 902 | ## Deploying WordPress 903 | 904 | Before Deploying, let's push our changes: 905 | 906 | ``` 907 | git status 908 | git add build.properties 909 | git add composer.json 910 | git add tests/features/homepage.feature 911 | git commit -m "Adding plugins and behat tests" 912 | git push origin develop 913 | ``` 914 | 915 | A build has started automatically on continuousphp. 916 | 917 | **Deploying WordPress manually with continuousphp** 918 | 919 | 1. Click on the **Play** button on the top right of the project 920 | 2. Select the **develop** branch 921 | 3. The build is started. It will create the testing and dist package, then run the tests (Behat) for the choosen PHP versions, and finally it deploys the WordPress on Elastic BeanStalk Staging environment. 922 | 4. In the deploy console, you should see **Deployment successfully started** 923 | 5. Login to the AWS console/AWS Elastic BeanStalk to see the details. 924 | 925 | Let's modify our Dumy plugin at ./wp-content/plugins/dumy-plugin/dumy-plugin.php and bump its version to 1.1: 926 | 927 | ``` 928 | 938 | ``` 939 | 940 | ```bash 941 | git checkout develop 942 | git add ./wp-content/plugins/dumy-plugin/dumy-plugin.php 943 | git commit -m "Bumping our Dumy plugin version" 944 | git pusih origin develop 945 | ``` 946 | 947 | Now, everytime you push to the develop branch, your develop pipeline is triggered and continuousphp builds, tests and deploys your WordPress upon a successful build. 948 | 949 | ## Notes 950 | 951 | * The Configuration used in this tutorial is an example and should not be used for production use as is. 952 | * The Configuration used in this tutorial is a base and should be completed to suit your needs. 953 | * This Tutorials used AWS Resources which has cost, please delete your Elastic BeanStalk and RDS database when you have finished to avoid cost. 954 | 955 | If you like to know more about production configuration or have questions about this tutorial, do not hesitate to contact us using the chat button! 956 | -------------------------------------------------------------------------------- /build.local.properties.sample: -------------------------------------------------------------------------------- 1 | environment=develop 2 | dir.vendor=./vendor 3 | phinx.bin=${dir.vendor}/bin/phinx 4 | server_hostname=http://192.168.99.100/ 5 | 6 | db_hostname=192.168.99.100 7 | db_port=3306 8 | db_name=wordpress 9 | db_username=root 10 | db_password=password 11 | s3_backup_url=s3://backup-bucket/db-backup-updraftplus.zip 12 | s3_media_url=s3://backup-bucket/media-backup-updraftplus.zip 13 | 14 | wp.theme=twentyeleven 15 | wp.plugins=business-profile,contact-form-7 16 | 17 | # Behat configuration 18 | # ------------------- 19 | 20 | # The location of the Behat executable. 21 | behat.bin = ${project.basedir}/vendor/bin/behat 22 | 23 | # The location of the Behat tests. 24 | behat.dir = ${project.basedir}/tests 25 | 26 | # The location of the Behat configuration template. 27 | behat.yml.template = ${behat.dir}/behat.yml.dist 28 | 29 | # The location of the generated Behat configuration file. 30 | behat.yml.path = ${behat.dir}/behat.yml 31 | 32 | # The base URL to use in Behat tests. 33 | behat.base_url = http://192.168.99.100/ 34 | 35 | # The browser to use for testing, either 'firefox' or 'chrome'. 36 | behat.browser_name = chrome 37 | 38 | # The port of the webdriver host (e.g. Selenium or PhantomJS). 39 | behat.webdriver_port = 4444 40 | 41 | # The URL of the webdriver host (e.g. Selenium or PhantomJS). 42 | behat.webdriver_url = http://192.168.99.100:${behat.webdriver_port}/wd/hub 43 | 44 | # The location to search for Behat subcontexts. 45 | behat.subcontexts.path = ${website.modules.dir} 46 | 47 | # The output format to use for Behat tests, either 'progress' or 'pretty'. 48 | behat.formatter.name = progress 49 | 50 | # The location of the test files. 51 | behat.files.path = ${behat.dir}/fixtures/files 52 | -------------------------------------------------------------------------------- /build.properties: -------------------------------------------------------------------------------- 1 | dir.vendor=./vendor 2 | phinx.bin=${dir.vendor}/bin/phinx 3 | server_hostname=${env.SERVER_HOSTNAME} 4 | 5 | db_hostname=${env.MYSQL_ADDON_HOST} 6 | db_port=3306 7 | db_name=${env.MYSQL_ADDON_DB} 8 | db_username=${env.MYSQL_ADDON_USER} 9 | db_password=${env.MYSQL_ADDON_PASSWORD} 10 | s3_backup_url=${env.S3_BACKUP_URL} 11 | s3_media_url=${env.S3_MEDIA_URL} 12 | 13 | wp.theme=vanilla 14 | wp.plugins=business-profile,contact-form-7,updraftplus,w3-total-cache 15 | 16 | # Behat configuration 17 | # ------------------- 18 | 19 | # The location of the Behat executable. 20 | behat.bin = ${project.basedir}/vendor/bin/behat 21 | 22 | # The location of the Behat tests. 23 | behat.dir = ${project.basedir}/tests 24 | 25 | # The location of the Behat configuration template. 26 | behat.yml.template = ${behat.dir}/behat.yml.dist 27 | 28 | # The location of the generated Behat configuration file. 29 | behat.yml.path = ${behat.dir}/behat.yml 30 | 31 | # The base URL to use in Behat tests. 32 | behat.base_url = ${SERVER_HOSTNAME} 33 | 34 | # The browser to use for testing, either 'firefox' or 'chrome'. 35 | behat.browser_name = chrome 36 | 37 | # The port of the webdriver host (e.g. Selenium or PhantomJS). 38 | behat.webdriver_port = 4444 39 | 40 | # The URL of the webdriver host (e.g. Selenium or PhantomJS). 41 | behat.webdriver_url = http://localhost:${behat.webdriver_port}/wd/hub 42 | 43 | # The location to search for Behat subcontexts. 44 | behat.subcontexts.path = ${website.modules.dir} 45 | 46 | # The output format to use for Behat tests, either 'progress' or 'pretty'. 47 | behat.formatter.name = progress 48 | 49 | # The location of the test files. 50 | behat.files.path = ${behat.dir}/fixtures/files 51 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | ${db_hostname} 159 | DROP DATABASE IF EXISTS `${db_name}`; 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | CREATE DATABASE IF NOT EXISTS ${db_name}; 170 | GRANT USAGE ON *.* TO '${db_username}'@'%' IDENTIFIED BY '${db_password}'; 171 | GRANT UPDATE,CREATE,REFERENCES,ALTER,LOCK TABLES,CREATE VIEW,CREATE 172 | ROUTINE,TRIGGER,INSERT,DELETE,DROP,INDEX,CREATE TEMPORARY TABLES,EXECUTE,SHOW VIEW,ALTER ROUTINE,SELECT ON 173 | `${db_name}`.* TO '${db_username}'@'%'; 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 241 | 242 | 245 | 246 | 249 | 250 | 253 | 254 | 257 | 258 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "continuousphp/wordpress-eb-demo", 3 | "description": "Wordpress Elastic Beanstalk Demo", 4 | "repositories": [ 5 | { 6 | "type": "composer", 7 | "url": "https://wpackagist.org" 8 | } 9 | ], 10 | "require": { 11 | "php": ">=7.0", 12 | "johnpbloch/wordpress": ">=4.7.2", 13 | "composer/installers": "~1.0", 14 | "wpackagist-plugin/contact-form-7": "4.7", 15 | "wpackagist-plugin/business-profile": "1.1.4", 16 | "wpackagist-plugin/updraftplus": "1.13.1", 17 | "wpackagist-plugin/w3-total-cache": "0.9.5.4", 18 | "wpackagist-theme/vanilla": "1.3.5", 19 | "robmorgan/phinx": "~0.6.0", 20 | "wp-cli/wp-cli": "^1.0", 21 | "phing/phing": "~2.14" 22 | }, 23 | "require-dev": { 24 | "guzzlehttp/guzzle": "~5.0", 25 | "robmorgan/phinx": "~0.6.0", 26 | "phing/phing": "~2.14", 27 | "behat/behat": "2.5.*@stable", 28 | "behat/mink": "1.4.*@stable", 29 | "behat/mink-extension": "*", 30 | "behat/mink-goutte-driver": "*", 31 | "behat/mink-selenium2-driver": "*" 32 | }, 33 | "minimum-stability": "stable", 34 | "extra": { 35 | "wordpress-install-dir": "wp", 36 | "installer-paths": { 37 | "wp/wp-content/plugins/{$name}/": ["type:wordpress-plugin"], 38 | "wp/wp-content/themes/{$name}/": ["type:wordpress-theme"] 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /data/README.md: -------------------------------------------------------------------------------- 1 | SQL Data Folder 2 | -------------------------------------------------------------------------------- /data/db/README.md: -------------------------------------------------------------------------------- 1 | SQL Data Folder 2 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | nginx: 4 | image: evild/alpine-nginx:1.11.2-libressl 5 | container_name: wordpress_nginx 6 | restart: always 7 | volumes: 8 | - .:/var/www/html/:rw 9 | - ./nginx/conf/nginx.conf:/etc/nginx/conf/nginx.conf:ro 10 | - ./nginx/conf.d:/etc/nginx/conf.d:ro 11 | ports: 12 | - 80:80 13 | - 443:443 14 | networks: 15 | - front 16 | php: 17 | build: . 18 | container_name: php 19 | restart: always 20 | volumes: 21 | - .:/var/www/html:rw 22 | - ./php/upload.ini:/usr/local/etc/php/conf.d/uploads.ini 23 | - ./php/php.ini:/usr/local/etc/php/php.ini 24 | depends_on: 25 | - db 26 | links: 27 | - db 28 | environment: 29 | - MYSQL_ADDON_DB=wordpress 30 | - MYSQL_ADDON_HOST=db 31 | - MYSQL_ADDON_USER=root 32 | - MYSQL_ADDON_PASSWORD=password 33 | - AUTH_KEY='' 34 | - SECURE_AUTH_KEY='' 35 | - LOGGED_IN_KEY='' 36 | - NONCE_KEY='' 37 | - AUTH_SALT='' 38 | - SECURE_AUTH_SALT='' 39 | - LOGGED_IN_SALT='' 40 | - NONCE_SALT='' 41 | networks: 42 | - front 43 | - back 44 | db: 45 | image: mariadb:10 46 | container_name: wordpress_mariadb 47 | restart: always 48 | ports: 49 | - 3306:3306 50 | environment: 51 | - MYSQL_ROOT_PASSWORD=password 52 | networks: 53 | - back 54 | hub: 55 | image: selenium/hub 56 | container_name: wordpress_selenium-hub 57 | ports: 58 | - "4444:4444" 59 | networks: 60 | - back 61 | chrome: 62 | container_name: selenium-chrome 63 | image: selenium/node-chrome 64 | restart: always 65 | links: 66 | - hub 67 | environment: 68 | - HUB_PORT_4444_TCP_ADDR=hub 69 | networks: 70 | - back 71 | networks: 72 | front: 73 | back: 74 | -------------------------------------------------------------------------------- /nginx/conf.d/default.conf: -------------------------------------------------------------------------------- 1 | upstream php { 2 | server php:9000; 3 | } 4 | 5 | server { 6 | 7 | root /var/www/html/wp; 8 | index index.php; 9 | 10 | location = /favicon.ico { 11 | log_not_found off; 12 | access_log off; 13 | } 14 | 15 | location = /robots.txt { 16 | allow all; 17 | log_not_found off; 18 | access_log off; 19 | } 20 | 21 | location / { 22 | 23 | try_files $uri $uri/ /index.php?$args; 24 | } 25 | 26 | location ~ \.php$ { 27 | 28 | include fastcgi.conf; 29 | fastcgi_intercept_errors on; 30 | fastcgi_pass php; 31 | } 32 | 33 | location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { 34 | expires max; 35 | log_not_found off; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /nginx/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | daemon off; 4 | 5 | events { 6 | worker_connections 1024; 7 | } 8 | 9 | error_log /var/log/nginx/error.log warn; 10 | pid /var/run/nginx.pid; 11 | 12 | http { 13 | include /etc/nginx/conf/mime.types; 14 | default_type application/octet-stream; 15 | 16 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 17 | '$status $body_bytes_sent "$http_referer" ' 18 | '"$http_user_agent" "$http_x_forwarded_for"'; 19 | 20 | access_log /var/log/nginx/access.log main; 21 | 22 | sendfile on; 23 | #tcp_nopush on; 24 | 25 | keepalive_timeout 65; 26 | 27 | gzip on; 28 | gzip_disable "msie6"; 29 | 30 | gzip_vary on; 31 | gzip_proxied any; 32 | gzip_comp_level 6; 33 | gzip_buffers 16 8k; 34 | gzip_http_version 1.1; 35 | gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 36 | # tells the server to use on-the-fly gzip compression. 37 | client_max_body_size 64M; 38 | include /etc/nginx/conf.d/*.conf; 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /php/php.ini: -------------------------------------------------------------------------------- 1 | log_errors = On 2 | error_log = /dev/stderr 3 | error_reporting = E_ALL 4 | -------------------------------------------------------------------------------- /php/upload.ini: -------------------------------------------------------------------------------- 1 | file_uploads = On 2 | memory_limit = 64M 3 | upload_max_filesize = 64M 4 | post_max_size = 64M 5 | max_execution_time = 600 6 | -------------------------------------------------------------------------------- /scripts/htaccess-no-bot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$environemt" = "staging" ] 4 | then 5 | if grep -Fxq "# NO-BOT" wp/.htaccess 6 | then 7 | echo "No-Bot already set" 8 | else 9 | 10 | cat <> wp/.htaccess 11 | 12 | # NO-BOT 13 | RewriteEngine On 14 | 15 | RewriteCond %{HTTP_USER_AGENT} (googlebot|bingbot|Baiduspider) [NC] 16 | RewriteRule .* - [R=403,L] 17 | # NO-BOT 18 | EOF 19 | 20 | fi 21 | fi 22 | -------------------------------------------------------------------------------- /tests/behat.local.yml.sample: -------------------------------------------------------------------------------- 1 | # behat.yml 2 | default: 3 | extensions: 4 | Behat\MinkExtension\Extension: 5 | base_url: http://192.168.99.100/ 6 | browser_name: 'chrome' 7 | show_cmd: /Applications/Firefox.app/Contents/MacOS/firefox %s 8 | javascript_session: 'selenium2' 9 | goutte: 10 | guzzle_parameters: 11 | verify: false 12 | ssl.certificate_authority: false 13 | 14 | selenium2: 15 | wd_host: http://192.168.99.100:4444/wd/hub 16 | capabilities: {"browserName":"chrome", "platform":"LINUX", "browserVersion":"9", "version": "", "browser": "chrome"} 17 | 18 | imports: 19 | - behat.params.yml 20 | -------------------------------------------------------------------------------- /tests/behat.params.yml: -------------------------------------------------------------------------------- 1 | # Local configuration. 2 | default: 3 | context: 4 | parameters: 5 | wp_users: 6 | editor-qa: 7 | 'password' 8 | another-user: 9 | 'password' 10 | 11 | -------------------------------------------------------------------------------- /tests/behat.params.yml.sample: -------------------------------------------------------------------------------- 1 | # Local configuration. 2 | default: 3 | context: 4 | parameters: 5 | wp_users: 6 | editor-qa: 7 | 'password for editor-qa' 8 | another-user: 9 | 'password for another-user' 10 | -------------------------------------------------------------------------------- /tests/behat.yml: -------------------------------------------------------------------------------- 1 | # behat.yml 2 | default: 3 | extensions: 4 | Behat\MinkExtension\Extension: 5 | base_url: http://localhost/ 6 | browser_name: chrome 7 | goutte: 8 | guzzle_parameters: 9 | verify: false 10 | ssl.certificate_authority: false 11 | selenium2: 12 | wd_host: 'http://selenium:4444/wd/hub' 13 | 14 | imports: 15 | - behat.params.yml 16 | -------------------------------------------------------------------------------- /tests/features/bootstrap/FeatureContext.php: -------------------------------------------------------------------------------- 1 | wp_users = $parameters['wp_users']; 30 | } 31 | 32 | /** 33 | * Authenticates a user. 34 | * 35 | * @Given /^I am logged in as "([^"]*)" with the password "([^"]*)"$/ 36 | */ 37 | public function iAmLoggedInAsWithThePassword($username, $passwd) { 38 | // Go to the Login page. 39 | $this->getSession()->visit($this->locatePath('/wp-login.php')); 40 | // Log in 41 | $element = $this->getSession()->getPage(); 42 | if (empty($element)) { 43 | throw new Exception('Page not found'); 44 | } 45 | $element->fillField('Username', $username); 46 | $element->fillField('Password', $passwd); 47 | $submit = $element->findButton('Log In'); 48 | if (empty($submit)) { 49 | throw new Exception('No submit button at ' . $this->getSession() 50 | ->getCurrentUrl()); 51 | } 52 | $submit->click(); 53 | $link = $this->getSession()->getPage()->findLink("Dashboard"); 54 | if (empty($link)) { 55 | throw new Exception('Login failed at ' . $this->getSession() 56 | ->getCurrentUrl()); 57 | } 58 | return; 59 | } 60 | 61 | /** 62 | * Authenticates a user with password from configuration. 63 | * 64 | * @Given /^I am logged in as "([^"]*)"$/ 65 | */ 66 | public function iAmLoggedInAs($username) { 67 | $password = $this->fetchPassword($username); 68 | $this->iAmLoggedInAsWithThePassword($username, $password); 69 | } 70 | 71 | 72 | 73 | /** 74 | * Helper function to fetch user passwords stored in behat.local.yml. 75 | * 76 | * @param string $type 77 | * The user type, e.g. drupal or git. 78 | * 79 | * @param string $name 80 | * The username to fetch the password for. 81 | * 82 | * @return string 83 | * The matching password or FALSE on error. 84 | */ 85 | public function fetchPassword($name) { 86 | $property_name = 'wp_users'; 87 | try { 88 | $property = $this->$property_name; 89 | $password = $property[$name]; 90 | return $password; 91 | } catch (Exception $e) { 92 | throw new Exception("Non-existent user/password for $property_name:$name please check behat.local.yml."); 93 | } 94 | } 95 | 96 | /** 97 | * Pauses the scenario until the user presses a key. Useful when debugging a scenario. 98 | * 99 | * @Then /^(?:|I )break$/ 100 | */ 101 | public function iPutABreakpoint() 102 | { 103 | fwrite(STDOUT, "\033[s \033[93m[Breakpoint] Press \033[1;93m[RETURN]\033[0;93m to continue...\033[0m"); 104 | while (fgets(STDIN, 1024) == '') {} 105 | fwrite(STDOUT, "\033[u"); 106 | return; 107 | } 108 | 109 | 110 | /** 111 | * @Then /^I wait for the message to appear$/ 112 | */ 113 | public function iWaitForTheMessageToAppear() 114 | { 115 | $this->getSession()->wait(5000, 116 | "jQuery('#message').children().length > 0" 117 | ); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /tests/features/homepage.feature: -------------------------------------------------------------------------------- 1 | @home 2 | Feature: As a visitor I should be able to load the home page 3 | 4 | Scenario: Home page loads 5 | Given I am on the homepage 6 | Then I should see "Hello world!" 7 | -------------------------------------------------------------------------------- /wp-content/plugins/README.md: -------------------------------------------------------------------------------- 1 | this folder is for custom plugins 2 | -------------------------------------------------------------------------------- /wp-content/themes/README.md: -------------------------------------------------------------------------------- 1 | this folder is for custom themes 2 | -------------------------------------------------------------------------------- /wp-root/.htaccess: -------------------------------------------------------------------------------- 1 | # BEGIN WordPress 2 | 3 | RewriteEngine On 4 | RewriteBase / 5 | RewriteRule ^index\.php$ - [L] 6 | RewriteCond %{REQUEST_FILENAME} !-f 7 | RewriteCond %{REQUEST_FILENAME} !-d 8 | RewriteRule . /index.php [L] 9 | 10 | # END WordPress 11 | -------------------------------------------------------------------------------- /wp-root/README.md: -------------------------------------------------------------------------------- 1 | this folder is for root WP config file 2 | -------------------------------------------------------------------------------- /wp-root/wp-config.php: -------------------------------------------------------------------------------- 1 |