<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Emmanuel K</title>
    <description>The latest articles on DEV Community by Emmanuel K (@emmanuelnk).</description>
    <link>https://dev.to/emmanuelnk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F60750%2Fae073f24-1fde-4c54-8196-8758faaa71cd.jpg</url>
      <title>DEV Community: Emmanuel K</title>
      <link>https://dev.to/emmanuelnk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/emmanuelnk"/>
    <language>en</language>
    <item>
      <title>Simplifying GitHub Actions Workflows Through Typescript</title>
      <dc:creator>Emmanuel K</dc:creator>
      <pubDate>Wed, 30 Aug 2023 12:09:46 +0000</pubDate>
      <link>https://dev.to/emmanuelnk/simplifying-github-actions-workflows-through-typescript-3f31</link>
      <guid>https://dev.to/emmanuelnk/simplifying-github-actions-workflows-through-typescript-3f31</guid>
      <description>&lt;h2&gt;
  
  
  Quick Summary
&lt;/h2&gt;

&lt;p&gt;Harness the power of Typescript for designing your GitHub Actions Workflows. Check out &lt;a href="https://github.com/emmanuelnk/github-actions-workflow-ts"&gt;github-actions-workflow-ts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4uk9k5r6jpefdnwdtk85.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4uk9k5r6jpefdnwdtk85.png" alt="github-actions-workflow-ts logo" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge with YAML
&lt;/h2&gt;

&lt;p&gt;Despite its widespread use in DevOps and CI/CD pipelines—think Kubernetes, Jenkins, CircleCI, Bitbucket Pipelines, CloudFormation, and of course, GitHub Actions—YAML comes with its own set of complexities. Issues often arise from poor indentation, block referencing, and the tedious nature of code reuse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Not YAML for GitHub Actions?
&lt;/h2&gt;

&lt;p&gt;While YAML is somewhat versatile, it's not the most readable or maintainable choice for composing GitHub Actions Workflows. Attempting to implement complex functionality can make your YAML files convoluted, making the process of maintaining, updating or even remembering their function painful.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Epiphany
&lt;/h2&gt;

&lt;p&gt;Enter my introduction to AWS CDK a few years ago — a tool that lets you write infrastructure code in your preferred language and then compiles it into Cloudformation YAML. This sparked an idea: why not apply the same principle to GitHub Actions Workflows?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Inspiration
&lt;/h2&gt;

&lt;p&gt;Initially, I stumbled upon &lt;a href="https://github.com/webiny/github-actions-wac"&gt;webiny/github-actions-wac&lt;/a&gt;, an incredible package that did exactly what I was envisioning. While it's a remarkable tool, I encountered some limitations concerning type exports, file naming, and directory placement. These led me down a path of extensive modifications and enhancements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing github-actions-workflow-ts
&lt;/h2&gt;

&lt;p&gt;Instead of merely tweaking the existing package, I found myself reimagining many of its core functionalities. Thus, I introduce &lt;a href="https://github.com/emmanuelnk/github-actions-workflow-ts"&gt;github-actions-workflow-ts&lt;/a&gt; — a package heavily inspired by the original but with expanded capabilities. While it's still in its beta stage (version 0.X.X), I'm close to releasing a stable 1.0.0 version. However, the current API is robust and already implemented in several of my projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started Now
&lt;/h2&gt;

&lt;p&gt;Curious to see it in action? Explore these Replit examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://replit.com/@EmmanuelKyeyune/github-actions-workflow-ts-example#workflows/simple.example.wac.ts"&gt;Simple Example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://replit.com/@EmmanuelKyeyune/github-actions-workflow-ts-example#src/workflows/advanced.example.wac.ts"&gt;Advanced Example&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;I'm &lt;a href="https://emmanuelnk.com"&gt;Emmanuel&lt;/a&gt;, passionate about software, AWS, and DevOps. If you found this article valuable, feel free to connect with me on &lt;a href="https://www.linkedin.com/in/emmanuel-nsubuga-kyeyune/"&gt;LinkedIn&lt;/a&gt; or follow me on &lt;a href="https://twitter.com/emmanuel_n_k"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>github</category>
      <category>typescript</category>
      <category>cicd</category>
    </item>
    <item>
      <title>How to monitor long running ALTERS in AWS RDS MySQL 5.7+ using the Performance Schema</title>
      <dc:creator>Emmanuel K</dc:creator>
      <pubDate>Fri, 07 Oct 2022 20:02:19 +0000</pubDate>
      <link>https://dev.to/emmanuelnk/how-to-monitor-long-running-alters-in-aws-rds-mysql-57-using-the-performance-schema-4m4o</link>
      <guid>https://dev.to/emmanuelnk/how-to-monitor-long-running-alters-in-aws-rds-mysql-57-using-the-performance-schema-4m4o</guid>
      <description>&lt;p&gt;You've probably landed on this page because you have a MySQL RDS database that has one/many massive tables and anytime you run an &lt;code&gt;ALTER&lt;/code&gt; it takes hours, maybe even days. Unfortunately, MySQL does not provide an easy way to monitor this and neither does RDS monitoring or RDS Performance Insights on AWS.&lt;/p&gt;

&lt;p&gt;Luckily, since MySQL 5.7 there has been support for Progress information and that is implemented with the Performance Schema using the stage events. I recommend you read this excellent &lt;a href="https://mysql.wisborg.dk/2018/08/10/innodb-progress-information/"&gt;article&lt;/a&gt; for a detailed explanation (and also a better way to do the below in MySQL 8). In this article I will focus on MySQL 5.7&lt;/p&gt;

&lt;p&gt;So how do you do it on RDS?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set &lt;code&gt;performance_schema&lt;/code&gt; parameter to 1 in your database's parameter group (⚠Requires instance reboot so that parameter is applied)
&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgt8qqvvvzh39h1kpl202.png" alt="Image description" width="800" height="385"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once the parameter has been applied. Run the following queries&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Enable events_stages_current to monitor threads&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup_consumers&lt;/span&gt; 
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;ENABLED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'YES'&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'events_stages_current'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Check results of below to see that ENABLED &lt;/span&gt;
&lt;span class="c1"&gt;-- and EnabledWithHierarchy are both "YES"&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;ENABLED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ps_is_consumer_enabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;EnabledWithHierarchy&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup_consumers&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'events_stages_current'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If the above works then you are good to go. You can now start an alter and execute this query to see its progress&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;THREAD_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SQL_TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EVENT_NAME&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WORK_COMPLETED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WORK_ESTIMATED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ROUND&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WORK_COMPLETED&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WORK_ESTIMATED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;CompletedPct&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;events_statements_current&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;
&lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;performance_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;events_stages_current&lt;/span&gt; &lt;span class="n"&gt;stage&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;THREAD_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;THREAD_ID&lt;/span&gt;
&lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NESTING_EVENT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EVENT_ID&lt;/span&gt;

&lt;span class="c1"&gt;-- ALTERNATIVELY&lt;/span&gt;
&lt;span class="c1"&gt;----------------&lt;/span&gt;
&lt;span class="c1"&gt;-- SELECT &lt;/span&gt;
&lt;span class="c1"&gt;--  thd_id, &lt;/span&gt;
&lt;span class="c1"&gt;--     conn_id, &lt;/span&gt;
&lt;span class="c1"&gt;--     db, &lt;/span&gt;
&lt;span class="c1"&gt;--     command, &lt;/span&gt;
&lt;span class="c1"&gt;--     state, &lt;/span&gt;
&lt;span class="c1"&gt;--     current_statement,&lt;/span&gt;
&lt;span class="c1"&gt;--     statement_latency, &lt;/span&gt;
&lt;span class="c1"&gt;--     progress, &lt;/span&gt;
&lt;span class="c1"&gt;--     current_memory, &lt;/span&gt;
&lt;span class="c1"&gt;--     program_name&lt;/span&gt;
&lt;span class="c1"&gt;-- FROM sys.session&lt;/span&gt;
&lt;span class="c1"&gt;-- WHERE progress IS NOT NULL;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You should see something like this (where &lt;code&gt;WORK_COMPLETED&lt;/code&gt; is how many rows have been altered and &lt;code&gt;WORK_ESTIMATED&lt;/code&gt; is how many rows are left to alter and &lt;code&gt;CompletedPct&lt;/code&gt; is the completion percent). Run this query everytine you need to see the updated values.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj92j2at7cmzq6f1jyfre.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj92j2at7cmzq6f1jyfre.png" alt="Image description" width="800" height="296"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that's it -- hopefully now you can monitor long running queries on an RDS database!&lt;/p&gt;




&lt;p&gt;Hi I'm &lt;a href="https://emmanuelnk.com"&gt;Emmanuel&lt;/a&gt;! I write about software, AWS and DevOps.&lt;/p&gt;

&lt;p&gt;If you liked this article and want to see more, add me on &lt;a href="https://www.linkedin.com/in/emmanuel-nsubuga-kyeyune/"&gt;LinkedIn&lt;/a&gt; or follow me on &lt;a href="https://twitter.com/emmanuel_n_k"&gt;Twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mysql</category>
      <category>queries</category>
      <category>rds</category>
      <category>aws</category>
    </item>
    <item>
      <title>How to get old LinkedIn app in China</title>
      <dc:creator>Emmanuel K</dc:creator>
      <pubDate>Wed, 22 Dec 2021 20:41:34 +0000</pubDate>
      <link>https://dev.to/emmanuelnk/how-to-get-old-linkedin-app-in-china-3ac8</link>
      <guid>https://dev.to/emmanuelnk/how-to-get-old-linkedin-app-in-china-3ac8</guid>
      <description>&lt;p&gt;TLDR -- The China-localised LinkedIn app has been replaced with InJobs app. If you are unfortunate like me, that localised LinkedIn app is not easily replaceable with a non-China-localised version on your phone (e.g. on most Samsung phones) -- which means you simply cannot use the LinkedIn app on your phone anymore because if you open it, you are prompted to download InJobs app instead. Scroll to 'The solution' section to see how to fix this.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Recently, the LinkedIn mobile app &lt;a href="https://www.nytimes.com/2021/10/14/technology/linkedin-china-microsoft.html"&gt;exited the China market&lt;/a&gt; -- more specifically, &lt;a href="https://blog.linkedin.com/2021/october/14/china-sunset-of-localized-version-of-linkedin-and-launch-of-new-injobs-app"&gt;they sunsetted the normal LinkedIn app and replaced it with a new application called InJobs specifically for China region&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So as the new InJob app rollout is underway, users of the old China-localised LinkedIn app are now blocked from logging in and are instead prompted to download the new InJobs app. This happened to me yesterday. &lt;/p&gt;

&lt;p&gt;This would usually be fine because it means all you have to do is uninstall the China-localised LinkedIn application and install a non-China-localised LinkedIn application from the Google Playstore to continue using the LinkedIn app you are used to.&lt;/p&gt;

&lt;p&gt;But... What happens when you cannot remove it? Unfortunately for most Samsung users, apps like Facebook (HK, TW, Rest of the world), LinkedIn (Mainland, HK, TW, Rest of the world) and many Microsoft apps are in most cases pre-installed bloatware. This means they cannot be uninstalled easily -- only disabled.&lt;/p&gt;

&lt;p&gt;These are apps I use (or at least did not mind being bloatware) so this hasn't been an issue for me -- until now. Unfortunately for users who got their Samsung (and probably other phones) from China region (Mainland, HK, Taiwan) the uninstallable LinkedIn app is the now discontinued China-localised version. &lt;/p&gt;

&lt;p&gt;Since I'm no longer in the China region (where I bought my phone), the InJobs app is useless to me. And even if I wasn't I would probably still want to use the regular LinkedIn app and not a stripped down version. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;Fortunately, there is a work-around. It is quite technical so I hope you know how to use the terminal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Don't attempt this if you don't know what you are doing or have never used the terminal. I am not responsible for you bricking yor phone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-requisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Computer&lt;/li&gt;
&lt;li&gt;Data wire&lt;/li&gt;
&lt;li&gt;Your mobile phone&lt;/li&gt;
&lt;li&gt;Internet&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Initial Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Enable USB debugging on your Phone&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.verizon.com/support/knowledge-base-223020/"&gt;https://www.verizon.com/support/knowledge-base-223020/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Download Android SDK platform tools for your operating system (I use Linux and it is what I will show from now on)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/studio/releases/platform-tools"&gt;https://developer.android.com/studio/releases/platform-tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Unzip platform tools you just downloaded&lt;/li&gt;
&lt;li&gt;Enter the platform tools folder and open your terminal there
&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywekqqletke3vnzui43u.png" alt="Image description" width="800" height="351"&gt;
&lt;/li&gt;
&lt;li&gt;Connect your phone to computer and allow it to share data if prompted&lt;/li&gt;
&lt;li&gt;Download the latest version of LinkedIn APK from APKPure. Download &lt;a href="https://m.apkpure.com/linkedin-jobs-business-news/com.linkedin.android/download"&gt;here&lt;/a&gt;. We need this non-China-localised version to overwrite the existing China localised version -- Don't worry its safe to install. Also, we only need it for a few minutes and all future versions will be from your trusted Google Playstore. Copy the location of the downloaded LinkedIn APK &lt;/li&gt;
&lt;li&gt;Prepare your phone -- Set the screen timeout to be at least 10 minutes. You don't want your screen going odd during this process. Make sure you do not disconnect the wire during any of the following steps.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Next steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open your terminal and do the following
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./adb devices
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see your device connected.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flez29pk11q4ma0g8jy4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flez29pk11q4ma0g8jy4m.png" alt="Image description" width="424" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run the following command to ensure you grant permissions to run commands on your device
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./adb shell pm list packages | &lt;span class="nb"&gt;grep &lt;/span&gt;linkedin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvciuuitv42l8rfrhf0kq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvciuuitv42l8rfrhf0kq.png" alt="Image description" width="638" height="99"&gt;&lt;/a&gt;&lt;br&gt;
You should see that &lt;code&gt;linkedin&lt;/code&gt; is installed&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the LinkedIn apk you just downloaded
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./adb &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; ~/Downloads/LinkedIn&lt;span class="se"&gt;\ &lt;/span&gt;Jobs&lt;span class="se"&gt;\ &lt;/span&gt;Business&lt;span class="se"&gt;\ &lt;/span&gt;News_v4.1.649.1_apkpure.com.apk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this command, &lt;code&gt;-r&lt;/code&gt; will force the APK to update with the new APK and &lt;code&gt;-d&lt;/code&gt; will force the phone to ignore the possibly lower LinkedIn version you want to install&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If prompted to grant permission on your phone, ensure you grant it. If the command fails because of this, just run it again.&lt;/li&gt;
&lt;li&gt;When it is done (may take a while -- give it up to 3 min) -- You should see &lt;code&gt;success&lt;/code&gt;
&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mvyyargoshjpp9v5x6t.png" alt="Image description" width="800" height="96"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. You can now disconnect your phone from your computer and now you should have the correct non-China localised LinkedIn application installed on your phone. &lt;/p&gt;

&lt;p&gt;If the version you downloaded from APKPure is lower than the latest version on Google Play, you will see a prompt to update the app in Google Play. Update it.&lt;/p&gt;

&lt;p&gt;That's all.&lt;/p&gt;




&lt;p&gt;Hi I'm &lt;a href="https://emmanuelnk.com"&gt;Emmanuel&lt;/a&gt;! I write about software, devOps and other random technical stuff.&lt;/p&gt;

&lt;p&gt;If you liked this article and want to see more, add me on &lt;a href="https://www.linkedin.com/in/emmanuel-nsubuga-kyeyune/"&gt;LinkedIn&lt;/a&gt; or follow me on &lt;a href="https://twitter.com/emmanuel_n_k"&gt;Twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>samsung</category>
      <category>linkedin</category>
      <category>adb</category>
    </item>
    <item>
      <title>Saving and Retrieving Well-known Text (WKT) in MySQL or Postgres with TypeORM</title>
      <dc:creator>Emmanuel K</dc:creator>
      <pubDate>Wed, 09 Jun 2021 19:50:49 +0000</pubDate>
      <link>https://dev.to/emmanuelnk/saving-and-retrieving-well-known-text-wkt-in-mysql-or-postgres-with-typeorm-19gf</link>
      <guid>https://dev.to/emmanuelnk/saving-and-retrieving-well-known-text-wkt-in-mysql-or-postgres-with-typeorm-19gf</guid>
      <description>&lt;p&gt;Sometimes in TypeORM you want to save location/coordinates in a type that can take advantage of GIS functions like distance, closeness etc MySQL and Postgres have these functions that get this information when you have &lt;code&gt;geometry&lt;/code&gt; data column types.&lt;/p&gt;

&lt;p&gt;This was surprisingly difficult to find information on so here's my implementation.&lt;/p&gt;

&lt;p&gt;I assume you already have a TypeORM project set up.&lt;/p&gt;

&lt;p&gt;Install these packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;wkx geojson 
npm &lt;span class="nb"&gt;install&lt;/span&gt; @types/geojson &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add this custom transformer that converts GeoJSON to WKT and WKT back to GeoJSON&lt;/p&gt;

&lt;p&gt;Example GeoJSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;point&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;coordinates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;74.534&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;39.123&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example WKT (like you would use in MySQL query):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;POINT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;74&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;534&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would be saved as &lt;code&gt;BLOB&lt;/code&gt; type in MySQL&lt;/p&gt;

&lt;h2&gt;
  
  
  Files
&lt;/h2&gt;

&lt;p&gt;First you need to add the transformer class&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ./src/lib/transformers.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;wkx&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wkx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Geometry&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;geojson&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ValueTransformer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typeorm/decorator/options/ValueTransformer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * TypeORM transformer to convert GeoJSON to MySQL WKT (Well Known Text) e.g. POINT(LAT, LON) and back
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GeometryTransformer&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;ValueTransformer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;geojson&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Geometry&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;wkx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Geometry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseGeoJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;geojson&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toWkt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wkb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;wkb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;wkx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Geometry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wkb&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toGeoJSON&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then inside your target entity class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ./src/entities/user.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;PrimaryGeneratedColumn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;BaseEntity&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typeorm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GeometryTransformer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../transformers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Geometry&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;geojson&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;


&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseEntity&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;PrimaryGeneratedColumn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;idUser&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;

    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;geometry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;spatialFeatureType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Point&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;srid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4326&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// WGS84 reference system&lt;/span&gt;
        &lt;span class="na"&gt;transformer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GeometryTransformer&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Geometry&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Insert GeoJSON
&lt;/h2&gt;

&lt;p&gt;And then finally if you want to insert location data, insert geoJSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ./src/services/user.service.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Geometry&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;geojson&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getRepository&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typeorm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../entities/user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Geometry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Point&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;coordinates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;74.534&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;39.123&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// you should validate the geojson here&lt;/span&gt;
    &lt;span class="c1"&gt;// https://www.npmjs.com/package/geojson-validation&lt;/span&gt;

    &lt;span class="c1"&gt;// if(!validGeoJson(location))throw new Error('invalid GeoJSON')&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Retrieve GeoJSON
&lt;/h2&gt;

&lt;p&gt;And then when you query the object you will get &lt;code&gt;location&lt;/code&gt; as type &lt;code&gt;Geometry&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's it!&lt;/p&gt;




&lt;p&gt;Hi I'm &lt;a href="https://emmanuelnk.com"&gt;Emmanuel&lt;/a&gt;! I write about Software and DevOps.&lt;/p&gt;

&lt;p&gt;If you liked this article and want to see more, add me on &lt;a href="https://www.linkedin.com/in/emmanuel-nsubuga-kyeyune/"&gt;LinkedIn&lt;/a&gt; or follow me on &lt;a href="https://twitter.com/emmanuel_n_k"&gt;Twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>typeorm</category>
      <category>wkt</category>
      <category>geojson</category>
    </item>
    <item>
      <title>Part 4 - Wordpress EC2 instance in ASG with RDS database and ALB- Awesome AWS CDK</title>
      <dc:creator>Emmanuel K</dc:creator>
      <pubDate>Mon, 24 May 2021 10:48:41 +0000</pubDate>
      <link>https://dev.to/emmanuelnk/part-4-wordpress-ec2-instance-in-asg-with-rds-database-and-alb-awesome-aws-cdk-3cij</link>
      <guid>https://dev.to/emmanuelnk/part-4-wordpress-ec2-instance-in-asg-with-rds-database-and-alb-awesome-aws-cdk-3cij</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Abbreviations&lt;/li&gt;
&lt;li&gt;
Setup

&lt;ul&gt;
&lt;li&gt;Setup AWS configuration and CDK&lt;/li&gt;
&lt;li&gt;Create a new project&lt;/li&gt;
&lt;li&gt;Project structure&lt;/li&gt;
&lt;li&gt;Config&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

VPC

&lt;ul&gt;
&lt;li&gt;Setup&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

RDS

&lt;ul&gt;
&lt;li&gt;Setup&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Application Load Balancer

&lt;ul&gt;
&lt;li&gt;Important Load Balancer concepts&lt;/li&gt;
&lt;li&gt;Setup&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

EC2 via Autoscaling Group

&lt;ul&gt;
&lt;li&gt;Setup&lt;/li&gt;
&lt;li&gt;User script&lt;/li&gt;
&lt;li&gt;EC2 instance in ASG&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Deployment

&lt;ul&gt;
&lt;li&gt;Local machine&lt;/li&gt;
&lt;li&gt;Github Actions&lt;/li&gt;
&lt;li&gt;Destroying the stack&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Final result&lt;/li&gt;

&lt;li&gt;

Conclusion

&lt;ul&gt;
&lt;li&gt;Debugging&lt;/li&gt;
&lt;li&gt;Homework Assignments&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Hot off the heels (more than one month ago lol) of the last post, we're going to provision better infrastructure for our Wordpress powered website using the AWS CDK!&lt;/p&gt;

&lt;p&gt;In this tutorial, you will learn how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;setup a Wordpress EC2 instance in an Autoscaling Group (ASG) that is attached to an Application Load Balancer (ALB)&lt;/li&gt;
&lt;li&gt;setup AWS RDSMySQL database using the CDK&lt;/li&gt;
&lt;li&gt;place your RDS MySQL database in an isolated subnet in a custom VPC for better security&lt;/li&gt;
&lt;li&gt;SSH into the Wordpress instance using AWS SSM and IAM credentials&lt;/li&gt;
&lt;li&gt;add CI/CD to your deployment so that you can deploy to multiple environments via Github actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of this will be done in the CDK without needing you to even open the AWS web console. How awesome is that?&lt;/p&gt;

&lt;p&gt;The repository of this project is &lt;a href="https://github.com/emmanuelnk/wordpress-ec2-rds" rel="noopener noreferrer"&gt;emmanuelnk/wordpress-ec2-rds&lt;/a&gt;. You can find all the final code files here.&lt;/p&gt;

&lt;p&gt;Alright, let's go!&lt;/p&gt;

&lt;h1&gt;
  
  
  Abbreviations
&lt;/h1&gt;

&lt;p&gt;I may use certain abbreviations throughout this tutorial. When using AWS generally, these abbreviations are quite common due to the insanely verbose names AWS gives its services&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ALB - &lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html" rel="noopener noreferrer"&gt;Application Load Balancer&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;ASG - &lt;a href="https://docs.aws.amazon.com/autoscaling/ec2/userguide/AutoScalingGroup.html" rel="noopener noreferrer"&gt;AutoScaling Group&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AWS SM - &lt;a href="https://aws.amazon.com/secrets-manager/" rel="noopener noreferrer"&gt;AWS Secrets Manager&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GA - &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;Github Actions&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Setup
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Setup AWS configuration and CDK
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;As usual, you're going to have to ensure you have your AWS dev environment set up (crendentials and config). &lt;/li&gt;
&lt;li&gt;See &lt;a href="https://dev.to/emmanuelnk/awesome-aws-cdk-part-2-setting-up-aws-cdk-3ggj"&gt;Awesome AWS CDK - Part 2 - Setting up AWS CDK&lt;/a&gt; for how to do this.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create a new project
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Make a new directory and init a new TS project:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;wordpress-ec2-rds &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;wordpress-ec2-rds
cdk init &lt;span class="nt"&gt;--language&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Sometimes it so happens that the &lt;code&gt;cdk init&lt;/code&gt; installs an old verison of &lt;code&gt;cdk-core&lt;/code&gt;. A version mismatch between &lt;code&gt;@aws-cdk/core&lt;/code&gt; and &lt;code&gt;@aws-cdk/aws-SOME_SERVICE&lt;/code&gt; can cause errors in Typescript. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you get any weird TS errors while writing CDK code, try checking &lt;code&gt;package.json&lt;/code&gt; to ensure you're using the latest version of &lt;code&gt;@aws-cdk/core&lt;/code&gt; and that that version matches exactly with other CDK packages e.g. below &lt;code&gt;aws-core&lt;/code&gt; and other &lt;code&gt;aws-cdk&lt;/code&gt; packages are all on version &lt;code&gt;1.102.0&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@aws-cdk/aws-ec2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;"^1.102.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@aws-cdk/aws-rds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;"^1.102.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@aws-cdk/aws-secretsmanager"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;"^1.102.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@aws-cdk/core"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;"^1.102.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"dotenv"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;"^8.4.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"source-map-support"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;"^0.5.16"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To be on the safe side, everytime you start a new CDK project, just run:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @aws-cdk/core@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project structure
&lt;/h2&gt;

&lt;p&gt;In the last tutorial, we put all of our infrastructure in one file. This is fine if you're provisioning a few resources. However it's always better to split your resources logically into different files to make the project easier to manage. &lt;/p&gt;

&lt;p&gt;This time, we will create a folder called constructs (a construct is just a particular class that is created from a base service class) i.e. we will then create the following files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="nb"&gt;mkdir &lt;/span&gt;lib/constructs
    &lt;span class="nb"&gt;touch &lt;/span&gt;lib/constructs/ec2.ts
    &lt;span class="nb"&gt;touch &lt;/span&gt;lib/constructs/alb.ts
    &lt;span class="nb"&gt;touch &lt;/span&gt;lib/constructs/rds.ts
    &lt;span class="nb"&gt;touch &lt;/span&gt;lib/constructs/vpc.ts
    &lt;span class="nb"&gt;touch &lt;/span&gt;lib/config.ts
    &lt;span class="nb"&gt;touch&lt;/span&gt; .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where each construct file will contains a specfic AWS service. These constructs will then be imported into the base infrastructure file that the CDK created for us (&lt;code&gt;lib/wordpress-ec2-rds-stack.ts&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;We also create a &lt;code&gt;config.ts&lt;/code&gt; file to hold our configurations and a &lt;code&gt;.env&lt;/code&gt; file to contain our envrionment variables.&lt;/p&gt;

&lt;p&gt;(Optional) add a CI file for Github Actions. At the end of the tutorial I will show you how to deploy to either or both &lt;code&gt;prod&lt;/code&gt; and &lt;code&gt;dev&lt;/code&gt; using Github Actions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .github/workflows/deploy.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are thus the files we will concentrate on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;├── bin
│   └── wordpress-ec2-rds.ts       &lt;span class="c"&gt;# entry file&lt;/span&gt;
├── lib
│   ├── config.ts                  &lt;span class="c"&gt;# stack and account config&lt;/span&gt;
│   ├── constructs
│   │   └── ec2.ts
│   │   └── rds.ts
│   │   └── alb.ts
│   │   └── vpc.ts
│   └── wordpress-ec2-rds-stack.ts &lt;span class="c"&gt;# where we import the constructs&lt;/span&gt;
├── &lt;span class="nb"&gt;test&lt;/span&gt;
│   └── wordpress-ec2-rds.test.ts  &lt;span class="c"&gt;# where we test our infrastructure&lt;/span&gt;
├── .github
│   ├── workflows
│   │   └── deploy.yml             &lt;span class="c"&gt;# CI/CD config file (Github Actions)&lt;/span&gt;
└── .env                           &lt;span class="c"&gt;# environment variables&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Config
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Let's install some required dependencies first&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install dotenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Let's write our configuration file (&lt;code&gt;lib/config.ts&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/config.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="k"&gt;as&lt;/span&gt;  &lt;span class="nx"&gt;dotenv&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// load our environment variables from .env&lt;/span&gt;
&lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// this will be used in resource names&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt;  &lt;span class="nx"&gt;stage&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STAGE&lt;/span&gt;  &lt;span class="o"&gt;||&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dev&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt;  &lt;span class="kd"&gt;const&lt;/span&gt;  &lt;span class="nx"&gt;config&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// we'll use this prefix to help name our provisioned resources&lt;/span&gt;
    &lt;span class="na"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="s2"&gt;`wordpress-ec2-rds-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AWS_ACCOUNT_NUMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AWS_REGION&lt;/span&gt;  &lt;span class="o"&gt;||&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;us-west-2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;deployedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEPLOYED_BY&lt;/span&gt;  &lt;span class="o"&gt;||&lt;/span&gt;  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Let's create our &lt;code&gt;.env&lt;/code&gt; file. The variables below are used to aid deployment from localhost as you will see later.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STAGE=dev
AWS_ACCOUNT_NUMBER=XXXXXXXXXXXXX
AWS_REGION=us-west-2
DEPLOYED_BY=john.doe
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Let's modify our entry file (&lt;code&gt;bin/wordpress-ec2-rds.ts&lt;/code&gt;) from this&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// bin/wordpress-ec2-rds.ts&lt;/span&gt;&lt;span class="cp"&gt;
#!/usr/bin/env node
&lt;/span&gt;&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;source-map-support/register&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="k"&gt;as&lt;/span&gt;  &lt;span class="nx"&gt;cdk&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="nx"&gt;WordpressEc2RdsStack&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../lib/wordpress-ec2-rds-stack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt;  &lt;span class="nx"&gt;app&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="k"&gt;new&lt;/span&gt;  &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt;  &lt;span class="nc"&gt;WordpressEc2RdsStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WordpressEc2RdsStack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="cm"&gt;/* If you don't specify 'env', this stack will be environment-agnostic.
* Account/Region-dependent features and context lookups will not work,
* but a single synthesized template can be deployed anywhere. */&lt;/span&gt;

&lt;span class="cm"&gt;/* Uncomment the next line to specialize this stack for the AWS Account
* and Region that are implied by the current CLI configuration. */&lt;/span&gt;

&lt;span class="c1"&gt;// env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },&lt;/span&gt;

&lt;span class="cm"&gt;/* Uncomment the next line if you know exactly what Account and Region you
* want to deploy the stack to. */&lt;/span&gt;
&lt;span class="c1"&gt;// env: { account: '123456789012', region: 'us-east-1' },&lt;/span&gt;

&lt;span class="cm"&gt;/* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;to this:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// bin/wordpress-ec2-rds.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;source-map-support/register&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="k"&gt;as&lt;/span&gt;  &lt;span class="nx"&gt;cdk&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="nx"&gt;WordpressEc2RdsStack&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../lib/wordpress-ec2-rds-stack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="nx"&gt;config&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../lib/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt;  &lt;span class="nx"&gt;app&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="k"&gt;new&lt;/span&gt;  &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt;  &lt;span class="nc"&gt;WordpressEc2RdsStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WordpressEc2RdsStack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Deploys resources for RDS and S3 powered Wordpress infrastructure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="na"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="na"&gt;Deployedby&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deployedBy&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; It's very important to let the CDK know what account and region you will deploy the stack to. This is why we explicitly set the &lt;code&gt;env&lt;/code&gt; object (which contains &lt;code&gt;account&lt;/code&gt; and &lt;code&gt;region&lt;/code&gt; from your environment variables)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our configuration files and entry files are nopw mostly set up. Let's get to creating our construct files.&lt;/p&gt;

&lt;h1&gt;
  
  
  VPC
&lt;/h1&gt;

&lt;p&gt;In short, a VPC (Virtual Private Cloud) is virtual local network (VLAN) that you create on your cloud service provider. You can then add resources to this network and rest assured this network is separated (isolated) from other people's resources on the cloud provider. This has many advantages, the biggest one being security. &lt;/p&gt;

&lt;p&gt;A VPC, essentially being a virtual LAN looks like this: &lt;code&gt;172.25.0.0/16&lt;/code&gt;. To understand what I just wrote, its important to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.computernetworkingnotes.com/ip-tutorials/ip-address-network-address-and-host-address-explained.html" rel="noopener noreferrer"&gt;network addresses, host addresses, subnet masks&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.keycdn.com/support/what-is-cidr" rel="noopener noreferrer"&gt;CIDR - Classless Inter-Domain Routing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, &lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Subnets.html" rel="noopener noreferrer"&gt;here is a great explanation from Amazon on VPCs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mkdir -p lib/constructs/vpc.ts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;You can either create a new VPC or import an existing one.&lt;/li&gt;
&lt;li&gt;Since I do not have a VPC with isolated subnets, I will create a new VPC&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We need to install the &lt;code&gt;ec2&lt;/code&gt; cdk module to get access to VPC creation functions&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @aws-cdk/aws-ec2
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Here we create the new VPC&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/constructs/vpc.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-ec2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;cidr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Creates a new custom VPC
 *
 * @param  {cdk.Construct} scope stack application scope
 * @param  {StackProps} props props needed to create the resource
 *
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomVPC&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// we export the vpc we just created so other resources can use it&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IVpc&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-vpc`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;maxAzs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// RDS requires at least 2 availability zones&lt;/span&gt;
      &lt;span class="na"&gt;cidr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cidr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// the ip address block of the vpc e.g. '172.22.0.0/16'&lt;/span&gt;
      &lt;span class="na"&gt;enableDnsHostnames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;enableDnsSupport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// expensive -- we don't need that yet (we have no PRIVATE subnets)&lt;/span&gt;
      &lt;span class="na"&gt;natGateways&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;subnetConfiguration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;cidrMask&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-public-`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;subnetType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SubnetType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PUBLIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// for WP instance&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;cidrMask&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-isolated-`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;subnetType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SubnetType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ISOLATED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// for RDS DB&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Here it's important to note that &lt;code&gt;scope&lt;/code&gt; represents the base infrastructure class constructor that the new DefaultVPC instance will be created in. It comes from &lt;code&gt;lib/wordpress-ec2-rds-stack.ts&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Thus let's fetch our custom VPC inside the &lt;code&gt;lib/wordpress-ec2-rds-stack.ts&lt;/code&gt; contructor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Change &lt;code&gt;lib/wordpress-ec2-rds-stack.ts&lt;/code&gt; from:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/wordpress-ec2-rds-stack.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="k"&gt;as&lt;/span&gt;  &lt;span class="nx"&gt;cdk&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt;  &lt;span class="kd"&gt;class&lt;/span&gt;  &lt;span class="nc"&gt;WordpressEc2RdsStack&lt;/span&gt;  &lt;span class="kd"&gt;extends&lt;/span&gt;  &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt;  &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// The code that defines your stack goes here&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;to this:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/wordpress-ec2-rds-stack.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="k"&gt;as&lt;/span&gt;  &lt;span class="nx"&gt;cdk&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="nx"&gt;CustomVPC&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constructs/vpc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt;  &lt;span class="kd"&gt;class&lt;/span&gt;  &lt;span class="nc"&gt;WordpressEc2RdsStack&lt;/span&gt;  &lt;span class="kd"&gt;extends&lt;/span&gt;  &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt;  &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// The code that defines your stack goes here&lt;/span&gt;

        &lt;span class="c1"&gt;// VPC -- fetch the custom VPC&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt;  &lt;span class="nx"&gt;customVPC&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="k"&gt;new&lt;/span&gt;  &lt;span class="nc"&gt;CustomVPC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;cidr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;172.22.0.0/16&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you're not sure about what all these configurations mean, you can read more about configuring VPCs in AWS in this &lt;a href="https://www.simplilearn.com/tutorials/aws-tutorial/aws-vpc" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The important takeaway for this tutorial is that your custom VPC has both PUBLIC and ISOLATED (or PRIVATE) subnets&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  RDS
&lt;/h1&gt;

&lt;p&gt;From the horse's &lt;a href="https://aws.amazon.com/rds/" rel="noopener noreferrer"&gt;mouth&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Amazon Relational Database Service (Amazon RDS) makes it easy to set up, operate, and scale a relational database in the cloud. It provides cost-efficient and resizable capacity while automating time-consuming administration tasks such as hardware provisioning, database setup, patching and backups. It frees you to focus on your applications so you can give them the fast performance, high availability, security and compatibility they need.&lt;/p&gt;

&lt;p&gt;Amazon RDS is available on several  &lt;a href="https://aws.amazon.com/rds/instance-types/" rel="noopener noreferrer"&gt;database instance types&lt;/a&gt;  - optimized for memory, performance or I/O - and provides you with six familiar database engines to choose from, including  &lt;a href="https://aws.amazon.com/rds/aurora/" rel="noopener noreferrer"&gt;Amazon Aurora&lt;/a&gt;,  &lt;a href="https://aws.amazon.com/rds/postgresql/" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt;,  &lt;a href="https://aws.amazon.com/rds/mysql/" rel="noopener noreferrer"&gt;MySQL&lt;/a&gt;, &lt;a href="https://aws.amazon.com/rds/mariadb/" rel="noopener noreferrer"&gt;MariaDB&lt;/a&gt;,  &lt;a href="https://aws.amazon.com/rds/oracle/" rel="noopener noreferrer"&gt;Oracle Database&lt;/a&gt;, and &lt;a href="https://aws.amazon.com/rds/sqlserver/" rel="noopener noreferrer"&gt;SQL Server&lt;/a&gt;. You can use the  &lt;a href="https://aws.amazon.com/dms/" rel="noopener noreferrer"&gt;AWS Database Migration Service&lt;/a&gt;  to easily migrate or replicate your existing databases to Amazon RDS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the last tutorial, we installed and ran the MySQL database on the same instance running Wordpress. You usually want to have your database on a separate (and managed) instance so that you can easily configure it, scale or resize it, back it up, secure it behind a private subnet etc AWS RDS is thus perfect for our use case&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Create the cdk construct file&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; lib/constructs/rds.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Let's install the cdk modules that we need&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @aws-cdk/aws-rds @aws-cdk/aws-secretsmanager
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Let's import what we need&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/constructs/rds.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-ec2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;rds&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-rds&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// this is where we will keep our database credentials e.g. user, password, host etc&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;secrets&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-secretsmanager&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Since the RDS construct is initialized from the base infrastructure class, when we create a new instance we can pass some needed properties&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For example, we need to know the vpc we want to use, the database port or user we would like to use, the name of the secret in secretsmanager that will keep our db secrets etc&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// this is useful when deploying to multiple environments e.g. prod, dev&lt;/span&gt;
  &lt;span class="nl"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Vpc&lt;/span&gt;
  &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
  &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;secretName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Creates a MySQL DB on AWS RDS
 * 
 * @param  {cdk.Construct} scope stack application scope
 * @param  {StackProps} props props needed to create the resource
 * 
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MySQLRdsInstance&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;databaseSecretName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// this is where all the following code will go&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Eveything that follows is inside the constructor of &lt;code&gt;MySQLRdsInstance&lt;/code&gt; i.e. right below the &lt;code&gt;// this is where all the following code will go&lt;/code&gt; comment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Let's get our vpc from the props we just created&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// use the vpc we expoted from lib/constructs/vpc.ts&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customVPC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a security group to allow connections only from inside the vpc&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// create the security group for RDS instance&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ingressSecurityGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SecurityGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-rds-ingress`&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt; 
        &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customVPC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;securityGroupName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-rds-ingress-sg`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nx"&gt;ingressSecurityGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addIngressRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="c1"&gt;// defaultVPC.vpcCidrBlock refers to all the IP addresses in defaultVPC&lt;/span&gt;
      &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Peer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ipv4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defaultVPC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpcCidrBlock&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Port&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tcp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3306&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Allows only local resources inside VPC to access this MySQL port (default -- 3306)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Generate the database secrets using Secrets Manager&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// Dynamically generate the username and password, then store in secrets manager&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;databaseCredentialsSecret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Secret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-MySQLCredentialsSecret`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secretName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Credentials to access Wordpress MYSQL Database on RDS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;generateSecretString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;secretStringTemplate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
          &lt;span class="na"&gt;excludePunctuation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;includeSpace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;generateStringKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now let's create our RDS MySQL instance&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mysqlRDSInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;rds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DatabaseInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-MySqlRDSInstance`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromSecret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;databaseCredentialsSecret&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DatabaseInstanceEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MysqlEngineVersion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VER_5_7_31&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;allocatedStorage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;storageType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StorageType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GP2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;backupRetention&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;days&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="c1"&gt;// t2.micro is free tier so we use it  &lt;/span&gt;
      &lt;span class="na"&gt;instanceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;InstanceType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InstanceClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InstanceSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MICRO&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customVPC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// we chose to place our database in an isolated subnet of our VPC&lt;/span&gt;
      &lt;span class="na"&gt;vpcSubnets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;subnetType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SubnetType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ISOLATED&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="c1"&gt;// if we destroy our database, AWS will take a snapshot of the database instance before terminating it&lt;/span&gt;
      &lt;span class="na"&gt;removalPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RemovalPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SNAPSHOT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// accidental deletion protection -- you need to manually disable this in AWS web console to delete the database&lt;/span&gt;
      &lt;span class="na"&gt;deletionProtection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;securityGroups&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ingressSecurityGroup&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;View the final file &lt;a href="https://github.com/emmanuelnk/wordpress-ec2-rds/blob/master/lib/constructs/rds.ts" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then let's import the RDS construct in our &lt;code&gt;lib/wordpress-ec2-rds-stack.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// lib/wordpress-ec2-rds-stack.ts&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DefaultVPC&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constructs/vpc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MySQLRdsInstance&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constructs/rds&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WordpressEc2RdsStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// The code that defines your stack goes here&lt;/span&gt;

            &lt;span class="c1"&gt;// VPC -- fetch the default VPC&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaultVPC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DefaultVPC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;// RDS -- create the mysql database&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MySQLRdsInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;defaultVPC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// deploy the database in the default VPC!&lt;/span&gt;
                &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wordpress_admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;awesome-wp-site-db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3306&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="c1"&gt;// DB credentials will be saved under this pathname in AWS Secrets Manager&lt;/span&gt;
                &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/rds/mysql/credentials`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// secret pathname&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Application Load Balancer
&lt;/h1&gt;

&lt;p&gt;From the horse's &lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html" rel="noopener noreferrer"&gt;mouth&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Elastic Load Balancing automatically distributes your incoming traffic across multiple targets, such as EC2 instances, containers, and IP addresses, in one or more Availability Zones. It monitors the health of its registered targets, and routes traffic only to the healthy targets. Elastic Load Balancing scales your load balancer as your incoming traffic changes over time. It can automatically scale to the vast majority of workloads.&lt;br&gt;
Elastic Load Balancing supports the following load balancers: Application Load Balancers (ALBs), Network Load Balancers (NLBs), Gateway Load Balancers (GLBs), and Classic Load Balancers (CLBs).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Important Load Balancer concepts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A  &lt;em&gt;load balancer&lt;/em&gt;  serves as the single point of contact for clients. The load balancer distributes incoming application traffic across multiple targets, such as EC2 instances, in multiple Availability Zones. This increases the availability of your application. You add one or more listeners to your load balancer.&lt;/li&gt;
&lt;li&gt;A  &lt;em&gt;listener&lt;/em&gt;  checks for connection requests from clients, using the protocol and port that you configure. The rules that you define for a listener determine how the load balancer routes requests to its registered targets. Each rule consists of a priority, one or more actions, and one or more conditions. When the conditions for a rule are met, then its actions are performed. You must define a default rule for each listener, and you can optionally define additional rules.&lt;/li&gt;
&lt;li&gt;Each  &lt;em&gt;target group&lt;/em&gt;  routes requests to one or more registered targets, such as EC2 instances, using the protocol and port number that you specify. You can register a target with multiple target groups. You can configure health checks on a per target group basis. Health checks are performed on all targets registered to a target group that is specified in a listener rule for your load balancer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;For this tutorial we will be setting up an ALB.&lt;/li&gt;
&lt;li&gt;You can read about the difference between ALB, NLB and CLB &lt;a href="https://medium.com/awesome-cloud/aws-difference-between-application-load-balancer-and-network-load-balancer-cb8b6cd296a4" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new file to define the ALB in and install required CDK dependency&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;lib/constructs/alb.ts
npm &lt;span class="nb"&gt;install&lt;/span&gt; @aws-cdk/aws-elasticloadbalancingv2
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the newly created file:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/constructs/alb.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-ec2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;elbv2&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-elasticloadbalancingv2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IVpc&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Creates an Application Load Balancer for our Wordpress stack
 *
 * @param  {cdk.Construct} scope stack application scope
 * @param  {StackProps} props props needed to create the resource
 *
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WordpressApplicationLoadBalancer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// export the DNS name of the load balancer for WP install &lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;loadBalancerDnsName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="c1"&gt;// export ALB listener so we can attach autoscaling group&lt;/span&gt;
  &lt;span class="nx"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;elbv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IApplicationListener&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;alb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;elbv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ApplicationLoadBalancer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-alb`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;loadBalancerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-alb`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;internetFacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// we need to expose the dns name of the load balancer&lt;/span&gt;
    &lt;span class="c1"&gt;// so we can use it when installing Wordpress later&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loadBalancerDnsName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;alb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loadBalancerDnsName&lt;/span&gt;

    &lt;span class="c1"&gt;// we will  need the listener to add our autoscaling group later&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;alb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-alb-listener`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// print out the dns name of the alb&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CfnOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-alb-dns-name`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;alb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loadBalancerDnsName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then let’s import the ALB construct in our &lt;code&gt;lib/wordpress-ec2-rds-stack.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/wordpress-ec2-rds-stack.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DefaultVPC&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constructs/vpc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MySQLRdsInstance&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constructs/rds&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WordpressApplicationLoadBalancer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constructs/alb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WordpressEc2RdsStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// The code that defines your stack goes here&lt;/span&gt;

    &lt;span class="c1"&gt;// VPC -- fetch the default VPC&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaultVPC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DefaultVPC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// RDS -- create the mysql database&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MySQLRdsInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;defaultVPC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// deploy the database in the default VPC!&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wordpress_admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;awesome-wp-site-db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3306&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// DB credentials will be saved under this pathname in AWS Secrets Manager&lt;/span&gt;
      &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/rds/mysql/credentials`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// secret pathname&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// ALB -- for our single instance&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loadBalancerDnsName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WordpressApplicationLoadBalancer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customVPC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  EC2 via Autoscaling Group
&lt;/h1&gt;

&lt;p&gt;In the last tutorial, we used the CDK to launch a single EC2 instance. This time, we will do the same thing, however, we will launch the instance using an ASG. &lt;/p&gt;

&lt;p&gt;From the horse's &lt;a href="https://docs.aws.amazon.com/autoscaling/ec2/userguide/AutoScalingGroup.html" rel="noopener noreferrer"&gt;mouth&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An  &lt;em&gt;Auto Scaling group&lt;/em&gt;  contains a collection of Amazon EC2 instances that are treated as a logical grouping for the purposes of automatic scaling and management. An Auto Scaling group also enables you to use Amazon EC2 Auto Scaling features such as health check replacements and scaling policies. Both maintaining the number of instances in an Auto Scaling group and automatic scaling are the core functionality of the Amazon EC2 Auto Scaling service.&lt;/p&gt;

&lt;p&gt;The size of an Auto Scaling group depends on the number of instances that you set as the desired capacity. You can adjust its size to meet demand, either manually or by using automatic scaling.&lt;/p&gt;

&lt;p&gt;An Auto Scaling group starts by launching enough instances to meet its desired capacity. It maintains this number of instances by performing periodic health checks on the instances in the group. The Auto Scaling group continues to maintain a fixed number of instances even if an instance becomes unhealthy. If an instance becomes unhealthy, the group terminates the unhealthy instance and launches another instance to replace it. For more information, see  &lt;a href="https://docs.aws.amazon.com/autoscaling/ec2/userguide/healthcheck.html" rel="noopener noreferrer"&gt;Health checks for Auto Scaling instances&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;In our use case, we will use just one instance. This is because Wordpress is installed to the volume attached to this singular instance. If we launched more than two instances, then we would be redirecting users to two seperate WP installations (that may end up having different uploaded content, plugins etc because these files are installed to the file volumes).&lt;/li&gt;
&lt;li&gt;This is desirable in certain cases e.g. if you want to serve users in different geographic regions different website content (without changing the url).&lt;/li&gt;
&lt;li&gt;For most users however, the main use case of autoscaling is to spread server load horizonatally across instances. &lt;/li&gt;
&lt;li&gt;A work-around that I did not implement in this tutorial is to sync uploaded content to S3 and use a shared EFS file system for the wordpress installation (something which I may look at in detail in another tutorial or at the ednof this one)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;What then is the purpose of using an ASG with just one desired instance?&lt;/em&gt; Good question. For this tutorial, it is mostly used to warm you up to the concept of using ASGs and Load Balancers. In later tutorials, I will write applications that are better at utilizing ASGs than Wordpress. Also, if you instance should get accidentally terminated somehow, the ASG will immediately spin up another one. Awesome!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Create the file to hold our EC2 constructs and install dependecies&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;lib/constructs/ec2/ts
npm &lt;span class="nb"&gt;install&lt;/span&gt; @aws-cdk/aws-secretsmanager @aws-cdk/aws-autoscaling
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This time, instead of using an SSH key, we will use &lt;code&gt;aws-ssm&lt;/code&gt; and IAM to access our instances via SSH&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We will place our instance in an autoscaling group with a maximum and minimum capacity of 1&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We are also going to define a helper function to help do some string replacement later on. We will be using this function to insert envrionment secrets into our user script.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;touch lib/utils.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/utils.ts&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Replaces all given substring in a text with new substring e.g.
 *
 * @example
 *  const text = 'The woman and man and woman and man'
 *  const wordsArray = [{ man: 'boy' }, { woman: 'girl' }]
 *
 *  console.log(replaceAllSubstrings(wordsArray, text))
 *  // The girl and boy and girl and boy
 *
 * @param  {Array&amp;lt;Record&amp;lt;string, string&amp;gt;&amp;gt;} wordsArray the words to be substituted and the words to substitute them with
 * @param  {string} text the text from which to substitute the given sub strings
 * @returns the altered text
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;replaceAllSubstrings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;wordsArray&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;wordsArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]]),&lt;/span&gt;
    &lt;span class="nx"&gt;text&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inside &lt;code&gt;lib/constructs/ec2.ts&lt;/code&gt;, we start by getting our imports&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="k"&gt;as&lt;/span&gt;  &lt;span class="nx"&gt;fs&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="k"&gt;as&lt;/span&gt;  &lt;span class="nx"&gt;cdk&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="k"&gt;as&lt;/span&gt;  &lt;span class="nx"&gt;ec2&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-ec2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="k"&gt;as&lt;/span&gt;  &lt;span class="nx"&gt;secrets&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-secretsmanager&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="k"&gt;as&lt;/span&gt;  &lt;span class="nx"&gt;autoscaling&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-autoscaling&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="k"&gt;as&lt;/span&gt;  &lt;span class="nx"&gt;iam&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-iam&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="nx"&gt;config&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="nx"&gt;replaceAllSubstrings&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We then define the &lt;code&gt;props&lt;/code&gt; for the EC2 instance class we are defining&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt;  &lt;span class="nx"&gt;StackProps&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IVpc&lt;/span&gt;
    &lt;span class="cm"&gt;/* the dns name of the ALB */&lt;/span&gt;
    &lt;span class="nx"&gt;dnsName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="cm"&gt;/* the path of the db access secret in AWS SM */&lt;/span&gt;
    &lt;span class="nx"&gt;dbSecretName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; 
    &lt;span class="cm"&gt;/* the path of the wp admin secret in AWS SM */&lt;/span&gt;
    &lt;span class="nx"&gt;wpSecretName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We then define a new class to hold our construct code&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Creates the Wordpress EC2 AutoscalingGroup
 *
 * @param  {cdk.Construct} scope stack application scope
 * @param  {StackProps} props props needed to create the resource
 *
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WordpressAutoScalingGroup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// export our newly created instance&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;asg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;autoscaling&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AutoScalingGroup&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// all the code will go here&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inside the constructor, we can start by importing the custom vpc, defining a role for ur ec2 instance and creating the necessary security groups:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// use the vpc we just created&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customVPC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;

    &lt;span class="c1"&gt;// define a role for the wordpress instances&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-instance-role`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;assumedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CompositePrincipal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ServicePrincipal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ec2.amazonaws.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ServicePrincipal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ssm.amazonaws.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;managedPolicies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;// allows us to access instance via SSH using IAM and SSM&lt;/span&gt;
        &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ManagedPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAwsManagedPolicyName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AmazonSSMManagedInstanceCore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="c1"&gt;// allows ec2 instance to access secrets maanger and retrieve secrets&lt;/span&gt;
        &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ManagedPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAwsManagedPolicyName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SecretsManagerReadWrite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// lets create a security group for the wordpress instance&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;securityGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SecurityGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wordpress-instances-sg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customVPC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;allowAllOutbound&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;securityGroupName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wordpress-instances-sg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// NB: the WP instance will not be exposed to the public Internet this time&lt;/span&gt;
    &lt;span class="c1"&gt;// the Internet can access it through the ALB only&lt;/span&gt;
    &lt;span class="c1"&gt;// the admin can access it (the console) via SSM&lt;/span&gt;
    &lt;span class="nx"&gt;securityGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addIngressRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Peer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ipv4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customVPC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpcCidrBlock&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Port&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tcp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Allows HTTP access from resources inside our VPC (like the ALB)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Since we want to automate the entire installation of WP on our instance, we will need to automate the famous &lt;a href="https://winningwp.com/how-to-install-wordpress-the-famous-five-minute-install-made-simple/" rel="noopener noreferrer"&gt;Wordpress 5 minute install&lt;/a&gt; (See step 9 in this article).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In order to do this, we need to define secrets for our WP Admin&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inside &lt;code&gt;lib/config.ts&lt;/code&gt;, we can add a new object &lt;code&gt;wordpress&lt;/code&gt; to keep some of those secrets:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/config.ts&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`wordpress-ec2-rds-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;wordpress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WP_ADMIN_USER&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WP_ADMIN_EMAIL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin@whatever.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;site&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// name of the database WP will use (cannot have hyphens) &lt;/span&gt;
      &lt;span class="na"&gt;databaseName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WP_DB_NAME&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;awesome_wp_site_db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// the name of our WP  website&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WP_SITE_TITLE&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;awesome-wp-site&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// where we will install WP on our instance volume&lt;/span&gt;
      &lt;span class="na"&gt;installPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WP_SITE_INSTALL_PATH&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/var/www/html/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make sure you add those variables in your &lt;code&gt;.env&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STAGE=dev
AWS_ACCOUNT_NUMBER=XXXXXXXXXXXXX
AWS_REGION=us-west-2
DEPLOYED_BY=john.doe

# Wordpress Site Variables
WP_DB_NAME='awesome_wp_site_db'
WP_SITE_TITLE='awesome_wp_site'
WP_SITE_INSTALL_PATH=/var/www/html/

# Wordpress Admin Secrets
WP_ADMIN_EMAIL=admin@awesomewpsite.com
WP_ADMIN_USER=admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Let's add the code to add our WP admin secrets in AWS SM for Wordpress Admin as well as generate a new WP Admin password inside the &lt;code&gt;WordpressAutoScalingGroup&lt;/code&gt; constructor&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;

    &lt;span class="c1"&gt;// secrets for wp admin&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Secret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WordpressAdminSecrets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wpSecretName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Admin credentials to access Wordpress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;generateSecretString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;secretStringTemplate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wordpress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wordpress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="c1"&gt;// will generate a random password under the object key 'password'&lt;/span&gt;
        &lt;span class="na"&gt;generateStringKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  User script
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We now need to write our user script to configure Wordpress on our instance and automate the famous 5 minute WP install&lt;/li&gt;
&lt;li&gt;In summary, we need to first install the dependencies (e.g. Apache, PHP and Wordpress etc) on the instance&lt;/li&gt;
&lt;li&gt;Then we need to wait for the RDS MySQL database to initialize and be in a ready state &lt;strong&gt;(very important)&lt;/strong&gt;. If the database is not ready, then WP installation will fail because you won't be able to create the necessary tables in the database.&lt;/li&gt;
&lt;li&gt;When the database is ready, we install  Wordpress and that's it!&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read the comments in the script to understand what's going on&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;lib/scripts &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;touch &lt;/span&gt;lib/scripts/wordpress_install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```bash
#! /bin/bash

# lib/scripts/wordpress_install.sh

#------------------ 0.USEFUL FUNCTIONS

# Checks to see if an env is defined (not null) in the bash session
is_defined () {
    for var in "$@" ; do
        if [ ! -z "${!var}" ] &amp;amp; [ "${!var}" != "null" ]; then
            echo "$var is set to ${!var}"
        else
            echo "$var is not set"
            return 1
        fi
    done
}

# Checks if desired db secrets in secrets manager are ready
# Db secrets are only fully ready when the RDS DB is ready
db_secrets_ready () {
    if ! is_defined "AWS_REGION" "DB_SECRETS_PATH";then
        return 0
    fi

    echo "Retrieving secrets..." 
    DB_SECRETS_JSON=$(aws secretsmanager get-secret-value --secret-id $DB_SECRETS_PATH --region $AWS_REGION | jq -r '.SecretString')

    echo "Retrieved secrets." 
    DB_USER=$(echo $DB_SECRETS_JSON | jq -r '.username')
    DB_PASS=$(echo $DB_SECRETS_JSON | jq -r '.password')
    DB_HOST=$(echo $DB_SECRETS_JSON | jq -r '.host')
    DB_PORT=$(echo $DB_SECRETS_JSON | jq -r '.port')

    echo "Checking secrets..." 
    if ! is_defined "DB_USER" "DB_PASS" "DB_HOST" "DB_PORT";then
        echo "Secrets are not ready." 
        return 1
    fi

    echo "Secrets are ready." 
    return 0

}

#------------------  1.INSTALL DEPENDECIES
# update dependencies
yum -y update

# Install Apache
yum -y install httpd

# Start Apache
service httpd start

# Install PHP, PHP CLI, JQ, MySQL
yum -y install php php-cli php-mysql jq mysql mysqladmin

# PHP7 needed for latest wordpress
amazon-linux-extras install php7.4 -y 

# Restart Apache
service httpd restart

# Install the Wordpress CLI which will help us install Wordpress correctly
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
mv wp-cli.phar /usr/local/bin/wp

#------------------  2.SET SCRIPT GLOBAL VARIABLES

# AWS and Wordpress variables to replace
# We will replace these variables in the CDK ec2 construct file
# before using the script to launch an ec2 instance
DB_SECRETS_PATH=_DB_SECRETS_PATH_
WP_SECRETS_PATH=_WP_SECRETS_PATH_
AWS_REGION=_AWS_REGION_
WP_DB_NAME=_WP_DB_NAME_
WP_SITE_TITLE=_WP_SITE_TITLE_
WP_SITE_INSTALL_PATH=_WP_SITE_INSTALL_PATH_
WP_SITE_BASE_DOMAIN=_WP_SITE_BASE_DOMAIN_

# Wait for Secrets Manager to have RDS secret ready
# Certain database secrets (e.g host, port) won't be ready until the database is ready
echo "Waiting up to 20 minutes for Secrets Manager to be ready with Secrets";
for i in {1..240}; do
    echo "try count: $i"
    db_secrets_ready &amp;amp;&amp;amp; break;
    # retry every 30 seconds
    sleep 30s; 
done
echo "Secrets Manager is ready with Secrets";

# Use the AWS CLI to get secrets from Secrets Manager
DB_SECRETS_JSON=$(aws secretsmanager get-secret-value --secret-id $DB_SECRETS_PATH --region $AWS_REGION | jq -r '.SecretString')
WP_SECRETS_JSON=$(aws secretsmanager get-secret-value --secret-id $WP_SECRETS_PATH --region $AWS_REGION | jq -r '.SecretString')

# Parse secrets from JSON response using the useful jq
DB_USER=$(echo $DB_SECRETS_JSON | jq -r '.username')
DB_PASS=$(echo $DB_SECRETS_JSON | jq -r '.password')
DB_HOST=$(echo $DB_SECRETS_JSON | jq -r '.host')
DB_PORT=$(echo $DB_SECRETS_JSON | jq -r '.port')
WP_ADMIN_USER=$(echo $WP_SECRETS_JSON | jq -r '.username')
WP_ADMIN_PASSWORD=$(echo $WP_SECRETS_JSON | jq -r '.password')
WP_ADMIN_EMAIL=$(echo $WP_SECRETS_JSON | jq -r '.email')

# If some ENV is not defined, stop the script
if ! is_defined \
"DB_SECRETS_PATH" \
"WP_SECRETS_PATH" \
"AWS_REGION" \
"WP_DB_NAME" \
"WP_SITE_TITLE" \
"WP_SITE_INSTALL_PATH" \
"WP_SITE_BASE_DOMAIN" \
"DB_USER" \
"DB_PASS" \
"DB_HOST" \
"DB_PORT" \
"WP_ADMIN_USER" \
"WP_ADMIN_PASSWORD" \
"WP_ADMIN_EMAIL" \
; then
    echo "Exiting WP installation script because some variables were undefined"
    exit 0
fi

#------------------  3.CREATE WORDPRESS MYSQL DATABASE

# Wait for the database to be ready
# Usually this should only run once because of the DB secrets in AWS SM are ready
# then it means the database is likely ready as well
for i in {1..30}; do
    echo "try count: $i"
    mysqladmin ping -h "$DB_HOST" -u$DB_USER -p$DB_PASS -P $DB_PORT --silent &amp;amp;&amp;amp; break;
    # retry every 30s
    sleep 30s
done

# Create the database.
echo "Creating the database $WP_DB_NAME..."
mysql -h $DB_HOST -u$DB_USER -p$DB_PASS -P $DB_PORT -e"CREATE DATABASE $WP_DB_NAME"

#------------------  4.SETUP WORDPRESS INSTALLATION

# Download WP Core.
/usr/local/bin/wp core download --path=$WP_SITE_INSTALL_PATH

# Generate the wp-config.php file
/usr/local/bin/wp core config \
--path=$WP_SITE_INSTALL_PATH \
--dbname=$WP_DB_NAME \
--dbuser=$DB_USER \
--dbpass=$DB_PASS \
--dbhost=$DB_HOST \
--extra-php &amp;lt;&amp;lt;PHP
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', true);
define('WP_MEMORY_LIMIT', '256M');
PHP

# Install the WordPress database.
/usr/local/bin/wp core install \
--path=$WP_SITE_INSTALL_PATH \
--url=$WP_SITE_BASE_DOMAIN \
--title=$WP_SITE_TITLE \
--admin_user=$WP_ADMIN_USER \
--admin_password=$WP_ADMIN_PASSWORD \
--admin_email=$WP_ADMIN_EMAIL

# Restart Apache
service httpd restart

# Wordpress is now installed!
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If all goes well, when yuo navigate to the loadbalancer DNS name, the wordpress website should just pop up without any need for any configuration &lt;/li&gt;
&lt;li&gt;Let's now add the user script and insert some required environment variables in the CDK file&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;code&gt;WordpressAutoScalingGroup&lt;/code&gt; constructor&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;

    &lt;span class="c1"&gt;// Fetch the user script from file system as a string&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userScript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lib/scripts/wordpress_install.sh&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Replace the following variable substrings in the userScript&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;modifiedUserScript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;replaceAllSubstrings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_DB_SECRETS_PATH_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dbSecretName&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_WP_SECRETS_PATH_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wpSecretName&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_AWS_REGION_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_WP_DB_NAME_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wordpress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;databaseName&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_WP_SITE_TITLE_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wordpress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_WP_SITE_INSTALL_PATH_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wordpress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;installPath&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_WP_SITE_BASE_DOMAIN_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dnsName&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// our load balancer dns name&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="nx"&gt;userScript&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  EC2 instance in ASG
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Finally, we can create our ec2 instance in an ASG&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="c1"&gt;// finally create and export out autoscaling group&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;autoscaling&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AutoScalingGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-asg`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customVPC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// add the role we created (needs access to AWS SM)&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;instanceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;InstanceType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InstanceClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InstanceSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MICRO&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;machineImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MachineImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;latestAmazonLinux&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;generation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AmazonLinuxGeneration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AMAZON_LINUX_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="c1"&gt;// add our modified user script to launch with instances in this ASG&lt;/span&gt;
  &lt;span class="na"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UserData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modifiedUserScript&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="c1"&gt;// we only want one instance in our ASG&lt;/span&gt;
  &lt;span class="na"&gt;minCapacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;maxCapacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;associatePublicIpAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;vpcSubnets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;subnetType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SubnetType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PUBLIC&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The final file should look like &lt;a href="https://github.com/emmanuelnk/wordpress-ec2-rds/blob/master/lib/constructs/ec2.ts" rel="noopener noreferrer"&gt;this&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We then need to attach the ASG we just created as a target to the the listener of the ALB we created earlier, using port 80 &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This will redirect all requests for WP at the loadblancer to port 80 of our WP instance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Right below the EC2 construct in the  &lt;code&gt;WordpressEc2RdsStack&lt;/code&gt; constructor, add:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// lets add our autoscaling group to our load balancer&lt;/span&gt;
    &lt;span class="nx"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addTargets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-wp-asg-targets`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;asg&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The final &lt;code&gt;lib/wordpress-ec2-rds-stack.ts&lt;/code&gt; should look like:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CustomVPC&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constructs/vpc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MySQLRdsInstance&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constructs/rds&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WordpressAutoScalingGroup&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constructs/ec2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WordpressApplicationLoadBalancer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constructs/alb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WordpressEc2RdsStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// The code that defines your stack goes here&lt;/span&gt;

    &lt;span class="c1"&gt;// VPC -- fetch the custom VPC&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customVPC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CustomVPC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;cidr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;172.22.0.0/16&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// RDS -- create the mysql database&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MySQLRdsInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customVPC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wordpress_admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;awesome-wp-site-db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3306&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// DB credentials will be saved under this pathname in AWS Secrets Manager&lt;/span&gt;
      &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/rds/mysql/credentials`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// secret pathname&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// Application Loadbalancer -- for our single instance&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loadBalancerDnsName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WordpressApplicationLoadBalancer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customVPC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// EC2 -- create the Wordpress instance in an autoscaling group&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;asg&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WordpressAutoScalingGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customVPC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;dnsName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;loadBalancerDnsName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;dbSecretName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/rds/mysql/credentials`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;wpSecretName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/wordpress/admin/credentials`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// lets add our autoscaling group to our load balancer&lt;/span&gt;
    &lt;span class="nx"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addTargets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-wp-asg-targets`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;asg&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;At this point,  all the resources are ready to be deployed!&lt;/p&gt;
&lt;h1&gt;
  
  
  Deployment
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Local machine
&lt;/h2&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To deploy from your local machine, make sure all your aws credentials and configurations are correctly setup&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ensure you have the &lt;code&gt;.env&lt;/code&gt; file with the following environment variables setup:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STAGE=dev
AWS_ACCOUNT_NUMBER=XXXXXXXXXXXXXXX
AWS_REGION=us-west-2
DEPLOYED_BY=john.doe

# Wordpress Variables
WP_DB_NAME='awesome_wp_site_db'
WP_SITE_TITLE='awesome_wp_site'
WP_SITE_INSTALL_PATH=/var/www/html/

# Wordpress Admin Secrets
WP_ADMIN_EMAIL=admin@awesomewpsite.com
WP_ADMIN_USER=admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can then first try to synthesize the stack and make sure everything is correct&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cdk synth &lt;span class="nt"&gt;--profile&lt;/span&gt; default
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If the CDK outputs a YAML file to the console without any issue, then you can deploy&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cdk deploy &lt;span class="nt"&gt;--profile&lt;/span&gt; default
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You will be asked to approve of IAM changes before the deployment can continue&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Github Actions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Deploying from your local machine is not recommended in a production environment.&lt;/li&gt;
&lt;li&gt;Fortunately, Github provides a free CI/CD service called &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;Github Actions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;All we have to do in this instance is create a simple YAML configuration file that can help us deploy to different stages using GA (for the purposes of this tutorial, just &lt;code&gt;dev&lt;/code&gt; and &lt;code&gt;prod&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;From the root of your project&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .github/workflows &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;touch&lt;/span&gt; .github/workflows/deploy.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open up &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt; and add the following code&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;dev&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nelonoel/branch-name@v1.0.1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cdk deploy&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;youyo/aws-cdk-github-actions@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;cdk_subcommand&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;deploy'&lt;/span&gt;
          &lt;span class="na"&gt;cdk_args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--require-approval&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;never'&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;STAGE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.BRANCH_NAME == 'master' &amp;amp;&amp;amp; 'prod' || 'dev'  }}&lt;/span&gt;
          &lt;span class="na"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;AWS_DEFAULT_REGION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_DEFAULT_REGION }}&lt;/span&gt;
          &lt;span class="na"&gt;AWS_ACCOUNT_NUMBER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ACCOUNT_NUMBER }}&lt;/span&gt;
          &lt;span class="na"&gt;DEPLOYED_BY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DEPLOYED_BY }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What's going on?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GA will only run this script when a push/merge to the branches &lt;code&gt;dev&lt;/code&gt; or &lt;code&gt;master&lt;/code&gt; happens&lt;/li&gt;
&lt;li&gt;GA will create an Ubuntu container, checkout the repository and run CDK deploy&lt;/li&gt;
&lt;li&gt;A useful GA action called &lt;code&gt;branch-name@v1.0.1&lt;/code&gt; gets the name fo the branch we are working on and deploys to the correct stage based on that branch (it sets the &lt;code&gt;STAGE&lt;/code&gt; env variable)&lt;/li&gt;
&lt;li&gt;GA action &lt;code&gt;aws-cdk-github-actions@v1&lt;/code&gt; runs &lt;code&gt;cdk deploy&lt;/code&gt; and deploys the resources to AWS&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;In order for this to work, you have to to go the settings of your repository on Github and add the follwowing secrets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS_ACCESS_KEY_ID&lt;/li&gt;
&lt;li&gt;AWS_SECRET_ACCESS_KEY&lt;/li&gt;
&lt;li&gt;AWS_DEFAULT_REGION&lt;/li&gt;
&lt;li&gt;AWS_ACCOUNT_NUMBER&lt;/li&gt;
&lt;li&gt;DEPLOYED_BY&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;For AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, you can create a new user in IAM in the AWS console called &lt;code&gt;github.actions.bot&lt;/code&gt; that has administrator privileges and only PROGRAMMATIC ACCESS and paste those values in Github settings as secrets&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Destroying the stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;To destroy the stack from your local machine using the CDK, just run&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cdk destroy &lt;span class="nt"&gt;--profile&lt;/span&gt; default
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To destroy the stack from AWS console&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log in to the AWS console&lt;/li&gt;
&lt;li&gt;Go to Cloudformation&lt;/li&gt;
&lt;li&gt;Find your stack &amp;gt; Destroy/Delete&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  Final result
&lt;/h1&gt;

&lt;p&gt;Whether you deploy from your local machine or via Github actions, if all goes well, after about 20 minutes (RDS databases take a while to initialize) you should see this output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjwgk7u4pm2wjmto309up.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjwgk7u4pm2wjmto309up.png" alt="Alt Text" width="800" height="139"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In your browser, navigate to the DNS name printed in the output of your local machine console or the GA console(replace the asteriks with the region you deployed in).&lt;/li&gt;
&lt;li&gt;Alternatively, you can find the DNS name of the ALB via EC2 console &amp;gt; Load balancers&lt;/li&gt;
&lt;li&gt;You should then see:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4akkty7z2mfkbpvxgqcn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4akkty7z2mfkbpvxgqcn.png" alt="Alt Text" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;In this tutorial I tried to keep things simple and did not add many improvements that I would likely add in a real production scenario (See the Homework Assignments section for improvements that can make your WP installation Production ready on AWS)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Debugging
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To access the ec2 instance your ASG just spn up, you need to get the instance id from the AWS EC2 console&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once you have the instance id, to log into your instance, just do:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm start-session &lt;span class="nt"&gt;--target&lt;/span&gt; &lt;span class="s2"&gt;"i-0191364267ad972a2"&lt;/span&gt; &lt;span class="nt"&gt;--profile&lt;/span&gt; default
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;where &lt;code&gt;i-0191364267ad972a2&lt;/code&gt; is the id of the instance as seen in the AWS console. Cool right? No need for SSH keys! &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Of course, if you still want to use regular SSH then in the CDK you have to open port 22 and create an SSH key pair on your machine and upload the public key to the ec2 instance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If Wordpress does not load correctly when you navigate to the ALB DNS name, then it is likely something with the configuration of the database, or access to secrets manager went wrong.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can check the user script logs in the ec2 instance&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# list all log files related to ec2 start up scripts&lt;/span&gt;
find / &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*cloud*log"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Homework Assignments
&lt;/h2&gt;

&lt;p&gt;There are many improvements you can make to this CDK stack to make a better WP installation. I'll leave them as homework&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an S3 bucket using the CDK and use this &lt;a href="https://github.com/humanmade/S3-Uploads" rel="noopener noreferrer"&gt;Wordpress plugin&lt;/a&gt; to sync Wordpress uploads to AWS S3. &lt;em&gt;Hint: You install this plugin via the user script.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Use the CDK to create an &lt;a href="https://aws.amazon.com/efs/" rel="noopener noreferrer"&gt;EFS filesystem&lt;/a&gt; to install Wordpress to instead of installing Wordpress to &lt;code&gt;var/www/html&lt;/code&gt; on the default attached volume (which limits WP to one instance). The key here is the same EFS filesystem can be used by many instances. &lt;/li&gt;
&lt;li&gt;The above two improvements combined will allow you to use more than one instance in the WP ASG and make your Wordpress Installation much more highly available and resilient.&lt;/li&gt;
&lt;li&gt;Create a cloudfront distribution to serve the WP content from the S3 bucket you just created&lt;/li&gt;
&lt;li&gt;Buy a cheap 5 dollar &lt;code&gt;.link&lt;/code&gt; domain on AWS Route53 and use it in the CDK instead of the ALB dnsName.  That way, your site can be accessed via something like &lt;code&gt;mywebsite.link&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;CloudWatchAgentServerPolicy&lt;/code&gt; to Wordpress instance role and in the user script, install Cloudwatch Agent so that you can collect logs and internal metrics from the instance in AWS Cloudwatch. See this &lt;a href="https://aws.amazon.com/blogs/mt/simplifying-apache-server-logs-with-amazon-cloudwatch-logs-insights/" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Hi I'm &lt;a href="https://emmanuelnk.com" rel="noopener noreferrer"&gt;Emmanuel&lt;/a&gt;! I write about Software and DevOps.&lt;/p&gt;

&lt;p&gt;If you liked this article and want to see more, add me on &lt;a href="https://www.linkedin.com/in/emmanuel-nsubuga-kyeyune/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or follow me on &lt;a href="https://twitter.com/emmanuel_n_k" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>awscdk</category>
      <category>ec2</category>
      <category>devops</category>
    </item>
    <item>
      <title>Quickly install software on a new Ubuntu installation with GMUAR</title>
      <dc:creator>Emmanuel K</dc:creator>
      <pubDate>Fri, 19 Mar 2021 08:47:21 +0000</pubDate>
      <link>https://dev.to/emmanuelnk/quickly-install-software-on-a-new-ubuntu-installation-with-gmuar-457i</link>
      <guid>https://dev.to/emmanuelnk/quickly-install-software-on-a-new-ubuntu-installation-with-gmuar-457i</guid>
      <description>&lt;p&gt;GMUAR -- Get Me Up And Running -- is a pure bash command-line utility program to install a host of common software on Ubuntu/Debian. This helps get software onto fresh Ubuntu installs fast.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/emmanuelnk/GetMeUpAndRunning"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LRB6IO4_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://gh-card.dev/repos/emmanuelnk/GetMeUpAndRunning.svg" alt="emmanuelnk/GetMeUpAndRunning - GitHub" width="442" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was inspired to create this by all the &lt;code&gt;sudo apt install&lt;/code&gt; commands I would have to get through  just to get a new development machine up and running. Some software also wasn't easily installable via &lt;code&gt;apt&lt;/code&gt; and need the addition of repositories, &lt;code&gt;curl&lt;/code&gt;ing scripts etc.&lt;/p&gt;

&lt;p&gt;This is my solution to all of that.&lt;/p&gt;

&lt;p&gt;Simply clone the &lt;a href="https://github.com/emmanuelnk/GetMeUpAndRunning"&gt;repository&lt;/a&gt; and run &lt;code&gt;./gmuar.sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2v8ybbyo55udxejf23za.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2v8ybbyo55udxejf23za.png" alt="Alt Text" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The program runs through several categories of software to install:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;setup (e.g. &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;pip3&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;utilities (e.g. &lt;code&gt;net-tools&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;desktop (e.g. &lt;code&gt;spotify&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;customization (e.g &lt;code&gt;zsh&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;development (e.g. &lt;code&gt;node.js&lt;/code&gt; )&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It has the ability to check via &lt;code&gt;apt&lt;/code&gt;, &lt;code&gt;PATH&lt;/code&gt; or even filename to determine whether a  program has been installed (since not all programs are installed via &lt;code&gt;apt&lt;/code&gt; or &lt;code&gt;snap&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;GMUAR can be extended by adding your own scripts to add your own desired software. Instructions are in the repository &lt;a href="https://github.com/emmanuelnk/GetMeUpAndRunning"&gt;README&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check it out now!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/emmanuelnk/GetMeUpAndRunning"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LRB6IO4_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://gh-card.dev/repos/emmanuelnk/GetMeUpAndRunning.svg" alt="emmanuelnk/GetMeUpAndRunning - GitHub" width="442" height="151"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Hi I'm &lt;a href="https://emmanuelnk.com"&gt;Emmanuel&lt;/a&gt;! I write about Software and DevOps.&lt;/p&gt;

&lt;p&gt;If you liked this article and want to see more, add me on &lt;a href="https://www.linkedin.com/in/emmanuel-nsubuga-kyeyune/"&gt;LinkedIn&lt;/a&gt; or follow me on &lt;a href="https://twitter.com/emmanuel_n_k"&gt;Twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>ubuntu</category>
      <category>bash</category>
      <category>terminal</category>
    </item>
    <item>
      <title>Part 3 - Simple EC2 instance - Awesome AWS CDK</title>
      <dc:creator>Emmanuel K</dc:creator>
      <pubDate>Thu, 18 Mar 2021 11:06:56 +0000</pubDate>
      <link>https://dev.to/emmanuelnk/part-3-simple-ec2-instance-awesome-aws-cdk-37ia</link>
      <guid>https://dev.to/emmanuelnk/part-3-simple-ec2-instance-awesome-aws-cdk-37ia</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Bootstrapping a new CDK Application&lt;/li&gt;
&lt;li&gt;
Structure and Setup of a CDK application

&lt;ul&gt;
&lt;li&gt;Structure&lt;/li&gt;
&lt;li&gt;Setup&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Writing the infrastructure code&lt;/li&gt;

&lt;li&gt;Creating a new Key Pair in the AWS Console&lt;/li&gt;

&lt;li&gt;Deploy&lt;/li&gt;

&lt;li&gt;Accessing the instance&lt;/li&gt;

&lt;li&gt;Updating the deployed stack&lt;br&gt;
&lt;/li&gt;

&lt;li&gt;

Testing the stack

&lt;ul&gt;
&lt;li&gt;Test requirements&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Destroying the stack&lt;/li&gt;

&lt;li&gt;Notes&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;li&gt;Up next&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Introduction
&lt;/h2&gt;

&lt;p&gt;Most tutorials on AWS try to get you to deploy the world famous &lt;code&gt;t2.micro&lt;/code&gt; instance  (a small virtual server under the free usage tier on AWS) using the AWS console. You then go on to install something like Wordpress through SSH or through a &lt;em&gt;user script&lt;/em&gt; (a script that runs when an instance is created) that you define in the AWS console. &lt;/p&gt;

&lt;p&gt;So that's exactly what we're going to deploy. But we're going to use the AWS CDK instead.&lt;/p&gt;

&lt;p&gt;This is what you'll learn in this tutorial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bootstrapping a new CDK application&lt;/li&gt;
&lt;li&gt;The structure and setup of a CDK application&lt;/li&gt;
&lt;li&gt;How to provision and setup an ec2 instance &lt;/li&gt;
&lt;li&gt;How to setup terminal access to the instance via SSH key.&lt;/li&gt;
&lt;li&gt;How to update the ec2 instance with a user script and update the deployed cdk stack&lt;/li&gt;
&lt;li&gt;How to write tests for the cdk application&lt;/li&gt;
&lt;li&gt;How to destroy the deployed stack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's go!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Bootstrapping a new CDK Application
&lt;/h2&gt;

&lt;p&gt;Using your terminal, create a new directory &lt;code&gt;simple-ec2&lt;/code&gt; and cd into it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

mkdir simple-ec2 &amp;amp;&amp;amp; cd simple-ec2


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We previously setup the AWS CDK cli globally. If you haven't done that see &lt;a href="https://dev.to/emmanuelnk/awesome-aws-cdk-part-2-setting-up-aws-cdk-3ggj"&gt;Part 2&lt;/a&gt; in this series. &lt;/p&gt;

&lt;p&gt;Bootstrap a new cdk project template that uses Typescript:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

cdk init --language=typescript


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This will initialize a new cdk project for you in Typescript.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;npm update&lt;/code&gt; to ensure you're using the latest version of the CDK. &lt;/li&gt;
&lt;li&gt;If you have version conflicts between &lt;code&gt;@aws-cdk/core&lt;/code&gt; and other &lt;code&gt;@aws-cdk&lt;/code&gt; sub-packages, then you'll come across some weird errors. &lt;code&gt;@aws-cdk/core&lt;/code&gt; and every other imported &lt;code&gt;@aws-cdk/PACKAGE&lt;/code&gt; should have the same version.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Structure and Setup of a CDK application
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Structure
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 bash
# tree -I 'node_modules'
.
├── bin
│   └── simple-ec2.ts       # entry point
├── cdk.json
├── jest.config.js          # for tests
├── lib                     # where the infrastructure code you write will go
│   └── simple-ec2-stack.ts 
├── package.json
├── package-lock.json
├── README.md
├── test                    # test folder
│   └── simple-ec2.test.ts
└── tsconfig.json


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;./bin/simple-ec2.ts&lt;/code&gt; is the entry point file used by the cdk. This is where you define your stack(s).&lt;/li&gt;
&lt;li&gt;The IaC that provisions the resources will be inside the &lt;code&gt;lib&lt;/code&gt; folder and is required by &lt;code&gt;./bin/simple-ec2.ts&lt;/code&gt; during &lt;code&gt;synth&lt;/code&gt; and &lt;code&gt;deploy&lt;/code&gt; actions. I'll explain both commands later.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;./test/simple-ec2.test.ts&lt;/code&gt; contains the template code to test your CDK application&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Setup
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;./bin/simple-ec2.ts&lt;/code&gt; a  new &lt;code&gt;App()&lt;/code&gt; is defined and this represents a single stack. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can add a description for our stack in this file. &lt;/li&gt;
&lt;li&gt;This description will be visible in the Cloudformation console:
```ts
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;// ./bin/simple-ec2.ts&lt;/p&gt;

&lt;p&gt;import 'source-map-support/register';&lt;br&gt;
import * as cdk from '@aws-cdk/core';&lt;br&gt;
import { SimpleEc2Stack } from '../lib/simple-ec2-stack';&lt;/p&gt;

&lt;p&gt;const app = new cdk.App();&lt;br&gt;
new SimpleEc2Stack(app, 'SimpleEc2Stack', {&lt;br&gt;
   description: 'This is a simple EC2 stack'&lt;br&gt;
});&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Let's head over to `./lib/simple-ec2-stack.ts` and see what the CDK boostrapped for us:

```ts


// ./lib/simple-ec2-stack.ts

import * as cdk from '@aws-cdk/core';

export class SimpleEc2Stack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here
  }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As you can see, the &lt;code&gt;cdk init&lt;/code&gt; command bootstrapped a nice template for us to get to writing our IaC fast. The base class &lt;code&gt;cdk.Stack&lt;/code&gt; gives us the ability to create a new Cloudformation stack. &lt;/p&gt;

&lt;p&gt;We also need to create a &lt;code&gt;.env&lt;/code&gt; file to keep our AWS Account number and the region we will use. In the root of the project create a file called &lt;code&gt;.env&lt;/code&gt; and add the following. Replace the &lt;code&gt;xxXxXxxXXxXxx&lt;/code&gt; with your AWS account number and use the region you want.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

AWS_ACCOUNT_NUMBER=xxXxXxxXXxXxx
AWS_ACCOUNT_REGION=us-west-2


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Writing the infrastructure code
&lt;/h2&gt;

&lt;p&gt;We want to create an ec2 instance so we will need the &lt;code&gt;@aws-cdk/ec2&lt;/code&gt; library. (This is the same process for any other AWS service you need to provision resources). We will also need &lt;code&gt;@aws-cdk/aws-iam&lt;/code&gt; library to give permissions to our instance to do stuff. We also want to be able to read our &lt;code&gt;.env&lt;/code&gt; file so lets also install &lt;code&gt;dotenv&lt;/code&gt; package&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

npm install @aws-cdk/aws-ec2 @aws-cdk/aws-iam dotenv


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Remember, since the CDK is written in Typescript and is typed excellently, while typing you can access intellisense and see the various properties of CDK resources e.g. in the image below I can see what properties an instance of &lt;code&gt;ec2.Instance()&lt;/code&gt; class has.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frwvn83wjbix9cgv72j5r.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frwvn83wjbix9cgv72j5r.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here goes our first iteration:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-ec2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// import ec2 library &lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-iam&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// import iam library for permissions&lt;/span&gt;

&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AWS_ACCOUNT_NUMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AWS_REGION&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleEc2Stack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// its important to add our env config here otherwise CDK won't know our AWS account number&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// Get the default VPC. This is the network where your instance will be provisioned&lt;/span&gt;
    &lt;span class="c1"&gt;// All activated regions in AWS have a default vpc. &lt;/span&gt;
    &lt;span class="c1"&gt;// You can create your own of course as well. https://aws.amazon.com/vpc/&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaultVpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromLookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VPC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isDefault&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// Lets create a role for the instance&lt;/span&gt;
    &lt;span class="c1"&gt;// You can attach permissions to a role and determine what your&lt;/span&gt;
    &lt;span class="c1"&gt;// instance can or can not do&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simple-instance-1-role&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// this is a unique id that will represent this resource in a Cloudformation template&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;assumedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ServicePrincipal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ec2.amazonaws.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// lets create a security group for our instance&lt;/span&gt;
    &lt;span class="c1"&gt;// A security group acts as a virtual firewall for your instance to control inbound and outbound traffic.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;securityGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SecurityGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simple-instance-1-sg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;defaultVpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;allowAllOutbound&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// will let your instance send outboud traffic&lt;/span&gt;
        &lt;span class="na"&gt;securityGroupName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simple-instance-1-sg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// lets use the security group to allow inbound traffic on specific ports&lt;/span&gt;
    &lt;span class="nx"&gt;securityGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addIngressRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Peer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;anyIpv4&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Port&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tcp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Allows SSH access from Internet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;securityGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addIngressRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Peer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;anyIpv4&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Port&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tcp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Allows HTTP access from Internet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;securityGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addIngressRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Peer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;anyIpv4&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Port&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tcp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Allows HTTPS access from Internet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Finally lets provision our ec2 instance&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simple-instance-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;defaultVpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;securityGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;securityGroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;instanceName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simple-instance-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;instanceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;InstanceType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="c1"&gt;// t2.micro has free tier usage in aws&lt;/span&gt;
        &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InstanceClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InstanceSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MICRO&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;machineImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MachineImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;latestAmazonLinux&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;generation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AmazonLinuxGeneration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AMAZON_LINUX_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;

      &lt;span class="na"&gt;keyName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simple-instance-1-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// we will create this in the console before we deploy&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// cdk lets us output prperties of the resources we create after they are created&lt;/span&gt;
    &lt;span class="c1"&gt;// we want the ip address of this new instance so we can ssh into it later&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CfnOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simple-instance-1-output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instancePublicIp&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Creating a new Key Pair in the AWS Console
&lt;/h2&gt;

&lt;p&gt;Before we try to deploy our newly created instance, we need to go to the AWS console and create a key pair that we will use to access the instance called &lt;code&gt;simple-instance-1-key&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log into the AWS console. &lt;/li&gt;
&lt;li&gt;Go to &lt;code&gt;EC2&lt;/code&gt; dashboard. &lt;/li&gt;
&lt;li&gt;Go to Key Pairs and click create Key Pair&lt;/li&gt;
&lt;li&gt;Enter key name as &lt;code&gt;simple-instance-1-key&lt;/code&gt; and click create&lt;/li&gt;
&lt;li&gt;Your new key pair will be created and your browser will automatically download a new &lt;code&gt;.pem&lt;/code&gt; file called &lt;code&gt;simple-instance-1-key.pem&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;this is the key file you'll use to gain access to your instance via SSH&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvo9h9zejdykpkapld38a.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvo9h9zejdykpkapld38a.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new directory under &lt;code&gt;.aws/&lt;/code&gt; called &lt;code&gt;pems&lt;/code&gt;
```bash
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;mkdir ~./aws/pems/&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- move the newly downloaded file to this directory and give it the necessary permissions
```bash


mv ~/Downloads/simple-instance-1-key.pem ~/.aws/pems

# important step or your key file won't work
chmod 400 ~/.aws/pems/simple-instance-1-key.pem


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Now that we have our key file properly setup, lets deploy our instance!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Deploy
&lt;/h2&gt;

&lt;p&gt;Remember we set up our aws profiles and crednetials in &lt;code&gt;~/.aws/config&lt;/code&gt; and &lt;code&gt;~/.aws/credentials&lt;/code&gt; back in &lt;a href="https://dev.to/emmanuelnk/awesome-aws-cdk-part-2-setting-up-aws-cdk-3ggj"&gt;part 2&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I will be deploying to my &lt;code&gt;default&lt;/code&gt; profile which is linked to my personal AWS account with the region &lt;code&gt;us-west-2&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;If you have another profile you want to use then in the commands below use that profile name instead of &lt;code&gt;default&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In your terminal:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

cdk synth --profile default


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This command will synthesize your stack.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When CDK apps are executed, they produce (or “synthesize”, in CDK parlance) an AWS CloudFormation template for each stack defined in your application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Essentially it will print the cloudformation template for your stack to your console. &lt;/li&gt;
&lt;li&gt;It's a good way to check that there's nothing wrong with your stack before trying to deploy since &lt;code&gt;cdk synth&lt;/code&gt; will verify the resources you are trying to provision can actually be provisioned. &lt;/li&gt;
&lt;li&gt;You should something like this:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

❯ cdk synth &lt;span class="nt"&gt;--profile&lt;/span&gt; default
Resources:
  simpleinstance1role9EEDA67C:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
        Version: &lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;
   ...
   ...
   ...


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If the entire stack prints without error then you're okay to go.&lt;/p&gt;

&lt;p&gt;Now we can deploy:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

cdk deploy &lt;span class="nt"&gt;--profile&lt;/span&gt; default


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You should get a prompt accessing for Cloudformation to allow the creation of resources that need approval. Type &lt;code&gt;y&lt;/code&gt; and press &lt;code&gt;ENTER&lt;/code&gt; to continue with the deployment:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7c6qw50t0bidqoyhxp25.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7c6qw50t0bidqoyhxp25.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll start seeing the output from Cloudformation in your console as the stack is being created.&lt;/p&gt;

&lt;p&gt;When the stack has been successfully deployed, you should see:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffso15euru0fnvaksym5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffso15euru0fnvaksym5j.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice the output which we defined at the end of the stack. The CDK printed the public ip address of the newly created instance for us because we told it to, awesome! You can use this method to print out any value when a stack has successfully deployed.&lt;/p&gt;

&lt;p&gt;You can alternatively get this information from the ec2 console by checking on the instances dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Accessing the instance
&lt;/h2&gt;

&lt;p&gt;Let's ssh into our newly created instance with our key file and the public ip address.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; that the default &lt;em&gt;user&lt;/em&gt; for AMAZON LINUX images is &lt;code&gt;ec2-user&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

ssh &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.aws/pems/simple-instance-1-key.pem ec2-user@34.220.79.175


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You should now be able to log into your instance!&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbau99kvx3em1ks61oxe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbau99kvx3em1ks61oxe.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, we have an instance that isn't running anything on it. &lt;/p&gt;

&lt;p&gt;Let's fix that!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Adding User script
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Let's create a new file under &lt;code&gt;./lib/&lt;/code&gt; directory called &lt;code&gt;user_script.sh&lt;/code&gt;. 
Paste this code into that file. &lt;/li&gt;
&lt;li&gt;This code will deploy Apache, Wordpress, Mysql server on this intance. In this script, the database password will be &lt;code&gt;pl55w0rd&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It's very insecure to add passwords to scripts but in this case I'm doing this just for demonstration purposes. &lt;/li&gt;
&lt;li&gt;In production you should first of all never use such a weak password and secondly, not inside such a script.&lt;/li&gt;
&lt;li&gt;Rather, you should deploy the Mysql database on AWS RDS and setup credentials for that database using AWS Secrets Manager.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the setup file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;#! /bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# become root user&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;su

&lt;span class="c"&gt;# update dependencies&lt;/span&gt;
yum &lt;span class="nt"&gt;-y&lt;/span&gt; update

&lt;span class="c"&gt;# we'll install 'expect' to input keystrokes/y/n/passwords&lt;/span&gt;
yum &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;expect 

&lt;span class="c"&gt;# Install Apache&lt;/span&gt;
yum &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;httpd

&lt;span class="c"&gt;# Start Apache&lt;/span&gt;
service httpd start

&lt;span class="c"&gt;# Install PHP&lt;/span&gt;
yum &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;php php-mysql
&lt;span class="c"&gt;# php 7 needed for latest wordpress&lt;/span&gt;
amazon-linux-extras &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;php7.2 

&lt;span class="c"&gt;# Restart Apache&lt;/span&gt;
service httpd restart

&lt;span class="c"&gt;# Install MySQL&lt;/span&gt;
wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm
rpm &lt;span class="nt"&gt;-ivh&lt;/span&gt; mysql-community-release-el7-5.noarch.rpm

yum &lt;span class="nt"&gt;-y&lt;/span&gt; update 
yum &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;mysql-server

&lt;span class="c"&gt;# Start MySQL&lt;/span&gt;
service mysqld start

&lt;span class="c"&gt;# Create a database named blog&lt;/span&gt;
mysqladmin &lt;span class="nt"&gt;-uroot&lt;/span&gt; create blog

&lt;span class="c"&gt;# Secure database&lt;/span&gt;
&lt;span class="c"&gt;# non interactive mysql_secure_installation with a little help from expect.&lt;/span&gt;

&lt;span class="nv"&gt;SECURE_MYSQL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;expect &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"

set timeout 10
spawn mysql_secure_installation

expect &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Enter current password for root (enter for none):&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;
send &lt;/span&gt;&lt;span class="se"&gt;\"\r\"&lt;/span&gt;&lt;span class="s2"&gt;

expect &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Change the root password?&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;
send &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;y&lt;/span&gt;&lt;span class="se"&gt;\r\"&lt;/span&gt;&lt;span class="s2"&gt;
expect &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;New password:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;
send &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;pl55w0rd&lt;/span&gt;&lt;span class="se"&gt;\r\"&lt;/span&gt;&lt;span class="s2"&gt;
expect &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Re-enter new password:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;
send &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;pl55w0rd&lt;/span&gt;&lt;span class="se"&gt;\r\"&lt;/span&gt;&lt;span class="s2"&gt;
expect &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Remove anonymous users?&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;
send &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;y&lt;/span&gt;&lt;span class="se"&gt;\r\"&lt;/span&gt;&lt;span class="s2"&gt;

expect &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Disallow root login remotely?&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;
send &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;y&lt;/span&gt;&lt;span class="se"&gt;\r\"&lt;/span&gt;&lt;span class="s2"&gt;

expect &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Remove test database and access to it?&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;
send &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;y&lt;/span&gt;&lt;span class="se"&gt;\r\"&lt;/span&gt;&lt;span class="s2"&gt;

expect &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Reload privilege tables now?&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;
send &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;y&lt;/span&gt;&lt;span class="se"&gt;\r\"&lt;/span&gt;&lt;span class="s2"&gt;

expect eof
"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SECURE_MYSQL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Change directory to web root&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /var/www/html

&lt;span class="c"&gt;# Download Wordpress&lt;/span&gt;
wget http://wordpress.org/latest.tar.gz

&lt;span class="c"&gt;# Extract Wordpress&lt;/span&gt;
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzvf&lt;/span&gt; latest.tar.gz

&lt;span class="c"&gt;# Rename wordpress directory to blog&lt;/span&gt;
&lt;span class="nb"&gt;mv &lt;/span&gt;wordpress blog

&lt;span class="c"&gt;# Change directory to blog&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /var/www/html/blog/

&lt;span class="c"&gt;# Create a WordPress config file &lt;/span&gt;
&lt;span class="nb"&gt;mv &lt;/span&gt;wp-config-sample.php wp-config.php

&lt;span class="c"&gt;#set database details with perl find and replace&lt;/span&gt;
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"s/database_name_here/blog/g"&lt;/span&gt; /var/www/html/blog/wp-config.php
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"s/username_here/root/g"&lt;/span&gt; /var/www/html/blog/wp-config.php
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"s/password_here/pl55w0rd/g"&lt;/span&gt; /var/www/html/blog/wp-config.php

&lt;span class="c"&gt;# create uploads folder and set permissions&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;wp-content/uploads
&lt;span class="nb"&gt;chmod &lt;/span&gt;777 wp-content/uploads

&lt;span class="c"&gt;#remove wp file&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/www/html/latest.tar.gz


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We will need to add &lt;code&gt;fs&lt;/code&gt; module at the top of our &lt;code&gt;./lib/simple-ec2-stack.ts&lt;/code&gt; file since &lt;code&gt;instance.addUserData()&lt;/code&gt; needs to access the file system during deployment.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-ec2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// import ec2 library &lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-iam&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// import iam library for permissions&lt;/span&gt;

&lt;span class="c1"&gt;// lets include fs module&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then we can the function &lt;code&gt;instance.addUserData()&lt;/code&gt; right before our output function:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="p"&gt;...&lt;/span&gt;

    &lt;span class="c1"&gt;// add user script to instance&lt;/span&gt;
    &lt;span class="c1"&gt;// this script runs when the instance is started &lt;/span&gt;
    &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addUserData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lib/user_script.sh&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// cdk lets us output prperties of the resources we create after they are created&lt;/span&gt;
    &lt;span class="c1"&gt;// we want the ip address of this new instance so we can ssh into it later&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CfnOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simple-instance-1-output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instancePublicIp&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Update the deployed stack
&lt;/h2&gt;

&lt;p&gt;Let's re-synthesize to check everything is okay:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

cdk &lt;span class="nt"&gt;--synth&lt;/span&gt; &lt;span class="nt"&gt;--profile&lt;/span&gt; default


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;You should now see the user script commands in the &lt;code&gt;synth&lt;/code&gt; output&lt;/li&gt;
&lt;li&gt;Let's deploy our new changes. &lt;/li&gt;
&lt;li&gt;Cloudformation will only update resources that are being updated. &lt;/li&gt;
&lt;li&gt;In this case, only ec2 instance is being updated. &lt;/li&gt;
&lt;li&gt;Other things like roles and security groups will remain as they are since there are no changes to them in the updated stack.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

cdk &lt;span class="nt"&gt;--deploy&lt;/span&gt; &lt;span class="nt"&gt;--profile&lt;/span&gt; default


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fion34zyeoyj2zuv2xwv8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fion34zyeoyj2zuv2xwv8.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Take note:&lt;/em&gt; Since we are not using an elastic IP, its highly likely that the public ip address of the instance has changed.&lt;/p&gt;

&lt;p&gt;Let's use the outputted IP address and check to see that Wordpress, Mysql and PHP were installed correctly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In your browser, navigate to http:///blog&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You should then see:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fif3mfuajrtxfqb06x185.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fif3mfuajrtxfqb06x185.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;and then you can complete the installation of Wordpress! &lt;/li&gt;
&lt;li&gt;Remember your database credentials &lt;code&gt;root&lt;/code&gt; and &lt;code&gt;pl55w0rd&lt;/code&gt; as defined in the script&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Testing the stack
&lt;/h2&gt;

&lt;p&gt;Well we know our CDK code works and can provision an ec2 instance to run our Wordpress server and database. Good. &lt;/p&gt;

&lt;p&gt;But how can we make sure that changes to the CDK code do not do what we don't want it to do? &lt;/p&gt;

&lt;p&gt;This is where tests come in.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Test requirements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;I do not want any instance other &lt;code&gt;t2.micro&lt;/code&gt; to be used as my server instance type because I always want to remain under AWS free tier usage for EC2. Let's ensure that.&lt;/li&gt;
&lt;li&gt;I want to ensure that my instance uses the SSH key with the name &lt;code&gt;simple-instance-1-key&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To accomplish this, we change the code inside the file &lt;code&gt;./test/simple-ec2.test.ts&lt;/code&gt; to:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;expectCDK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;haveResourceLike&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/assert&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;SimpleEc2&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../lib/simple-ec2-stack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Check InstanceType and SSH KeyName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;SimpleEc2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SimpleEc2Stack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyTestStack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;expectCDK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;haveResourceLike&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AWS::EC2::Instance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;InstanceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;t2.micro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;KeyName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simple-instance-1-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As you can see from the test code, the test will check the generated Cloudformation template generated by the CDK. &lt;/p&gt;

&lt;p&gt;In our case we want to check that the instance is a &lt;code&gt;t2.micro&lt;/code&gt; and that it uses the SSH key &lt;code&gt;simple-instance-1-key&lt;/code&gt;. These are two crucial properties to us. &lt;/p&gt;

&lt;p&gt;You can read more about testing infrastructure with the CDK here &lt;a href="https://aws.amazon.com/blogs/developer/testing-infrastructure-with-the-aws-cloud-development-kit-cdk/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run the test:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

npm test


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbyipv0hu8l8f3owkdxkh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbyipv0hu8l8f3owkdxkh.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All good!&lt;/p&gt;

&lt;p&gt;And now your code should be able to run a test before deploying your infrastructure! Fantastic!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

npm test &amp;amp;&amp;amp; cdk deploy --profile default


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Destroying the stack
&lt;/h2&gt;

&lt;p&gt;If you would like to destroy the infrastructure you just provisioned, it's as simple as:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

cdk destroy --profile default


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And Cloudformation will remove your entire stack!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Notes:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It's not advisable to run mysql on the same instance as your Wordpress server. You can instead use AWS managed Database service &lt;a href="https://aws.amazon.com/rds/" rel="noopener noreferrer"&gt;RDS&lt;/a&gt; to deploy the database that Wordpress will use. &lt;/li&gt;
&lt;li&gt;Don't put sensitive information like passwords in user scripts since in many cases they are committed to source control or their output is visible in a CI/CD console or instance terminal history&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Conclusion
&lt;/h2&gt;

&lt;p&gt;The AWS CDK makes writing IaC, provisioning, deploying, updating and destroying infrastructure very painless. You can write tests to make sure you do not deploy the wrong things.&lt;/p&gt;

&lt;p&gt;This was a simple example and may seem quite a lot just to deploy an ec2 instance. However, as we progress through the series, you will realize how its very beneficial to complex infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Up next
&lt;/h2&gt;

&lt;p&gt;In part 4, using the CDK, we will make our Wordpress server more more production ready. We will: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create AWS RDS Mysql database instead of running the database on the ec2 instance &lt;/li&gt;
&lt;li&gt;provision this database in an isolated subnet to keep it secure from the public Internet&lt;/li&gt;
&lt;li&gt;use AWS SSM to access our instance instead of an SSH key and gain all the benefits of IAM permissions/roles&lt;/li&gt;
&lt;li&gt;deploy an Application Load Balancer&lt;/li&gt;
&lt;li&gt;Create our EC2 instance with better/more advanced script&lt;/li&gt;
&lt;li&gt;Place the Wordpress instance in an AutoScaling Group&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Hi I'm &lt;a href="https://emmanuelnk.com" rel="noopener noreferrer"&gt;Emmanuel&lt;/a&gt;! I write about Software and DevOps.&lt;/p&gt;

&lt;p&gt;If you liked this article and want to see more, add me on &lt;a href="https://www.linkedin.com/in/emmanuel-nsubuga-kyeyune/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or follow me on &lt;a href="https://twitter.com/emmanuel_n_k" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>awscdk</category>
      <category>ec2</category>
      <category>devops</category>
    </item>
    <item>
      <title>Awesome AWS CDK - Part 2 - Setting up AWS CDK</title>
      <dc:creator>Emmanuel K</dc:creator>
      <pubDate>Sun, 14 Mar 2021 09:39:04 +0000</pubDate>
      <link>https://dev.to/emmanuelnk/awesome-aws-cdk-part-2-setting-up-aws-cdk-3ggj</link>
      <guid>https://dev.to/emmanuelnk/awesome-aws-cdk-part-2-setting-up-aws-cdk-3ggj</guid>
      <description>&lt;h2&gt;
  
  
  What you will learn in this part
&lt;/h2&gt;

&lt;p&gt;In this tutorial, you will learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to install AWS CDK&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's go!&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-requisites
&lt;/h2&gt;

&lt;p&gt;You are going to need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html"&gt;An AWS account with programmatic access&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en/"&gt;Node.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Make sure you have Node.js setup&lt;/li&gt;
&lt;li&gt;Make sure your aws credentials are properly configured.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's an example of my AWS configured access files where I have my own personal aws account as the &lt;code&gt;default&lt;/code&gt; profile and two other aws accounts for my work company -- acme-corp👨🏿‍💻.&lt;/p&gt;

&lt;p&gt;AWS &lt;code&gt;credentials&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Linux and MacOS: ~/.aws/credentials
# Windows: %USERPROFILE%\.aws\credentials

[default]
aws_access_key_id=xXXxxxxXXXXxxxxxxx
aws_secret_access_key=xxXXXXxxxXXxXxx

[acme-corp-prod-acc]
aws_access_key_id=xXXxxxxXXXXxxxxxxx
aws_secret_access_key=xxXXXXxxxXXxXxx

[acme-corp-dev-acc]
aws_access_key_id=xXXxxxxXXXXxxxxxxx
aws_secret_access_key=xxXXXXxxxXXxXxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AWS &lt;code&gt;config&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Linux and MacOS: ~/.aws/config
# Windows: %USERPROFILE%\.aws\config

[default]
region=us-west-2
output=json

[profile acme-corp-prod-acc]
region=us-west-2
output=json

[profile acme-corp-dev-acc]
region=us-west-2
output=json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The AWS CDK will look for these files when it needs access to whatever AWS accounts it needs to deploy resources to.&lt;/li&gt;
&lt;li&gt;It helps that the IAM credentials used have administrator privileges when deploying resources as this will reduce a lot of headache regarding permissions. &lt;/li&gt;
&lt;li&gt;You can filter out permissions and privileges if you have a good understanding of AWS IAM and the permission needs of your deployments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Install the AWS CDK globally (so that you can bootstrap a new CDK project in your language choice) in any folder
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g aws-cdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check that its installed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk --version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it!&lt;/p&gt;

&lt;p&gt;In the next part, we will set up a project with the cdk and deploy it!&lt;/p&gt;




&lt;p&gt;Hi I'm &lt;a href="https://emmanuelnk.com"&gt;Emmanuel&lt;/a&gt;! I write about Software and DevOps.&lt;/p&gt;

&lt;p&gt;If you liked this article and want to see more, add me on &lt;a href="https://www.linkedin.com/in/emmanuel-nsubuga-kyeyune/"&gt;LinkedIn&lt;/a&gt; or follow me on &lt;a href="https://twitter.com/emmanuel_n_k"&gt;Twitter&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Awesome AWS CDK - Part 1 - A series on common and practical deployments with the AWS CDK</title>
      <dc:creator>Emmanuel K</dc:creator>
      <pubDate>Sun, 14 Mar 2021 09:24:34 +0000</pubDate>
      <link>https://dev.to/emmanuelnk/awesome-aws-cdk-a-series-on-common-and-practical-deployments-with-the-aws-cdk-4opk</link>
      <guid>https://dev.to/emmanuelnk/awesome-aws-cdk-a-series-on-common-and-practical-deployments-with-the-aws-cdk-4opk</guid>
      <description>&lt;h1&gt;
  
  
  PART 1
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This is going to be the first in a series of articles about using the AWS CDK (Cloud Development Kit) for common and practical deployment of cloud resources on AWS. This is to help those who are already familiar with AWS to deploy cloud resources using this awesome IaC (Infrastructure as Code) library from AWS.&lt;/p&gt;

&lt;p&gt;As you may have figured, the AWS CDK is targeted at the deployment of AWS cloud infrastructure only. So if you are afraid of AWS vendor lock-in for your cloud deployments, then maybe this will not be the series for you. There are other tools that can do multi-vendor cloud deployments and provisioning (like &lt;a href="https://www.terraform.io/"&gt;Terraform&lt;/a&gt;, &lt;a href="https://www.pulumi.com/"&gt;Pulumi&lt;/a&gt;, &lt;a href="https://www.serverless.com/"&gt;Serverless&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;However, if you feel like you use AWS a lot like many DevOps/Solutions Architects/Developers do then this is the series to show you practical examples of using the AWS CDK to deploy resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;h3&gt;
  
  
  In the beginning...
&lt;/h3&gt;

&lt;p&gt;You can manually create resources on AWS using the console, command line interface or other IaC tools. And this is what people did when AWS was new. But it became evident pretty fast that this mode of provisioning cloud infrastructure was error prone and not sustainable, especially for massive and complex stacks of resources. These frustrations led to the birth of &lt;a href="https://aws.amazon.com/cloudformation/"&gt;Cloudformation&lt;/a&gt; in 2011.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloudformation
&lt;/h3&gt;

&lt;p&gt;AWS Cloudformation is AWS' managed service for provisioning cloud infrastructure and services. You do this using a JSON or YAML template file that defines what resources you would like AWS to Create, Update or Destroy. Cloudformation consumes file and makes the necessary changes to your deployed stack of resources.&lt;/p&gt;

&lt;p&gt;Cloudformation is the backbone service of automatically deployed resources on AWS. It ensures consistency of your deployed resources and can keep track of drifts (when resources are created, updated or destroyed outside of the Cloudformation template file).&lt;/p&gt;

&lt;p&gt;The problem is Cloudformation template files are ridiculously hard to write, read, update and manage. After all they are basic YAML/JSON. Its fine if you are provisioning a few resources. But it is completely unmanageable with human effort once you exceed 20 resources. &lt;/p&gt;

&lt;p&gt;This is where the CDK comes in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloud Development Kit
&lt;/h3&gt;

&lt;p&gt;The AWS CDK is a library of functions that will generate a Cloudformation template and use it to provision resources in AWS. It allows you to write code to define in your favorite language to create these Cloudformation templates.&lt;/p&gt;

&lt;p&gt;With the CDK, the ability to have access to intellisense from your code editor, ability to break up resources into logical parts, type checking, enums etc means that the tendency to make errors when configuring resources dramatically reduces. You can also write tests for the infrastructure you want to deploy to ensure that whatever changes made in the IaC are not going to break your deployed stack of resources or cost you millions when you mistakenly provision beyond your means. &lt;/p&gt;

&lt;p&gt;Its been a joy working with CDK for the past year for me and it is hard to go back to other solutions like Terraform, Serverless, SAM for AWS resource provisioning.  &lt;/p&gt;

&lt;h3&gt;
  
  
  It's not all roses yet though
&lt;/h3&gt;

&lt;p&gt;No project is perfect. The AWS CDK, as great as it is, is also a recent project (launched in July 2019) so it doesn't yet cover everything possible to deploy on AWS (Even Cloudformation doesn't cover everything possible in AWS yet). Some things will need manual configuration via the console or command line interface. There are also minor bugs, fast changing interfaces, deprecations etc as the CDK development tries to catch up to and keep up with the pace at which AWS releases new services and updates. Maybe within a year many of my own code examples from this series will have some deprecations. But the core API and concepts will remain the same. Also, for most common services, the CDK will have you covered. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I will focus on simple and common deployments. &lt;/li&gt;
&lt;li&gt;I will use github actions as my CI/CD tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are other projects out there that focus on patterns like the awesome &lt;a href="https://cdkpatterns.com/"&gt;cdk patterns project&lt;/a&gt; which concentrates on serverless deployments with the cdk and AWS' own &lt;a href="https://github.com/aws-samples/aws-cdk-examples"&gt;aws-cdk-examples project&lt;/a&gt; which has tons of great examples on using the cdk. I drew tons of inspiration and learning from these projects.&lt;/p&gt;

&lt;p&gt;My series will focus on simple common deployments with a heavy leaning on practicality. This means I will take you through some best practices as well as well as my own experience.&lt;/p&gt;

&lt;p&gt;I will use Typescript because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The CDK API is essentially the same in Typescript, Python, .Net, Java. The language itself isn't too important. &lt;/li&gt;
&lt;li&gt;The CDK is also written in Typescript and then wrapped for use in other languages.&lt;/li&gt;
&lt;li&gt;It's awesome!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hope you can stick with me throughout. See you in part 2!&lt;/p&gt;




&lt;p&gt;Hi I'm &lt;a href="https://emmanuelnk.com"&gt;Emmanuel&lt;/a&gt;! I write about Software and DevOps.&lt;/p&gt;

&lt;p&gt;If you liked this article and want to see more, add me on &lt;a href="https://www.linkedin.com/in/emmanuel-nsubuga-kyeyune/"&gt;LinkedIn&lt;/a&gt; or follow me on &lt;a href="https://twitter.com/emmanuel_n_k"&gt;Twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>awscdk</category>
      <category>devops</category>
      <category>iac</category>
    </item>
    <item>
      <title>Is the AWS Solutions Architect Certification worth it? A review</title>
      <dc:creator>Emmanuel K</dc:creator>
      <pubDate>Wed, 17 Feb 2021 07:53:39 +0000</pubDate>
      <link>https://dev.to/emmanuelnk/is-the-aws-solutions-architect-certification-worth-it-a-review-2lem</link>
      <guid>https://dev.to/emmanuelnk/is-the-aws-solutions-architect-certification-worth-it-a-review-2lem</guid>
      <description>&lt;p&gt;&lt;strong&gt;TLDR:&lt;/strong&gt; Yes it is! But not for the reasons you may think.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;AWS has &lt;strong&gt;very many&lt;/strong&gt; services. And every year when &lt;a href="https://aws.amazon.com/new/reinvent"&gt;re:Invent&lt;/a&gt; rolls around, &lt;a href="https://www.infoq.com/news/2020/12/aws-reinvent-2020/"&gt;they add even more&lt;/a&gt;. Most people don't even dare venture into any other services beyond EC2, S3, Lambda and RDS. These are the primary services you'd use to setup a simple web server, for example. If you're a little more involved you may use Route53 to manage domains, VPC to manage your resource networks and subnets and Cloudfront as a CDN. Most people would find little use for SQS, Kinesis, DynamoDB, Step Functions etc&lt;/p&gt;

&lt;p&gt;Additionally, many DevOps engineers like to keep the deployed cloud infrastructure as high level as possible to prevent over-reliance on managed AWS services and avoid vendor lock-in (the concern of which is usually &lt;a href="https://thenewstack.io/should-you-really-be-so-worried-about-cloud-lock-in/"&gt;overblown&lt;/a&gt;). However even if you are unnecessarily afraid of vendor lock-in, content with managing cloud infrastructure yourself or you really have legitimate reasons to avoid using AWS managed services, getting (or at least studying for) an AWS Solutions Architect certificate is still worth it.&lt;/p&gt;

&lt;p&gt;This is because the AWS Solutions Architect exam (both Associate and Professional), doesn't just challenge you on your knowledge of AWS services, it challenges how you think about cloud infrastructure &lt;strong&gt;altogether&lt;/strong&gt; in order to... yes you guessed it -- architect solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Solutions Architect with bad solutions?
&lt;/h2&gt;

&lt;p&gt;Nothing is worse than a mechanic with a box full of tools who doesn't really know how to fix things. The AWS Solutions Architect Associate exam (the one I did) is truly a test of understanding the world of managed cloud services and how one can deliver practical and reliable solutions. You WILL need to know and understand not only many AWS services but also how they work together to produce the best possible results according to various scenarios. &lt;/p&gt;

&lt;p&gt;Because of this, this is not an exam you can study for on a weekend and pass on Monday. Even though some people may be able to memorize common solutions, the questions can and will be quite challenging and even seasoned AWS pros need to study for it. &lt;/p&gt;

&lt;p&gt;I had used AWS for about 3 years before doing the AWS Solutions Architect Associate exam in July 2020. I had deployed instances, serverless functions, message brokers and queues, databases etc But I only started to realize the many gaps in my knowledge once I started reading for the exam. I realized certain things I would do were either not best practice, impractical, not secure or just plain ridiculous. And a lot of it had nothing to do specifically with AWS services, but more to do with doing DevOps and cloud infrastrcture design in a correct way. I ended up reading many of the famous AWS &lt;a href="https://aws.amazon.com/whitepapers/?whitepapers-main.sort-by=item.additionalFields.sortDate&amp;amp;whitepapers-main.sort-order=desc"&gt;whitepapers&lt;/a&gt; like &lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/framework/wellarchitected-framework.pdf#welcome"&gt;Well Architected Framework&lt;/a&gt; and &lt;a href="https://d1.awsstatic.com/whitepapers/Security/AWS_Security_Checklist.pdf?did=wp_card&amp;amp;trk=wp_card"&gt;AWS Security Checklist&lt;/a&gt; and gained a wealth of knowledge I wouldn't have obtained otherwise because I &lt;em&gt;thought I knew&lt;/em&gt; what I was doing and I would never have taken the time to dive deeper into AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  A new understanding
&lt;/h2&gt;

&lt;p&gt;Within one week of starting my revision, I knew several things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I wasn't ready to do the exam anytime soon&lt;/li&gt;
&lt;li&gt;I had deployed poor or insecure architecture&lt;/li&gt;
&lt;li&gt;I was eager to apply my new found knowledge and understanding almost immediately&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Around this time I started to see the real value in what I was training myself for. See, my original intention was to get the certification just to look good on my resume and I really thought I'd only need about two weeks to prepare for the test (after all, I had used AWS for quite a while). I ended up using about 5 weeks in total for preparation (usually more than 7 hours a day). I also took two video courses to supplement my knowledge (one from &lt;a href="https://acloud.guru"&gt;ACloud Guru&lt;/a&gt; and one from &lt;a href="https://www.udemy.com/course/aws-solutions-architect-professional/#instructor-1"&gt;Stephane Maarek&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;This is not to frighten/discourage you. Most people who attempt the test with good preparation WILL pass. But the point of this post is to shed light on the value studying for this kind of exam will bring in your DevOps/Cloud journey beyond the certification itself. A lot of the knowledge I gained from SAA-C02 can easily be applied to other cloud providers such as Azure and GCP. Their services may have different names and may be slightly different in their capabilities and functionality but the core principles of deploying robust, highly scalable, highly available, fault tolerant, disaster tolerant and manageable cloud infrastructure still apply.&lt;/p&gt;

&lt;p&gt;It's been about 8 months since I did my test and while it has helped my profile gain more notice in the DevOps hiring space, the greater gift is the expanded knowledge that I'm utilizing in my daily DevOps life of writing good Infrastructure as Code and managing existing cloud infrastructure. It makes me much more confident in whatever I'm doing inside AWS. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Bite the bullet
&lt;/h2&gt;

&lt;p&gt;So if you are a:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DevOps Engineer&lt;/li&gt;
&lt;li&gt;Software Engineer&lt;/li&gt;
&lt;li&gt;Full-stack Developer&lt;/li&gt;
&lt;li&gt;Web Developer&lt;/li&gt;
&lt;li&gt;CTO&lt;/li&gt;
&lt;li&gt;Principal Tech Lead&lt;/li&gt;
&lt;li&gt;Curious noob who wants to be any of the above &lt;/li&gt;
&lt;li&gt;or even an AWS employee who has to interact with AWS services a lot &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;then the certification is definitely worth &lt;strong&gt;studying for&lt;/strong&gt; and obtaining.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But don't do it for the wrong reasons&lt;/strong&gt; i.e. its a hot commodity that everyone talks about constantly, &lt;em&gt;so you must have it&lt;/em&gt;. The certification itself is a nice to have and does look good on your profile/resume/CV and will open more doors for you, but the deeper understanding of how AWS and similar cloud providers works is much more valuable. You will forego years of trial and error experience by learning so many essentials in one fell swoop.&lt;/p&gt;

&lt;p&gt;If you would like more information about how to start this journey towards certification or any other general questions, send me a message here, on &lt;a href="https://twitter.com/emmanuel_n_k"&gt;Twitter&lt;/a&gt; or on &lt;a href="https://www.linkedin.com/in/emmanuel-nsubuga-kyeyune/"&gt;LinkedIn&lt;/a&gt; .&lt;/p&gt;




&lt;p&gt;Hi I'm &lt;a href="https://emmanuelnk.com"&gt;Emmanuel&lt;/a&gt;! I write about Software and DevOps.&lt;/p&gt;

&lt;p&gt;I will be writing a series on AWS CDK, Terraform and other great deployment tools and what many lessons I've learned from them.&lt;/p&gt;

&lt;p&gt;If you liked this article and want to see more, add me on &lt;a href="https://www.linkedin.com/in/emmanuel-nsubuga-kyeyune/"&gt;LinkedIn&lt;/a&gt; or follow me on &lt;a href="https://twitter.com/emmanuel_n_k"&gt;Twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>certification</category>
      <category>devops</category>
      <category>cloudskills</category>
    </item>
    <item>
      <title>Using sudo without password prompt as non-root docker user</title>
      <dc:creator>Emmanuel K</dc:creator>
      <pubDate>Tue, 17 Nov 2020 06:50:43 +0000</pubDate>
      <link>https://dev.to/emmanuelnk/using-sudo-without-password-prompt-as-non-root-docker-user-52bg</link>
      <guid>https://dev.to/emmanuelnk/using-sudo-without-password-prompt-as-non-root-docker-user-52bg</guid>
      <description>&lt;p&gt;Follow me on twitter: &lt;a href="https://twitter.com/emmanuel_n_k"&gt;emmanuelnk&lt;/a&gt;  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;WARNING: This is generally considered NOT SECURE and thus do not use the methods in this article in a production container.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have a particular use case that justifies this usage. Now you can read on.&lt;/p&gt;

&lt;p&gt;Recently I wrote a pure bash menu program that has install scripts for various Ubuntu software I use. This is to allow me to reproduce my dev environment as fast as possible on a new Ubuntu installation.&lt;/p&gt;

&lt;p&gt;I want to release this program as an open source tool and for that reason it needs testing and CI. Docker is perfect for this. Except for one thing. Most docker images use user &lt;code&gt;root&lt;/code&gt; to execute commands. This is fine for most intent and purposes. But to appropriately test my program, I would need to be a non-root user inside the docker container.&lt;/p&gt;

&lt;h1&gt;
  
  
  Changing the root user
&lt;/h1&gt;

&lt;p&gt;This is trivial and actually quite common in Dockerfiles. By default, most docker images, including &lt;code&gt;ubuntu:latest&lt;/code&gt; have &lt;code&gt;USER&lt;/code&gt; set to &lt;code&gt;root&lt;/code&gt;. This can be changed by creating a new user in a &lt;code&gt;Dockerfile&lt;/code&gt; by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;useradd &lt;span class="nt"&gt;-ms&lt;/span&gt; /bin/bash newuser
&lt;span class="c"&gt;# where&lt;/span&gt;
&lt;span class="c"&gt;# -m -&amp;gt; Create the user's home directory&lt;/span&gt;
&lt;span class="c"&gt;# -s /bin/bash -&amp;gt; Set as the user's &lt;/span&gt;
&lt;span class="c"&gt;# default shell&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; newuser&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a &lt;code&gt;newuser&lt;/code&gt; without root privileges to run commands in the container. &lt;br&gt;
NB: You can add &lt;code&gt;&amp;amp;&amp;amp; echo 'pa55w0rd' | chpasswd&lt;/code&gt; right after the &lt;code&gt;useradd&lt;/code&gt; to set a password.&lt;/p&gt;

&lt;p&gt;For my use case, I need the password disabled and I need to NOT be prompted for a password when using &lt;code&gt;sudo&lt;/code&gt; command. Now you may be asking, why would someone want to do this?&lt;/p&gt;

&lt;p&gt;Well if you're using docker in CI and need to test certain commands being run as a regular user then this is the way. For example, on my machine, I am the &lt;code&gt;USER=emmanuel&lt;/code&gt;. I don't have root privileges and when I need to install something, I do &lt;code&gt;sudo apt-get install&lt;/code&gt; and enter my password to give me su access.&lt;/p&gt;

&lt;p&gt;For my project, I'm trying to test install scripts as a regular user and thus these scripts use &lt;code&gt;sudo&lt;/code&gt; and variables such as &lt;code&gt;$HOME&lt;/code&gt; a lot (&lt;code&gt;$HOME&lt;/code&gt; for &lt;code&gt;root&lt;/code&gt; is &lt;code&gt;/root&lt;/code&gt;). Hence using the default that most docker images have, programs would not install in the correct locations or not install correctly at all. This is not good.&lt;/p&gt;

&lt;p&gt;Anyway, enought talking. This is what my &lt;code&gt;Dockerfile&lt;/code&gt; looks like to accomplish this. Explanations in the comments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Get latest official Ubuntu image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu&lt;/span&gt;

&lt;span class="c"&gt;# ubuntu:latest does not have sudo&lt;/span&gt;
&lt;span class="c"&gt;# fetch it and install it&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;sudo&lt;/span&gt;

&lt;span class="c"&gt;# Create new user `docker` and disable &lt;/span&gt;
&lt;span class="c"&gt;# password and gecos for later&lt;/span&gt;
&lt;span class="c"&gt;# --gecos explained well here:&lt;/span&gt;
&lt;span class="c"&gt;# https://askubuntu.com/a/1195288/635348&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;adduser &lt;span class="nt"&gt;--disabled-password&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="nt"&gt;--gecos&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; docker

&lt;span class="c"&gt;#  Add new user docker to sudo group&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;adduser docker &lt;span class="nb"&gt;sudo&lt;/span&gt;

&lt;span class="c"&gt;# Ensure sudo group users are not &lt;/span&gt;
&lt;span class="c"&gt;# asked for a password when using &lt;/span&gt;
&lt;span class="c"&gt;# sudo command by ammending sudoers file&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'%sudo ALL=(ALL) NOPASSWD:ALL'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;/etc/sudoers

&lt;span class="c"&gt;# now we can set USER to the &lt;/span&gt;
&lt;span class="c"&gt;# user we just created&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; docker&lt;/span&gt;

&lt;span class="c"&gt;# we can now run sudo commands &lt;/span&gt;
&lt;span class="c"&gt;# as non-root user `docker` without&lt;/span&gt;
&lt;span class="c"&gt;# password prompt&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update 

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /home/docker/src&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Thanks!&lt;/p&gt;

&lt;p&gt;If you have suggestions, improvements or want to correct me, let me know in the comments! &lt;/p&gt;

&lt;p&gt;If this helped you out, follow me on twitter: &lt;a href="https://twitter.com/emmanuel_n_k"&gt;emmanuelnk&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>ubuntu</category>
      <category>sudo</category>
      <category>dockerfile</category>
    </item>
    <item>
      <title>Local Python Module imports when using virtualenv</title>
      <dc:creator>Emmanuel K</dc:creator>
      <pubDate>Sun, 15 Nov 2020 07:49:44 +0000</pubDate>
      <link>https://dev.to/emmanuelnk/local-python-module-imports-when-using-virtualenv-1ke</link>
      <guid>https://dev.to/emmanuelnk/local-python-module-imports-when-using-virtualenv-1ke</guid>
      <description>&lt;p&gt;Importing modules in python3 can be unnecessarily confusing, especially when using virtualenv&lt;/p&gt;

&lt;p&gt;Suppose you have this file structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.env
test.py
cool_modules
    |--__init__.py
    |--cool_module1.py
    |--cool_module2.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To prevent import errors while using virtualenv &lt;code&gt;.env&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;cool_module1.py:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CoolModule1&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;cool_module2.py:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CoolModule2&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the critical part. &lt;br&gt;
&lt;strong&gt;init&lt;/strong&gt;.py:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# The part to note here is you have to use `parent_folder.child_file`
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cool_modules.cool_module1&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CoolModule1&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cool_modules.cool_module2&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CoolModule2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;test.py:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cool_modules&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CoolModule1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CoolModule2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it!&lt;/p&gt;

&lt;p&gt;If this helped you out, follow me on Twitter: &lt;a href="https://twitter.com/emmanuel_n_k"&gt;emmanuel_n_k&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
