Local WordPress Development with Vagrant

The purpose of this post is to show you how to set up an isolated WordPress development environment on your local machine with Vagrant. The benefits of using Vagrant for development is that all your dependencies/packages are installed in an isolated, reproducible, & disposable development environment that doesn’t effect your local machine.

Learn more about what Vagrant is here.

This tutorial assumes that you have both Vagrant and Virtual Box install on your local machine. If not here are the links to both:

  1. https://www.vagrantup.com/
  2. https://www.virtualbox.org/

Once both are installed you will be able to complete the rest of this tutorial.

Step 1 – Fetch WordPress Source Code

Clone the latest WordPress source code from their Github:

git clone https://github.com/WordPress/WordPress.git
Terminal

When git is done fetching the source code you should have a new WordPress folder in your working directory which contains all the WordPress source code files.

Step 2 – Create a Vagrantfile

Run the vagrant init command to generate a new Vagrantfile in the same directory as you cloned the WordPress source code.

Terminal

The Vagrantfile generated tells VirtualBox how to provision and run the Ubuntu virtual machine we will spin up. We’ll edit this in a bit.

For a bit of house cleaning, let’s create a parent folder called wp and put both the WordPress source code and Vagrantfile inside it.

mkdir wp
Code directory

Step 3 – Quick Configuration Changes

Configure the Vagrantfile

Open the wp folder with your favorite text editor and edit the Vagrantfile to look like the following:


Vagrant.configure("2") do |config|
# The base disk image will be Ubuntu 16.04 LTS
config.vm.box = "ubuntu/xenial64"

# Set the host name of the machine
config.vm.hostname = "wordpress"

# A friendly message to appear on machine start up
config.vm.post_up_message = "Welcome to WordPress mate!"

# The private IP to access the virtual machine on your local
config.vm.network "private_network", ip: "192.168.33.10"

# Syncs the shared folder WordPress source code to
# /var/www/Wordpress on the virtual machine
config.vm.synced_folder "Wordpress", "/var/www/Wordpress"

# On start up the machine will run these commands to install
# Nginx
# PHP 7.0 packages we need to run WordPress
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y nginx
apt-get install -y php7.0 php7.0-common php7.0-mbstring php7.0-gd php7.0-intl php7.0-xml php7.0-mysql php7.0-mcrypt php7.0-fpm
SHELL
end

Configure WordPress

  1. In the WordPress source code folder rename the wp-config-sample.php to wp-config.php.
  2. In the wp-config.php update the salts with salts generate from this website https://api.wordpress.org/secret-key/1.1/salt/
  3. Update define( 'DB_NAME', 'database_name_here' ); with whatever name you want your database to be
  4. Update define( 'DB_USER', 'username_here' ); to be define( 'DB_USER', 'root' );
  5. Update define( 'DB_PASSWORD', 'password ); to be define( 'DB_PASSWORD', 'root' );
Wordpress configuration file

NOTE: For live environments I would highly recommend not using the root user for MySQL nor such a simple password.

Step 4 – Enter the Machine

With these configurations done it’s time to start your virtual machine with vargant up. When the machine is done provisioning and installing all dependencies you’ll see your friendly message in the terminal.

Terminal

To check that everything is working so far navigate to http://192.168.33.10/ on your local machine. You should see the default Nginx page.

Nginx default page

Congratulations, you now have a high performance web server running on your local machine! Just a few more steps to go.

Step 5 – Install MySQL

ssh into your machine with vagrant ssh and install MySQL on your virtual machine with

sudo apt-get install -y mysql-server

After which you will be prompted to enter and reconfirm a password. Above we made out database password root so we will use that input for both prompts.

MySQL Password Prompt
MySQL Confirm Password Prompt

Now we will create our database with the same name as specified in our wp-config.php file. Mine was called wp_db. From inside the machine log into your MySQL instance as the root user with:

mysql -u root -p

Once in the MySQL command line, create your database with:

CREATE DATABASE wp_db;

And then exit the MySQL command line with:

\q
Terminal of virtual machine

Step 6 – Configure Nginx

In your virtual machine, create a wordpress file in /etc/nginx/sites-available with the following contents:

server {
listen 80;
root /var/www/Wordpress;
index index.php index.html;
server_name example.com;

location / {
try_files $uri $uri/ =404;
}

location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
}

location ~ /\.ht {
deny all;
}
}

Remove the default file from /etc/nginx/sites-enabled and symlink the wordpress file you created in the sites-available directory to sites-enabled

Terminal of virtual machine

Confirm that your Nginx configuration is valid with:

sudo nginx -t

Restart your Nginx web server

sudo nginx -s reload

You’re Done!

Reload http://192.168.33.10 and you should WordPress!

Wordpress settings page

Please let me know how I can improve this post and I’ll be happy to update it!

Configure Angular for Multiple Development Environments

In this post I’ll show you how I set up my angular.json file to support multiple build environments for an Angular 6 application. I’ve used the configuration below in a development stack where I had a development, staging, and production server.

Configuration

// angular.json
...
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": false,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
},
"staging": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.staging.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
},
"development": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.dev.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": false,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
}
}
...

Each configuration tells Angular to replace /environment.ts with the correct environment file in the "with": block.

Now when you run

ng build --configuration=development

The Angular CLI will build an optimized static bundle in the newly generated dist/ directory with the environment variables in environment.dev.ts.

CI/CD Possibilities

With this setup I was able to create an AWS CI/CD pipeline using CodeCommit, CodeBuild, CodeDeploy, and CodePipeline. The AWS CodeBuild service allowed me to set variables at build time so making an automated pipeline for each EC2 instance was as simple as replacing the above command with:

ng build --configuration=$ENVIRONMENT

For those of you interested here is the buildspec.yml I used for my AWS CI/CD pipeline:

version: 0.2

phases:
install:
commands:
- echo $CODEBUILD_SRC_DIR
- npm install -y npm@latest
- npm install -g @angular/cli
- rm package-lock.json
pre_build:
commands:
- npm install
build:
commands:
- echo build started on `date`
- ng build --configuration=$ENVIRONMENT
- ls -l -F
post_build:
commands:
- echo Production build ended on `date`
artifacts:
files:
- appspec.yml
- dist/my-app/**/*
cache:
paths:
- node_modules/

Comment below if you would like me to write a post on how I made the all AWS CI/CD pipeline!

Top Visual Studio Code extensions for Angular Development

Below is a list of some VSCode extensions I use heavily when developing Angular web applications that have helped me move faster. Check them out!

Compodoc

This first tool is not a VSCode extension, however, I have been using this lately as an invaluable tool when developing in bigger teams. As a developer you will spend a lot of time reading other people’s code where there may not be any documentation. The good people at Compodoc give you an out-of-the-box solution for automatically generating an entire static site of documentation for your Angular project right in your working directory. By providing some really cool graphical diagrams of all the imports, routes, and modules, understanding other people’s code just got a little easier.

Angular7 Snippets

Having this extension installed provides hot keys and short cuts to generate Angular and Typescript snippets. There’s not much more to be said here.

Prettier

Prettier is my de-facto code formatter and takes care of 80% of all of my code formatting. It’s also extremely customizable in that you can include a .prettierrc file in the root directory of your project and customize exactly how Prettier formats your code. Recently I’ve been turned off by the way it formats HTMLcode blocks so I’ve added a .prettierignore file to the root directory of my project to tell Prettier to ignore formatting my HTML – hence the missing 20%. See some sample files below:

// .prettierrc
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"singleQuote": true
}
// .prettierignore
*.html

Code Spell Checker

Anybody writing code should some sort of spell checker in place. If you’re like me misspell words constantly then this extension will help you spot your blunders and correct them before your users read your mistakes in production!

You’ve inherited 100,000 lines of spaghetti code. Now what?

It’s the first day of your job at your startup as the new Angular developer on the block and you spend the first week warming up to the code base. On Friday your founder interrupts your morning coffee to say that he wants you to start working on updating an existing feature. You say “Sure! It’s about time I got my hands dirty”. You roll up your sleeves and get to work only to find:

  • Copy and pasted PHP code snippets in your Angular project
  • heavily using var instead of let or const
  • == instead of === almost everywhere you can find any object comparison
  • Each HTML and TypeScript file pushes ~1200 lines of code
  • Each route is it’s own component – there are no reusable components

And guess what! It’s all yours buddy. Don’t fret! Here’s what you should not do in this situation.

What you shouldn’t do

1. Don’t whine or complain

Do not set up a meeting with your boss and say “Hey this code base is horrible. We have to stop everything and re-do it all”. What are you expecting your founder to say to this? “Hey, wow bob, well…when you put it that way we should stop all product development and refactor the whole thing the way you want it”. Throwing your problems at your boss does not help the business. If you’re going to present a problem, present a solution or at least things you’ve tried. The business isn’t going to stop because you arrived.

2. Don’t be a cowboy

Your inner perfectionist is coming out now and you have the sudden urge to re-write the code base or at least most of it thinking you can do it better. Don’t. What is working now in production is working. There are many months, maybe even years of knowledge and experience behind that code block you just want to tear apart. Document the mysterious code blocks/components so that the next guy who looks at the code has some knowledge to work with. Refactoring the whole code base will be a drain of your company’s resources.

What you should do (from my experience)

1. Communicate constructively

Everything starts with solid communication. You should communicate with your direct report that the code is not in the best condition where you can just start pumping out features but that you’ll do your best to keep up with the deadlines. Don’t torture yourself by keeping the state of the project a secret and burn yourself out to meet a deadline to “just make it work” because you’re still warming up to the code base. This always leads to problems down the line. Work with your product manager to set appropriate deadlines. 

2. Start enforcing standards from day one

Do your best not to contribute to the spaghetti mess that you inherited. Start implementing some coding standards from day one and continue to enforce those standards. This will be very hard in the beginning, however, you will be very happy you did in a few months. You have to start somewhere right?

3. Understand your data services

I’ve found that the most effective way for me to start breaking up my Angular application in to components is to first understand the services that provide data to the components and make them accessible. When I start making my components, I try to make them as independent as possible from the other components. Understanding where your data is coming from and how to inject it properly in each component will help keep your components more independent, maintainable, and reusable.

3. Create your reusable components

Once you know where you data feeds are at, building reusable and maintainable components is a synch. In time you’ll see your code base come together and maybe you won’t be hating your work as much when sprints are easier to complete because you put the ground work to make reusable components.

Final notes

Refactor the code bit by bit on each deployment and soon you will be a much happier camper in about a month. Work hard but don’t forget to work smart. Please drop some comments below on how you guys have dealt with similar situations.

Upgrade CPU of EC2 instance on AWS

The purpose of the article is to show you how to increase the CPU of your instance on AWS. In this case, I will upgrade my t2.micro instance to a t2.medium instance. You may need to upgrade the CPU on your EC2 instance as the demand for internal operations increases or you see a noticeable decrease in overall performance. Be mindful of the added cost of upgrading your EC2 instance because your bill can accumulate quickly. 

You can find the breakdown of general purpose EC2 instances here https://aws.amazon.com/ec2/instance-types/

Step 1 – Stop your currently running instance

Select the EC2 instance you want to upgrade, then click Actions>Instance State>Stop

Step 2 – Change instance type

Once your EC2 instance has stopped, got to Actions>Instance Settings>Change Instance Type

Once you click on Change Instance Type you will select which instance you want to upgrade to. In this case, I will upgrade my t2.micro to a t2.medium

Step 3 – Start the instance 

Start the instance in Actions>Instance State>Start

Once the instance starts back up you will have successfully upgraded your EC2 instance! In the case that you want to downgrade your instance, you would follow the same steps and select an instance with a lower CPU.

How to switch between versions of Node on Mac with nvm

In this article, we’ll explore how to easily switch between different versions of node using the node version manager (nvm) on MacOS. 

The technologies used in this tutorial are

Step 1 – Install nvm

The first step is to visit the official nvm repository and look through the README.md. To install nvm via curl open up your terminal and enter the following command:

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash

Step 2 – Verify nvm Installation

If nvm was installed successfully, the output of the following command will return ‘nvm’

command -v nvm

If you do not see this output above you may have to restart your terminal application. Once you’ve verified you have installed nvm correctly you’re all set to start managing the global versions on node on your mac!

Step 3 – Install & Manage node

If you’re completely new to nvm I highly recommend reading the output of 

nvm --help

to view, all the options nvm have to offer. To download, install, and compile the latest release of node use

nvm install node

or use the following command to install a specific version of node

nvm install 10.12.0

To view the list of node versions you have installed via nvm use: 

nvm list

As you see in this output, I’m using v10.12.0 on my local mac. If I wanted to switch to node v11.3.0 I can simply do:

nvm use 11.3.0

and nvm will automatically configure my local to use node v11.3.0 instead of v10.12.0. 

Final Notes

Hopefully, you found this how-to on managing node versions very helpful. Please let me know if anything here was not clear and I’ll be happy to update this post!

Simple Angular CI/CD pipeline with GitLab & AWS

In this tutorial, I will show you how to set up a simple CI/CD pipeline that compiles code on GitLab and then deploys to AWS EC2 via AWS CodeDeploy. This tutorial assumes:

  1. You have a working EC2 Ubuntu instance set up with a web server such as Nginx or Apache running and configured. 
  2. You have an existing code repository hosting an Angular project on GitLab.

Technologies Used: 

  • Angular 7
  • Gitlab CI/CD
  • AWS S3
  • AWS CodeDeploy
  • AWS EC2 Ubuntu 18.04 LTS

I’ve made a start project that I will be referencing throughout this project on Github will all the files you need already built in. Check it out here!

Step 1 – Create an S3 to AWS CodeDeploy Pipeline

I really don’t like dropping links in tutorials like this, however, for the sake of not re-writing Amazon’s documentation, I will have to tell you to follow all instructions in the tutorial in the link below. Only once you finished the tutorial will you be able to continue with the rest of this tutorial. Once you’re done with Amazon’s tutorial, you will have a CD pipeline ready to go waiting for GitLab to send the code.

https://docs.aws.amazon.com/codepipeline/latest/userguide/tutorials-simple-s3.html

If you have successfully completed the above tutorial, any changes pushed to your S3 bucket will be deployed immediately to your EC2 instance. Then steps below will show you how to upload your production bundle to S3 from Gitlab to complete the CI/CD pipeline.

Step 2 – Create an appspec.yml 

Welcome back! The first thing we’ll have to do is create an appspec.yml file in the src/ folder of our project. The appspec.yml will tell AWS CodeDeploy to deploy your code in a specific file directory on the server – in our case, it’s the /var/www/ directory. 

version: 0.0
os: linux
files:
  - source: ./
    destination: /var/www/

Then we have to tell angular to include this file as an asset so it stays preserved during the production build. To do this, we edit the assets block in our angular.json file to include "src/appspec.yml":

...
"tsConfig": "src/tsconfig.app.json",
            "assets": [
              "src/favicon.ico",
              "src/assets",
              "src/manifest.json",
              "src/appspec.yml"
            ],
            "styles": [
...

Step 3 – Create .gitlab-ci.yml

Gitlab offers a continuous integration service if you add a

.gitlab-ci.yml

file to the root directory fo your code repository. I’ve provided a sample .gitlab-ci.yml file as seen in example Github project. Please be sure to update the group name and repository name for your own project. If you copy this code please be sure to use your own repository name.

image: node:10

stages:
  - build
  - deploy

build:
  stage: 'build'
  script:
    - apt update
    - apt-get install -y nodejs
    - npm install -y npm@6.11.0
    - nodejs -v
    - npm -v
    - ls -la -F
    - npm ci
    - npx ng build --prod
  cache:
    paths:
      - node_modules/
  artifacts:
    when: on_success
    name: '$CI_JOB_NAME-$CI_COMMIT_REF_NAME'
    paths:
      - dist/angular-gitlab-ci-cd-example/
  only:
    - dev
    - master

deploy:
  stage: 'deploy'
  environment:
    name: production
  script:
    - apt update
    - apt install -y software-properties-common
    - apt install -y python-dev
    - apt install -y python-pip
    - pip install awscli
    - aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID
    - aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY
    - aws configure set region us-east-1
    - ls -la -F
    - mv dist/angular-gitlab-ci-cd-example/appspec.yml dist/
    - cd dist
    - ls -al -F
    - cd ..
    - aws deploy push --application-name angular-gitlab-ci-cd-example --s3-location $AWS_S3_LOCATION --ignore-hidden-files --source dist
  only:
    - master

If you commit to your master branch with this file in the root directory of your project, a CI pipeline will initiate with two steps outlined line-by-line below:

The Build Stage

1.Update the packages in the node:10 Docker container

- apt update

2. Install node & npm

- apt-get install -y nodejs
- npm install -y npm@6.11.0
- nodejs -v
- npm -v

3. Run npm install

- npm install

4. Build the production bundle of Angular using the local cli

- npx ng build --prod

6. Tell GitLab to cache your node_modules so that your project builds faster next time around

cache: 
    paths: 
      - node_modules/

7. This code block creates a build artifact that will be passed onto the next stage in the pipeline if all operations in the container run without error. In the case of Angular7, I’m passing the created dist/ directory to the next stage so that GitLab can send it to AWS to be deployed

  artifacts: 
    when: on_success    
    name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
    paths: 
      - dist/angular-gitlab-ci-cd-example/

8. This keyword tells GitLab only to run this stage when a commit is pushed to either the master and dev branches. You can customize any stage to run a specific set of branched or all branches if that’s what you need. 

  only:
    - dev
    - master

The Deploy Stage

1. Update the packages on the node:10 Docker image, install the python libraries needed for AWS CLI and then install the AWS CLI.

script: 
    - apt update
    - apt install -y software-properties-common
    - apt install -y python-dev  
    - apt install -y python-pip
    - pip install awscli

2. Navigate to your CI/CD settings in GitLab and add the following variables for your $AWS_ACCESS_KEY_ID and $AWS_SECRET_ACCESS_KEY from the CodeDeploy IAM User you created earlier from following the AWS tutorial in Step 1. You should also include the $AWS_S3_LOCATION as a CI/CD variable as well in the following format:

s3://your-bucket-name/your-bundle-name.zip

The <key> will be by the same name as the zip created from the build stage.

3. In this step, we are configuring the AWS CLI with the IAM Credentials of a user with the correct CodePipeline policies attached.

    - aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID
    - aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY
    - aws configure set region us-east-1

4. Remember from step 1 how we made sure the appspec.yml was preserved in the dist/ production bundle? Well, now we have to move it out it to the same directory level as the dist/ folder so that it sits on the same level as the dist/ folder. We have to do this to make the appspec.yml visible to AWS. If we do not do this, the AWS CLI will throw an error stating that it cannot find the appspec.yml file in the next step.

- mv dist/angular-gitlab-ci-cd-example/appspec.yml dist/
- cd dist
- cd .. 

5. Use the AWS CLI to deploy the dist/ bundle to AWS S3

 - aws deploy push --application-name angular-gitlab-ci-cd-example --s3-location $AWS_S3_LOCATION --ignore-hidden-files --source dist
only:
    - master

You’re Done!

Once you push your code to the master branch, navigate to the CI/CD pipeline and watch your code being built. Once GitLab is done building the production bundle, it will send it to AWS S3, which in turn will be deployed onto your live server moments later. I would love to hear your feedback on how I can improve this simple pipeline.