Deploying Strapi on AWS EC2, Ubuntu 20.04 (with Laravel Forge)

System Information
  • Strapi Version: 3.5.3
  • Operating System: Linux (Ubuntu 20.04)
  • Database: MySQL 5.6
  • Node Version: 12.21.0
  • NPM Version: 6.14.11

Hi,

Apologies in advance for the long post, but I hope it does provide you, the reader, with all the required info to help me with my issue.

I’ve been trying to deploy Strapi to an AWS EC2 instance for about a day now, without success. Pulling in the repo and building it on the server with the build command goes just fine, but when I try to start the application I keep receiving the following error:

error Error: listen EADDRNOTAVAIL: address not available [IP address]:1337

Where “IP address” is the public IPv4 address of the server.

I’ve tried:

  1. installing pm2 to run the application
  2. running npm start from the root of the directory
  3. running node [/absolute/path/to/directory]/server.js after installing a server.js file conform the docs.

The steps I’ve taken so far ar as follows:

  • I’ve created an A-record in my DNS provider pointing the domain name to the server IP address
  • I’ve created a .env file with a PORT, HOST and APP_URL value for Strapi’s config/server.js
  • I’ve adapted the default Nginx config file that comes with my deployment service provider (Laravel Forge) for Node.js, to listen to HTTP requests on Strapi’s default port :1337
  • I’ve configured the webroot for Strapi to be /build. This made sense to me since the index.html file is located there, as well as all the compiled JS etc. However, in different forum posts I’ve also seen /public used as webroot. Maybe this is due to differences in version?

I’ve had no issues deploying and running a different Node.js-based application from the same server, but I can’t even get the Strapi app to run… Please help?

Kind regards,

Yoeri

P.S. Below I’ve pasted my config/server.js, .env and Nginx conf (created by Laravel Forge, adapted to work with Node (the “location /” block, specifically)) with sensitive info (domain name and credentials) redacted:

server.js

module.exports = ({ env }) => ({
  host: env('HOST', '0.0.0.0'),
  port: env.int('PORT', 1337),
  url: env('APP_URL'),
  admin: {
    auth: {
      secret: env('ADMIN_JWT_SECRET', 'secret-admin-jwt-default-value'),
    },
  },
});

.env

NODE_ENV=production
HOST=domain-name
PORT=1337
APP_URL=http://domain-name
DATABASE_HOST=rds-database-endpoint
DATABASE_PORT=3306
DATABASE_NAME=strapi
DATABASE_USERNAME=dbuser
DATABASE_PASSWORD=dbpassword
DATABASE_SSL=false

Nginx

# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/domain-name/before/*;

server {
    listen 80;
    listen [::]:80;
    server_name domain-name;
    server_tokens off;
    root /home/forge/domain-name/build;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.htm index.php;

    charset utf-8;

    # FORGE CONFIG (DO NOT REMOVE!)
    include forge-conf/domain-name/server/*;

    location / {
        proxy_pass http://localhost:1337; # Port number of node http server
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/domain-name-error.log error;

    error_page 404 /index.php;

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/content.wopp.nl/after/*;
HOST=127.0.0.1
PORT=1337
APP_URL=http://domain-name

HOST should contain your internal address, not the external one, 127.0.0.1 or localhost.

For nodejs apps with proxy pass you don’t need to declare root folder in nginx, în current case /public folder is served by Strapi, not by nginx as a static folder.

OMG YES! I had been banging my head against my desk for over a day, and the solution is so simple. Thank you for your help.

For future reference, I’d be willing to rewrite my original post to leave out a lot of the information that has turned out to be irrelevant for the answer. Do you think this would be a good idea?

1 Like

Yeah, you can edit it and add an updated info for others at the bottom of your initial question.

Hi Yoeri,

I’ve created an Ansible play that gives you a quick solution to deploy Strapi on Amazon AWS automatically. The solution spins up an EC2 and an RDS PostgreSQL database. Instances are placed in a private subnet (database) and a public subnet (EC2).

You can find a tutorial about this solution here: Using Ansible For Automatic Deployment Of A Strapi CMS To Amazon AWS | by Frank Haubenschild | Medium

The corresponding Github repo can be found here: GitHub - hauben/ansible-play-strapi: Ansible play with several roles to deploy the headless CMS Strapi on

Maybe it’s interesting for you or maybe some others who are looking for an automatic deployment solution to Amazon AWS.

Cheers
Frank