<?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>Forem: Terry Leonard Hunt Jr</title>
    <description>The latest articles on Forem by Terry Leonard Hunt Jr (@terry_hunt_d750664824501d).</description>
    <link>https://forem.com/terry_hunt_d750664824501d</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%2F3646981%2F2fed5090-c631-4c5f-af2c-6d41d9e452b7.jpeg</url>
      <title>Forem: Terry Leonard Hunt Jr</title>
      <link>https://forem.com/terry_hunt_d750664824501d</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/terry_hunt_d750664824501d"/>
    <language>en</language>
    <item>
      <title>How to Fire Bad Clients (Without Setting Your Career on Fire)</title>
      <dc:creator>Terry Leonard Hunt Jr</dc:creator>
      <pubDate>Wed, 10 Dec 2025 18:42:00 +0000</pubDate>
      <link>https://forem.com/terry_hunt_d750664824501d/how-to-fire-bad-clients-without-setting-your-career-on-fire-m4p</link>
      <guid>https://forem.com/terry_hunt_d750664824501d/how-to-fire-bad-clients-without-setting-your-career-on-fire-m4p</guid>
      <description>&lt;h2&gt;
  
  
  Why You Shouldn't Feel Guilty
&lt;/h2&gt;

&lt;p&gt;Let's face it. Firing a client feels awkward. But if your client is ghosting invoices, ignoring your expertise, or blocking access to essential tools, it's time for a digital breakup. And guess what? That's totally okay.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contracts are your superhero cape.&lt;/strong&gt;&lt;br&gt;
A solid agreement gives you an escape hatch and protects you when things go sideways. If you do not have one, stop reading and go write one.&lt;/p&gt;


&lt;h2&gt;
  
  
  Top Red Flags That Say "Run"
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. They Think You're a Keyboard, Not a Consultant
&lt;/h3&gt;

&lt;p&gt;You offer expert advice. They ignore it. Then blame you when the site crashes. You are not here to rubber stamp bad ideas.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. They Deny Access to Critical Tools
&lt;/h3&gt;

&lt;p&gt;No admin rights, no server access, no FTP. Congratulations, you are now a magician working blindfolded. Hard pass.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. They Keep Promising to Pay "Next Week"
&lt;/h3&gt;

&lt;p&gt;Client: "Can I pay you next Friday?"&lt;br&gt;
Reality: You will never see a dime.&lt;br&gt;
&lt;strong&gt;Pro tip:&lt;/strong&gt; Add late fees. Call it your emotional damage tax.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. They Are Financially Reckless
&lt;/h3&gt;

&lt;p&gt;If they owe thousands to Amazon, UPS, their cousin Larry, and that one Shopify plugin they forgot to cancel, you will be the last person they pay.&lt;/p&gt;
&lt;h3&gt;
  
  
  5. No Downpayment, No Deal
&lt;/h3&gt;

&lt;p&gt;Never start a project without a deposit. It is not rude. It is smart business. If they refuse to invest upfront, they will not respect the work.&lt;/p&gt;
&lt;h3&gt;
  
  
  6. They Want the Final Product Before Paying
&lt;/h3&gt;

&lt;p&gt;Do not upload anything to their live server until you have been paid in full. Use a dev server you control, or you risk getting ghosted with no money and no leverage.&lt;/p&gt;
&lt;h3&gt;
  
  
  7. They Micromanage Every Pixel
&lt;/h3&gt;

&lt;p&gt;If you get 14 Slack messages about button spacing or are asked to "make the site feel more vibey," you are being creatively smothered. You are not their emotional support developer.&lt;/p&gt;
&lt;h3&gt;
  
  
  8. They Treat You Like a Butler
&lt;/h3&gt;

&lt;p&gt;"Can you update my email signature?"&lt;br&gt;
"Can you Photoshop my dog into the homepage banner?"&lt;br&gt;
If your job description keeps expanding but your pay does not, it is time to dip.&lt;/p&gt;


&lt;h2&gt;
  
  
  How to Fire a Client Without Burning Bridges
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Reference the Contract
&lt;/h3&gt;

&lt;p&gt;Do not just say "I am out."&lt;br&gt;
Say, "As stated in Section 8B of our agreement, I am terminating our engagement effective immediately." It sounds polished and professional.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Send a Calm, Direct Email
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hi [Client],

Due to [non-payment / access issues / general chaos], I'm formally ending our working relationship effective [date]. I will deliver all agreed-upon materials completed up to this point.

Best of luck moving forward.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Only Deliver What Was Paid For
&lt;/h3&gt;

&lt;p&gt;If they paid for 40 percent of the work, send 40 percent. Not 100 percent. You are a professional, not a donation service.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Do Not Vent Publicly
&lt;/h3&gt;

&lt;p&gt;Keep the rage tweets in your drafts folder. Screenshotting conversations may feel satisfying, but it can harm your reputation or lead to legal issues. Vent privately.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to Do After You Fire a Client
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Pour Yourself a Coffee (or Something Stronger)
&lt;/h3&gt;

&lt;p&gt;You just dodged a stress tornado. Take a moment to breathe and remember you are not a punching bag with a GitHub account.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Review and Refine Your Process
&lt;/h3&gt;

&lt;p&gt;Update your contract. Add stricter payment terms. Enforce that staging-only deployment rule you promised yourself last time. Every bad client teaches you something.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Refill Your Pipeline
&lt;/h3&gt;

&lt;p&gt;Use your regained time to find clients who appreciate your work. Update your portfolio, reach out to past clients, or post a sharp case study on LinkedIn.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Celebrate Like a Freelancer Who Chooses Peace
&lt;/h3&gt;

&lt;p&gt;Treat yourself to tacos or bubble tea. You did not just fire a bad client. You made space for better projects, higher pay, and a more peaceful inbox.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Saying no to a bad client is how you say yes to better ones. Do not be afraid to walk away from disrespect, scope creep, or unpaid labor. You are running a business, not playing freelance roulette.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Firing a client does not make you rude. It makes you a boss.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>freelance</category>
      <category>clients</category>
      <category>webdev</category>
      <category>consulting</category>
    </item>
    <item>
      <title>Secure Strapi Deployment on Amazon AWS</title>
      <dc:creator>Terry Leonard Hunt Jr</dc:creator>
      <pubDate>Mon, 08 Dec 2025 14:27:39 +0000</pubDate>
      <link>https://forem.com/terry_hunt_d750664824501d/secure-strapi-deployment-on-amazon-aws-n2h</link>
      <guid>https://forem.com/terry_hunt_d750664824501d/secure-strapi-deployment-on-amazon-aws-n2h</guid>
      <description>&lt;h1&gt;
  
  
  ☑️ Prerequisites
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;You have created a &lt;strong&gt;&lt;a href="https://docs-v4.strapi.io/dev-docs/quick-start" rel="noopener noreferrer"&gt;Strapi project&lt;/a&gt;&lt;/strong&gt; to deploy on AWS&lt;/li&gt;
&lt;li&gt;You have read the &lt;strong&gt;&lt;a href="https://docs-v4.strapi.io/dev-docs/deployment#application-configuration" rel="noopener noreferrer"&gt;configuration documentation&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You understand the basics of AWS IAM and core security best practices&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  ☁️ Strapi Cloud
&lt;/h1&gt;

&lt;p&gt;You can also use &lt;strong&gt;&lt;a href="https://docs-v4.strapi.io/cloud/intro" rel="noopener noreferrer"&gt;Strapi Cloud&lt;/a&gt;&lt;/strong&gt; to deploy and host your project quickly.&lt;/p&gt;




&lt;h1&gt;
  
  
  Security First IAM Setup
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Create IAM User with Minimal Permissions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Security Note:&lt;/strong&gt; The official Strapi guide suggests broad permissions. The following approach applies hardened, minimal, service specific permissions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Administrator User (One time setup)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Login as &lt;strong&gt;root&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Create an &lt;strong&gt;Administrator&lt;/strong&gt; role following the AWS IAM Admin User Guide
&lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/getting-started_create-admin-group.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/IAM/latest/UserGuide/getting-started_create-admin-group.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Create Strapi Developer User with Hardened Permissions
&lt;/h3&gt;

&lt;p&gt;Instead of using &lt;code&gt;*FullAccess&lt;/code&gt; policies, create custom policies with only the required capabilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EC2 Minimal Policy:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&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="s2"&gt;"ec2:DescribeInstances"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ec2:StartInstances"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ec2:StopInstances"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ec2:RebootInstances"&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;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;RDS Minimal Policy:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&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="s2"&gt;"rds:DescribeDBInstances"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"rds:DescribeDBClusters"&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;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;S3 Secure Policy (replace with your bucket name):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"StrapiS3Access"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&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="s2"&gt;"s3:PutObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"s3:ListBucket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"s3:DeleteObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"s3:PutObjectAcl"&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;"Resource"&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="s2"&gt;"arn:aws:s3:::s3-bucket-name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::s3-bucket-name/*"&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="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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Secrets Manager Policy:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&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="s2"&gt;"secretsmanager:GetSecretValue"&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;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:secretsmanager:your-region:your-account-id:secret:your-secret-name*"&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;SES Policy (if using emails):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&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="s2"&gt;"ses:SendEmail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ses:SendRawEmail"&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;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  AWS VPC Setup
&lt;/h1&gt;

&lt;p&gt;Follow Strapi's original VPC guide but ensure you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select the correct AWS region&lt;/li&gt;
&lt;li&gt;Use two Availability Zones for redundancy&lt;/li&gt;
&lt;li&gt;Configure two public subnets and two private subnets&lt;/li&gt;
&lt;li&gt;Enable DNS hostnames and DNS resolution&lt;/li&gt;
&lt;/ol&gt;




&lt;h1&gt;
  
  
  EC2 Instance with IAM Role (Recommended)
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Create IAM Role for EC2
&lt;/h2&gt;

&lt;p&gt;Instead of access keys, assign an IAM role to your instance.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to IAM → Roles → Create Role&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;EC2&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Attach the minimal policies created earlier&lt;/li&gt;
&lt;li&gt;Name the role &lt;code&gt;StrapiEC2Role&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  2. Launch EC2 Instance
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;Ubuntu Server 22.04 LTS&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;t2.small&lt;/strong&gt; or higher&lt;/li&gt;
&lt;li&gt;Attach the role &lt;code&gt;StrapiEC2Role&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure security groups with minimal ports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSH 22 restricted to your IP&lt;/li&gt;
&lt;li&gt;HTTP 80&lt;/li&gt;
&lt;li&gt;HTTPS 443&lt;/li&gt;
&lt;li&gt;Custom TCP 1337 only for testing&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Security Warning:&lt;/strong&gt; Remove port 1337 after configuring NGINX.&lt;/p&gt;




&lt;h1&gt;
  
  
  Secure RDS Database Setup
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Create PostgreSQL Database
&lt;/h2&gt;

&lt;p&gt;Security best practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the latest PostgreSQL engine&lt;/li&gt;
&lt;li&gt;Select Production templates&lt;/li&gt;
&lt;li&gt;Connect RDS to your VPC&lt;/li&gt;
&lt;li&gt;Use private subnets&lt;/li&gt;
&lt;li&gt;Enable encryption at rest&lt;/li&gt;
&lt;li&gt;Enable automated backups&lt;/li&gt;
&lt;li&gt;Enable Performance Insights&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Database Security Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use strong passwords longer than 20 characters&lt;/li&gt;
&lt;li&gt;Encrypt data in transit&lt;/li&gt;
&lt;li&gt;Restrict RDS access to only your EC2 security group&lt;/li&gt;
&lt;li&gt;Apply routine updates&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Secure S3 Configuration
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Critical S3 Security Update
&lt;/h2&gt;

&lt;p&gt;Avoid the public bucket policy in the original guide. It exposes all actions publicly.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Create Private S3 Bucket
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Enable “Block all public access”&lt;/li&gt;
&lt;li&gt;Enable versioning&lt;/li&gt;
&lt;li&gt;Enable encryption&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Secure Access Options
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Option A: Private with Signed URLs (Recommended)&lt;/strong&gt;&lt;br&gt;
Uses temporary signed URLs for access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option B: Public Read Only (if required)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PublicReadGetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::your-bucket-name/*"&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows reading but not modifying files.&lt;/p&gt;




&lt;h1&gt;
  
  
  Secure Environment Variable Management
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. AWS Secrets Manager Setup
&lt;/h2&gt;

&lt;p&gt;Store sensitive variables in Secrets Manager.&lt;/p&gt;

&lt;p&gt;Create a secret:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws secretsmanager create-secret &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"strapi/production/env"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--description&lt;/span&gt; &lt;span class="s2"&gt;"Strapi production environment variables"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--secret-string&lt;/span&gt; file://secret.json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example &lt;code&gt;secret.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"APP_KEYS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-app-keys"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"API_TOKEN_SALT"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-api-token-salt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ADMIN_JWT_SECRET"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-admin-jwt-secret"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"JWT_SECRET"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-jwt-secret"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"DATABASE_HOST"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-rds-endpoint.rds.amazonaws.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"DATABASE_PORT"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5432"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"DATABASE_NAME"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"strapi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"DATABASE_USERNAME"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postgres"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"DATABASE_PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-secure-password"&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_REGION"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us-east-1"&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_BUCKET_NAME"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-bucket-name"&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;/div&gt;



&lt;h2&gt;
  
  
  2. Environment Fetch Scripts
&lt;/h2&gt;

&lt;p&gt;Goal: never commit &lt;code&gt;.env&lt;/code&gt; files to Git.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option A: Bash Script
&lt;/h3&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;# fetch-env.sh&lt;/span&gt;

&lt;span class="nv"&gt;SECRET_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"strapi/production/env"&lt;/span&gt;
&lt;span class="nv"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
&lt;span class="nv"&gt;OUTPUT_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;".env"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Fetching secrets..."&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; aws &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"AWS CLI missing"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; jq &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"jq missing"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;SECRET_JSON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws secretsmanager get-secret-value &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--secret-id&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SECRET_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; SecretString &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; text 2&amp;gt;/dev/null&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;$SECRET_JSON&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'to_entries|map("\(.key)=\(.value)")|.[]'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUTPUT_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make executable:&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;chmod&lt;/span&gt; +x fetch-env.sh
./fetch-env.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option B: Node.js Script
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&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;fs&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SecretsManagerClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;GetSecretValueCommand&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&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;@aws-sdk/client-secrets-manager&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;client&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;SecretsManagerClient&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-east-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchSecret&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="nx"&gt;outputPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.env&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="k"&gt;try&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;command&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;GetSecretValueCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;SecretId&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&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;secret&lt;/span&gt; &lt;span class="o"&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SecretString&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;envData&lt;/span&gt; &lt;span class="o"&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;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;val&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;key&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;val&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="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&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;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;envData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error fetching secret:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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="nf"&gt;exit&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="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;secretName&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;argv&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="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;strapi/production/env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;fetchSecret&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install dependencies:&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; @aws-sdk/client-secrets-manager
node fetch-secrets.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Secure PM2 Configuration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;apps&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;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;strapi-secure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/home/ubuntu/your-strapi-project&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;npm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/home/ubuntu/your-strapi-project/.env&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;h1&gt;
  
  
  Node.js and Application Setup
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Install Dependencies
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ca-certificates curl gnupg
&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /etc/apt/keyrings
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | &lt;span class="nb"&gt;sudo &lt;/span&gt;gpg &lt;span class="nt"&gt;--dearmor&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /etc/apt/keyrings/nodesource.gpg
&lt;span class="nv"&gt;NODE_MAJOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;20
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_&lt;/span&gt;&lt;span class="nv"&gt;$NODE_MAJOR&lt;/span&gt;&lt;span class="s2"&gt;.x nodistro main"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/sources.list.d/nodesource.list
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; nodejs

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @aws-sdk/client-secrets-manager

&lt;span class="nb"&gt;mkdir&lt;/span&gt; ~/.npm-global
npm config &lt;span class="nb"&gt;set &lt;/span&gt;prefix &lt;span class="s1"&gt;'~/.npm-global'&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH=~/.npm-global/bin:$PATH'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.profile
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.profile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Deploy Strapi Securely
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/your-org/your-strapi-repo.git
&lt;span class="nb"&gt;cd &lt;/span&gt;your-strapi-repo

npm &lt;span class="nb"&gt;install
&lt;/span&gt;node fetch-secrets.js
&lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production npm run build

npm &lt;span class="nb"&gt;install &lt;/span&gt;pm2@latest &lt;span class="nt"&gt;-g&lt;/span&gt;
pm2 start ecosystem.config.js
pm2 save
pm2 startup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Production Security Checklist
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Before Going Live
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Remove port 1337 access&lt;/li&gt;
&lt;li&gt;Configure NGINX reverse proxy with TLS&lt;/li&gt;
&lt;li&gt;Enable CloudWatch logging&lt;/li&gt;
&lt;li&gt;Enable automated RDS and S3 backups&lt;/li&gt;
&lt;li&gt;Enable AWS WAF&lt;/li&gt;
&lt;li&gt;Enable VPC Flow Logs&lt;/li&gt;
&lt;li&gt;Configure AWS Config&lt;/li&gt;
&lt;li&gt;Configure log aggregation and automated patches&lt;/li&gt;
&lt;li&gt;Enable CloudTrail auditing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Ongoing Security
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Update EC2 packages regularly&lt;/li&gt;
&lt;li&gt;Rotate database passwords every quarter&lt;/li&gt;
&lt;li&gt;Monitor CloudTrail logs&lt;/li&gt;
&lt;li&gt;Review IAM permissions often&lt;/li&gt;
&lt;li&gt;Update Strapi and dependencies&lt;/li&gt;
&lt;li&gt;Test backups and recovery procedures&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Complete Git Workflow
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Commit to Git
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;fetch-env.sh
fetch-secrets.js
.env.example
.gitignore
deploy.sh
package.json
/src/
/config/
ecosystem.config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Never Commit to Git
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;.env
.env.local
.aws/
secret.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Recommended .gitignore
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;.env
.env.&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt;.env.example
secret.json
.aws/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Deployment Automation
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. deploy.sh
&lt;/h2&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="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="nv"&gt;SECRET_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"strapi/production/env"&lt;/span&gt;
&lt;span class="nv"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
&lt;span class="nv"&gt;APP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/home/ubuntu/your-strapi-project"&lt;/span&gt;
&lt;span class="nv"&gt;PM2_CONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/home/ubuntu/ecosystem.config.js"&lt;/span&gt;

&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$APP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

git pull origin main
npm ci &lt;span class="nt"&gt;--production&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"fetch-env.sh"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  ./fetch-env.sh
&lt;span class="k"&gt;else
  &lt;/span&gt;node fetch-secrets.js &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SECRET_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production npm run build

pm2 restart &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PM2_CONFIG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; pm2 start &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PM2_CONFIG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
pm2 save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. EC2 Deployment
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/your-org/your-strapi-repo.git
&lt;span class="nb"&gt;cd &lt;/span&gt;your-strapi-repo

&lt;span class="nb"&gt;chmod&lt;/span&gt; +x fetch-env.sh deploy.sh
npm &lt;span class="nb"&gt;install&lt;/span&gt;
./deploy.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Subsequent Deployments
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /home/ubuntu/your-strapi-project
./deploy.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Webhook Integration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your_webhook_secret&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;repo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/home/ubuntu/your-strapi-project/&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;http&lt;/span&gt; &lt;span class="o"&gt;=&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;http&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;crypto&lt;/span&gt; &lt;span class="o"&gt;=&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;crypto&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;exec&lt;/span&gt; &lt;span class="o"&gt;=&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;child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha1=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-hub-signature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`cd &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; ./deploy.sh`&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Team Development Workflow
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Setup for New Members
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Initial Setup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/your-org/your-strapi-repo.git
&lt;span class="nb"&gt;cd &lt;/span&gt;your-strapi-repo
npm &lt;span class="nb"&gt;install
&lt;/span&gt;aws configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generate Environment File
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./fetch-env.sh
node fetch-secrets.js strapi/development/env
node fetch-secrets.js strapi/staging/env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Start Development
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Developer README Section
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Environment Setup&lt;/span&gt;

This project uses AWS Secrets Manager.

&lt;span class="gu"&gt;### Quick Start&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; Clone the repository
&lt;span class="p"&gt;2.&lt;/span&gt; Run npm install
&lt;span class="p"&gt;3.&lt;/span&gt; Run ./fetch-env.sh
&lt;span class="p"&gt;4.&lt;/span&gt; Run npm run develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Cost Optimization
&lt;/h1&gt;

&lt;h2&gt;
  
  
  AWS Secrets Manager Pricing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;0.40 dollars per secret per month&lt;/li&gt;
&lt;li&gt;0.05 dollars per 10,000 API calls&lt;/li&gt;
&lt;li&gt;First 30 days free&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example cost:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storage 0.40 dollars&lt;/li&gt;
&lt;li&gt;API calls 0.005 dollars&lt;/li&gt;
&lt;li&gt;Total about 0.41 dollars per month&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cost Saving Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use EC2 IAM roles&lt;/li&gt;
&lt;li&gt;Tag resources properly&lt;/li&gt;
&lt;li&gt;Use RDS reserved instances&lt;/li&gt;
&lt;li&gt;Enable S3 lifecycle policies&lt;/li&gt;
&lt;li&gt;Monitor costs using Cost Explorer&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Troubleshooting
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. IAM Permission Errors
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ensure IAM role is attached to EC2&lt;/li&gt;
&lt;li&gt;Ensure policies contain required actions&lt;/li&gt;
&lt;li&gt;Check resource ARNs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Secrets Manager Issues
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Check secret name and region&lt;/li&gt;
&lt;li&gt;Verify IAM permissions&lt;/li&gt;
&lt;li&gt;Check AWS SDK credentials&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. S3 Upload Issues
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Check bucket policy&lt;/li&gt;
&lt;li&gt;Check CORS&lt;/li&gt;
&lt;li&gt;Check IAM permissions&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you want, I can also format this for &lt;strong&gt;GitHub README&lt;/strong&gt;, generate a &lt;strong&gt;table of contents&lt;/strong&gt;, or optimize the Markdown for &lt;strong&gt;SEO on dev.to&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>api</category>
      <category>backend</category>
      <category>aws</category>
    </item>
    <item>
      <title>Deploy Your Own Strapi CMS to Railway (No Templates Needed)</title>
      <dc:creator>Terry Leonard Hunt Jr</dc:creator>
      <pubDate>Fri, 05 Dec 2025 13:35:00 +0000</pubDate>
      <link>https://forem.com/terry_hunt_d750664824501d/deploy-your-own-strapi-cms-to-railway-no-templates-needed-4118</link>
      <guid>https://forem.com/terry_hunt_d750664824501d/deploy-your-own-strapi-cms-to-railway-no-templates-needed-4118</guid>
      <description>&lt;h2&gt;
  
  
  🚀 How to Set Up Strapi Locally and Deploy to Railway (The Easy Way)
&lt;/h2&gt;

&lt;p&gt;Want to build and deploy your own Strapi CMS without touching Docker or overcomplicating things? Here is how you can go from local development to a live app on &lt;a href="https://railway.com?referralCode=ps81C1" rel="noopener noreferrer"&gt;Railway&lt;/a&gt; with &lt;strong&gt;no one-click templates needed&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🆚 Quick Note: Strapi Cloud vs Railway
&lt;/h2&gt;

&lt;p&gt;Strapi offers their own &lt;strong&gt;free tier cloud hosting&lt;/strong&gt;:&lt;br&gt;
👉 &lt;a href="https://strapi.io/pricing-cloud" rel="noopener noreferrer"&gt;https://strapi.io/pricing-cloud&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But many developers prefer &lt;strong&gt;Railway&lt;/strong&gt; for full control over:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your Strapi app&lt;/li&gt;
&lt;li&gt;your data&lt;/li&gt;
&lt;li&gt;your file system&lt;/li&gt;
&lt;li&gt;your deployments&lt;/li&gt;
&lt;li&gt;your database choices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If that sounds like your style, try Railway here:&lt;br&gt;
👉 &lt;a href="https://railway.com?referralCode=ps81C1" rel="noopener noreferrer"&gt;https://railway.com?referralCode=ps81C1&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  1. 🧑‍💻 Set Up Strapi on Your Local Machine
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Step 1: Install Strapi CLI
&lt;/h3&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; &lt;span class="nt"&gt;-g&lt;/span&gt; create-strapi-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 2: Create Your Project
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-strapi-app@latest my-strapi-project &lt;span class="nt"&gt;--quickstart&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This spins up a new Strapi app and launches it at:&lt;br&gt;
&lt;code&gt;http://localhost:1337&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; When prompted to create an admin user in the browser, go ahead and do that now.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Step 3: Test and Tweak
&lt;/h3&gt;

&lt;p&gt;Add your content types, explore the admin panel, and make sure everything works as expected.&lt;/p&gt;

&lt;p&gt;When finished, stop the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctrl + c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. 🧳 Prepare Your Project for Railway
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Add Environment Configs
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in your project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DATABASE_CLIENT=sqlite
NODE_ENV=production
PORT=1337
APP_KEYS=someLongAppKey1,someLongAppKey2
API_TOKEN_SALT=randomStringHere
ADMIN_JWT_SECRET=randomSecretHere
JWT_SECRET=anotherSecretHere
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🔐 Use &lt;a href="https://randomkeygen.com" rel="noopener noreferrer"&gt;https://randomkeygen.com&lt;/a&gt; to generate secure values.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 2: Update &lt;code&gt;package.json&lt;/code&gt; Scripts
&lt;/h3&gt;

&lt;p&gt;Ensure your scripts section includes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&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;"develop"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"strapi develop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"strapi start"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"strapi build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"strapi"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"strapi"&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;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Push to GitHub
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Initial commit"&lt;/span&gt;
git branch &lt;span class="nt"&gt;-M&lt;/span&gt; main
git remote add origin https://github.com/your-username/your-repo.git
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. 🚢 Deploy to Railway
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Connect Your GitHub Repo
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to Railway: &lt;a href="https://railway.com?referralCode=ps81C1" rel="noopener noreferrer"&gt;https://railway.com?referralCode=ps81C1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create a new project&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Deploy from GitHub Repo&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Choose your Strapi repository&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2: Set Environment Variables
&lt;/h3&gt;

&lt;p&gt;Go to Railway’s &lt;strong&gt;Variables&lt;/strong&gt; tab and add the same values you put in your &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Your app will not deploy correctly without these secrets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 3: Trigger the Deployment
&lt;/h3&gt;

&lt;p&gt;Railway detects it is a Node.js project and automatically runs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm run build&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm start&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once deployed, you will get a live URL in the &lt;strong&gt;Deployments&lt;/strong&gt; tab 🎉&lt;/p&gt;




&lt;h2&gt;
  
  
  4. ✅ Final Touches
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;📦 Prefer PostgreSQL over SQLite? Add Railway’s PostgreSQL plugin and update your &lt;code&gt;.env&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;☁️ Want persistent media uploads? Use a Strapi upload provider such as S3 or Cloudinary:
&lt;a href="https://docs-v4.strapi.io/dev-docs/plugins/upload/" rel="noopener noreferrer"&gt;https://docs-v4.strapi.io/dev-docs/plugins/upload/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔐 If exposing APIs, configure CORS plus roles and permissions.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 That’s It
&lt;/h2&gt;

&lt;p&gt;You have now built and deployed a Strapi CMS, fully customized and not locked into any presets.&lt;/p&gt;

&lt;p&gt;Try Railway:&lt;br&gt;
👉 &lt;a href="https://railway.com?referralCode=ps81C1" rel="noopener noreferrer"&gt;https://railway.com?referralCode=ps81C1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Curious about Strapi Cloud? Explore it here:&lt;br&gt;
👉 &lt;a href="https://strapi.io/pricing-cloud" rel="noopener noreferrer"&gt;https://strapi.io/pricing-cloud&lt;/a&gt;&lt;/p&gt;

</description>
      <category>backend</category>
      <category>devops</category>
      <category>cloud</category>
      <category>nocode</category>
    </item>
    <item>
      <title>Why WordPress Isn't What It Used To Be (And It Sucks Now)</title>
      <dc:creator>Terry Leonard Hunt Jr</dc:creator>
      <pubDate>Thu, 04 Dec 2025 20:04:18 +0000</pubDate>
      <link>https://forem.com/terry_hunt_d750664824501d/why-wordpress-isnt-what-it-used-to-be-and-it-sucks-now-3nnn</link>
      <guid>https://forem.com/terry_hunt_d750664824501d/why-wordpress-isnt-what-it-used-to-be-and-it-sucks-now-3nnn</guid>
      <description>&lt;h2&gt;
  
  
  A Nostalgic Beginning
&lt;/h2&gt;

&lt;p&gt;Let's rewind to 2003. WordPress had just been born, a promising open-source CMS that felt like the future of the web. It was lean, clean, and anyone could fire up a blog in minutes. I remember trying it out and thinking, 'This is going to change everything.' And for a while, it did. WordPress became the go-to platform for bloggers, small businesses, and even enterprise websites.&lt;/p&gt;

&lt;p&gt;Then came WooCommerce, and it was a big deal. Suddenly, you could run a full-blown online store without spending thousands on custom development. Life was simple. You had your theme, maybe a plugin or two, and your website was good to go. But fast forward to 2025, and WordPress has morphed into a bloated, plugin-infested monster that's more of a maintenance nightmare than a CMS.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Plugin Overdose Epidemic
&lt;/h2&gt;

&lt;p&gt;Here's the thing with WordPress plugins—they're like Pringles. Once you pop, you can't stop. Need a contact form? Plugin. SEO optimization? Plugin. Want breadcrumbs? Yup, another plugin. Before you know it, your WordPress site is carrying the weight of 30+ plugins, each adding its own load of scripts, CSS, and backend bloat.&lt;/p&gt;

&lt;p&gt;But wait, it gets worse. These plugins often don't play nice with each other. Install Plugin A, and suddenly Plugin B decides to throw a tantrum, breaking your site in ways that would make even the most seasoned developer question life choices. Plugin conflicts are the norm, not the exception.&lt;/p&gt;

&lt;p&gt;And let's not forget updates. Every other day, you're greeted with a cheerful notification that half your plugins need updating. Better pray none of those updates introduce new bugs, break compatibility, or worse—open up new security vulnerabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Elementor: The Necessary Evil We All Love to Hate
&lt;/h2&gt;

&lt;p&gt;Now, let's talk about the elephant—or should I say, Elementor—in the room. On paper, Elementor sounds fantastic: a drag-and-drop page builder that lets you design beautiful pages without touching code. In practice, it's a performance black hole.&lt;/p&gt;

&lt;p&gt;You get your fancy sliders, animations, and pixel-perfect layouts, but you also get bloated HTML, inlined CSS spaghetti, and JavaScript files that seem to multiply like rabbits. By the time an Elementor-heavy page finishes rendering, you could've hand-coded it in pure HTML and CSS and still had time to grab a coffee.&lt;/p&gt;

&lt;p&gt;Don't get me wrong, drag-and-drop builders have their place, but Elementor has become a crutch that's slowing down thousands of websites globally. Google PageSpeed Insights weeps every time an Elementor page is loaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security? What Security?
&lt;/h2&gt;

&lt;p&gt;One of the biggest WordPress downfalls is security—or the lack thereof. The sheer popularity of WordPress makes it a prime target for hackers, bots, and anyone looking to exploit vulnerable websites. And let's face it, the WordPress ecosystem is a ticking time bomb when it comes to security.&lt;/p&gt;

&lt;p&gt;The 'one-click WordPress install' via cPanel is a convenience that hides the ugly truth. Most people setting up WordPress don't:&lt;/p&gt;

&lt;h2&gt;
  
  
  Change default admin URLs
&lt;/h2&gt;

&lt;p&gt;Implement Web Application Firewalls (WAF)&lt;br&gt;
Disable XML-RPC&lt;br&gt;
Regularly audit plugins and themes for vulnerabilities&lt;br&gt;
They just install WordPress, slap on a theme, add a few plugins, and call it a day. This negligence creates a paradise for attackers. Outdated plugins, poorly-coded themes, and weak server configurations are all open doors waiting to be exploited.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Worst Offense: Customer Passwords
&lt;/h2&gt;

&lt;p&gt;Now, let's address the unforgivable sin: customer passwords.&lt;/p&gt;

&lt;p&gt;Believe it or not, there are still WordPress setups storing plain text passwords in databases. Even when passwords are hashed, improper configurations, lazy developers, or shady plugins can compromise user credentials. A leaked password file from a WooCommerce store is a disaster waiting to happen.&lt;/p&gt;

&lt;p&gt;The problem is compounded by the fact that many WordPress users aren't developers. They rely on 'set-it-and-forget-it' solutions that work until they don't. And when they don't, it's often too late. No backups. No security audits. Just a panicked site owner googling 'how to recover a hacked WordPress site.'&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Bottlenecks Everywhere
&lt;/h2&gt;

&lt;p&gt;Do you enjoy fast-loading websites? WordPress will cure you of that.&lt;/p&gt;

&lt;p&gt;The average WordPress site today is an intricate maze of theme options, plugin settings, shortcodes, and custom widgets. Each of these adds processing overhead. Database queries pile up, rendering times increase, and before you know it, your site takes 5 seconds to load. That's an eternity in the digital world where every extra second of load time costs you conversions.&lt;/p&gt;

&lt;p&gt;And don't think throwing caching plugins and CDN layers on top will magically fix everything. Those are band-aids, not solutions. At the core, WordPress is still trying to juggle a million moving parts that weren't meant to scale together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Headless CMS: A Breath of Fresh Air
&lt;/h2&gt;

&lt;p&gt;If you're tired of playing plugin roulette and dealing with bloated page builders, it might be time to look at a headless CMS. Platforms like Strapi, Contentful, or Sanity let you manage your content through a clean, API-first approach. No more plugin conflicts. No more page builder bloat.&lt;/p&gt;

&lt;p&gt;With a headless CMS, you get the freedom to build your frontend using modern frameworks like Next.js or Nuxt, giving you total control over performance and security. Sure, the learning curve is steeper, but the long-term gains in speed, flexibility, and security are worth it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;WordPress had a good run. It was the king of CMS for years, but in 2025, it feels like a relic from a different era. The constant plugin bloat, security nightmares, performance issues, and reliance on builders like Elementor make it an increasingly bad choice for serious projects.&lt;/p&gt;

&lt;p&gt;If you're setting up a hobby blog or a simple portfolio, WordPress can still be an option. But if you're building a scalable business, eCommerce site, or a content-driven platform, it's time to move on. Modern alternatives offer cleaner architectures, better security, and superior performance.&lt;/p&gt;

&lt;p&gt;So unless you enjoy spending your weekends debugging plugin conflicts, waiting for Elementor pages to load, and fighting off bot attacks, maybe it's time to break up with WordPress.&lt;/p&gt;

&lt;p&gt;It's not you, WordPress. It's… well, actually, it is you.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>wordpress</category>
      <category>website</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
