1. Signup Cloudflare
  2. Add website to Cloudflare
  3. Change name servers to Cloudflare’s
  4. Enable “Always On HTTPS”
  5. Tweak SSL settings if necessary – default is Full, can be Flexible or Strict


  1. Signup AWS account
  2. Decide which AWS Region as primary region, considering cost, latency, and feature parity
  3. Draw a Deployment Diagram using Diagram should contain: Buyer, Vendor, Customer Support, Internet, Cloudflare CDN, ECS for production, ECS for staging, EBS for production, EBS for staging, MariaDB, Redis, SES.
  4. Login to AWS Management Console.
  5. Switch to your chosen Region.
  6. (If not yet exists) Create a security group: “web-server“, allow Inbound on HTTP and HTTPS from anywhere. Optionally, allow SSH port.


  1. We start with SES as this step requires validation (SPF and DKIM) and also request to get out of sandbox.
  2. Check if SES is available in your primary region. If not, go to US East (N. Virginia).
  3. Verify your domain:
    • Save Record Set as CSV and save it in safe place.
    • In Cloudflare, add given TXT records.
    • In Cloudflare, add given CNAME/DKIM records (make sure to set as not proxied).
    • Only if you want to receive mail using SES: add given MX records.
    • Add TXT record (example is if you use Yandex Mail too):
      v=spf1 ~all
  4. Request Sending Limit Increase:
    • Select your region (likely US East Northern Virginia)
    • Desired Daily Sending Quota: 20000
    • Desired Maximum Send Rate: 20
    • Describe how you will comply: “My email-sending complies with the AWS Service Terms and AUP”
    • Then: “I only send to recipients who have specifically requested my mail”
    • Then: “I have a process to handle bounces and complaints”
    • Dear AWS team, In my app/website, I am collecting emails through opt-in subscriptions. My emails are clean and verified. I will be using online emailing application: WordPress/Mautic. This application can handle bounce, complaint and unsubscription effectively. I have also verified the domain I am using. Kindly approve my request for Amazon SES production access in above mentioned region. Let me know if you have any question. Thanks and Regards!
  5. Go to IAM. Create user “mailer” with Programmatic Access only, using policies AmazonSESFullAccess and AmazonSNSFullAccess (for more security, limit the permissions with manual policy).
    • Save the AWS access key ID and secret access key in a safe place.


  1. Go to your primary region.
  2. Go to RDS.
  3. Create a MariaDB cluster at latest version.
    1. Dev/Test is sufficient for starter
    2. Instance size: db.t3.micro is sufficient for starter
    3. Additional connectivity: If you need public access (but less security), set as Publicly accessible
    4. Security group: Create “mariadb” security group.
    5. Availability zone: Choose the “a” AZ, and later ensure that other services use the same AZ for highest performance and lower bandwidth costs.
    6. Enhanced monitoring: You may want to disable this to save costs
    7. Log exports: Audit log, Error log, General log, Slow query log
    8. Deletion protection: Enable
  4. Save the master username, master password, and endpoint, in a safe place.
  5. Create users in MariaDB, e.g. brand_wp_prd and brand_wp_stg.
  6. Create databases in MariaDB, e.g. brand_wp_prd and brand_wp_stg. Make sure to use charset=utf8mb4.
  7. Grant privileges to databases.
  8. Flush privileges.
  9. Save the users and databases credentials in a safe place.
  10. Go to EC2 > Security Groups > mariadb. Allow Inbound MySQL from “webserver”.
  11. Later, you’ll need to create ECS instances that includes the “mariadb” security group.

ElastiCache Redis

  1. Go to your primary region.
  2. Create Security group “redis”.
    • Allow Inbound Redis (port 6379) from “webserver”.
  3. Go to ElastiCache.
  4. Create a new ElastiCache Redis cluster:
    1. Cluster mode is usually disabled (i.e. replicas only, no shards), if enabled you can configure shards.
    2. Node type: cache.t3.micro is sufficient for a start.
    3. Replicas: if you only need primary, you can set 0 replicas.
    4. Preferred availability zone(s): select the “a” zone.
    5. Backup: If you use Redis only for caching, automatic backups can be disabled.
    6. Security group: “redis”.
  5. Later, you’ll need to create ECS instances that includes “webserver” security group which is allowed to access Redis.


  1. Create bucket “” in your primary region.
    • Disable “Block all public access” to the bucket.
  2. Create “” in your primary region.
    • Disable “Block all public access” to the bucket.
  3. Create IAM Policy “” with access to bucket “” and “”.
  4. Assign the IAM Policy to Role “brand_ecsInstanceRole”.
  5. In Cloudflare, add CNAME (proxied) “” to your S3 standard endpoint, e.g. “”.
  6. In Cloudflare, add CNAME (proxied) “” to your S3 standard endpoint, e.g. “”.


  1. Go to your primary region.
  2. Go to EC2. Create a keypair.
  3. Save the keypair in a safe place.
  4. Create Elastic IP and name it “”.
  5. In Cloudflare, add A record (proxied) to that Elastic IP.
  6. Go to IAM. Create RexrayPolicy.
  7. Add RexrayPolicy to “brand_ecsInstanceRole”.
  8. Go to ECS. Create cluster “brand-wp-prd”.
    1. Instance type: t3a.nano is sufficient for WordPress, t3a.micro is sufficient for WooCommerce.
    2. Key pair: Choose the keypair you already prepared.
    3. VPC: Choose existing.
    4. Subnet: Choose “a”.
    5. Security group: “webserver”.
  9. Assign Elastic IP to ECS instance.
  10. SSH to instance.
  11. Install rexray/ebs docker plugin.
  12. Restart docker service.
  13. Create cluster capacity provider, managed scaling & termination: disabled.
  14. Update cluster to use the new capacity provider.
  15. Optionally, go back to step 5 to prepare stg cluster.
  16. Create Task Definition “brand-wp-prd”.
    1. Volume: brand-wp-prd.
      Driver: rexray/ebs.
      Scope: Shared.
      Auto-provision: true.
      Driver options: volumetype=gp2, size=5.
    2. Container: wordpress,
      Port mapping: 80:80
    3. Mount brand-wp-prd to /var/www/html
    4. Auto-configure CloudWatch Logs
  17. Run task.

WordPress Setup Phase 1

  1. In .htaccess, increase memory_limit, post_max_size, and upload_max_size via .htaccess. php.ini’s upload_max_filesize is too small for typical web sites, and also for uploading plugins. Set both to 64M. How to:
    1. SSH to the ECS instance
    2. docker ps (to get wordpress container name)
    3. docker exec -it CONTAINER /bin/bash
    4. apt-get update
    5. apt-get install nano
    6. nano /var/www/html/.htaccess
    7. Append at bottom:
      php_value memory_limit 256M
      php_value post_max_size 64M
      php_value upload_max_filesize 64M
    8. After editing, save with Ctrl+X, enter, enter.
  2. In wp-config.php, increase WP_MEMORY_LIMIT and WP_MAX_MEMORY_LIMIT (reason). How to:
    1. SSH to the ECS instance
    2. docker ps (to get wordpress container name)
    3. docker exec -it CONTAINER /bin/bash
    4. apt-get update
    5. apt-get install nano
    6. nano /var/www/html/wp-config.php
    7. Append before /* That's all, stop editing! Happy publishing. */:
    8. define( 'WP_MEMORY_LIMIT', '128M' );
    9. define( 'WP_MAX_MEMORY_LIMIT', '256M' );
    10. After editing, save with Ctrl+X, enter, enter.
  3. Install WP Offload SES Lite for AWS SES Mail Support.
    • Note: need to edit wp-config.php using ssh/SFTP, and check the mount of docker’s rexray plugin, then edit using vi since nano & vim is not available in ECS container image.
    • Enable: Send via SES, Open Tracking, Click Tracking.
  4. (Optional) Alternative to WP Offload SES Lite: weMail.
    • Connect AWS SES using IAM user “mailer” API key.
    • Go to weMail Settings.
    • Registration Opt-in: Enabled.
    • WooCommerce Opt-in: Enabled.
    • Select List: WordPress Users.
    • Enable Notification: Enabled.
    • Enable (transactional) Emails: Enabled.
  5. (Optional) Alternative mailing lists: Sendy + Sendybay, MailPoet (1,000 subscribers free, visual builder), SendFox (basic WYSIWYG, no visual builder).
  6. Install WP Offload Media Lite.
    • Choose “My server is on Amazon Web Services and I’d like to use IAM Roles”
    • Bucket: “”
    • Custom Domain (CNAME): “”
    • Force HTTPS: Yes
    • Remove Files from Server: Yes (Warning: This is may cause problems with some plugins)
  7. (Only if you use Redis) Define in wp-config.php:
    • WP_REDIS_HOST (without port)
    • WP_CACHE_KEY_SALT = (stg.)
  8. (Only if you use Redis) Install Redis Object Cache.
    • Enable Object Cache.
    • Make sure status is “Connected”.
  9. TODO: phpredis (PECL)
  10. Install Breeze.
  11. Setup Cron.


Optional plugins depending on requirements:

  1. Abandoned cart reports plugin:
    1. Abandoned Cart Reports Lite (Free)
    2. Abandoned Cart Reports Premium ($15/yr/store)
    3. Cart Reports ($79/yr)
  2. WooCommerce Product addons plugin ($49/yr)
  3. WooCommerce Orders Spreadsheet ($29.99/yr or $69.99 lifetime)


  1. Install Dokan plugin (Free/Starter/Pro/Business/Enterprise)
  2. Register a vendor
  3. Enable vendor for selling
  4. Free modules:
    1. WooCommerce PDF Invoices & Packing Slips
    2. Dokan Invoice
    3. Setup Logo & Invoice Information: Admin > WooCommerce > PDF Invoices > Template

Elementor & WooCommerce Theme

  1. Theme (Freemium or Pro) compatible with WooCommerce. Should be compatible with Elementor and Elementor WooCommerce Builder:
    • Astra (Pro has its own WooCommerce Designer, $59/year for unlimited sites)
  2. Elementor (Pro).
  3. Starter Templates for Elementor.
  4. Elementor WooCommerce Builder.
  5. Essential Addons for Elementor.
  6. Dynamic Visibility for Elementor.
  7. Design header and footer.

SEO & Analytics

  1. Google Tag Manager.
  2. Track outbound link clicks.
  3. Yoast SEO (Free or Pro).


  1. In your AWS Region, create CloudWatch Dashboard
    • ECS EC2 – CPU per instance: CPUUtilization & CPUCreditBalance
    • ECS EC2 – Disk I/O per instance: EBSReadOps & EBSWriteOps
    • ECS EC2 – Network I/O per instance: NetworkIn & NetworkOut
    • RDS – per instance: DatabaseConnections & FreeableMemory
    • RDS – per instance: FreeStorageSpace & BurstBalance
    • RDS – per instance: ReadIOPS & WriteIOPS
    • S3: Storage
    • S3: Network I/O
    • Billing: Current & Forecasted
  2. Create CloudWatch Alarms with email (SNS) notification

Performance Optimization

Known Issues

Design Customization

  1. Elementor WooCommerce Builder: Single Product Template.
  2. Elementor WooCommerce Builder: Product Archive Template.


  1. TODO


  1. Polylang

Custom Post Types & Advanced Custom Fields

Disclosure: We may get a small commission if you buy certain products linked in this article. However, our opinions are our own and we only promote the products and services that we trust.