Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

A MERN deployment on one EC2 server can use Docker Compose to run the application services, Terraform to provision infrastructure, and GitHub Actions to automate releases. The pieces fit together only after you decide where MongoDB lives, how the React app is served, which ports the API uses, and how the workflow reaches the server. Those are application-specific choices, not facts that can be assumed for every MERN project.

This is an implementation guide, not a claim that a particular app was built or tested. Use the steps below to map your repository and AWS design into a deployment; fill in the app-specific settings from your own code and verify each stage before relying on it.

How the deployment pieces fit together

Docker Docs describes a single-server approach as a straightforward way to deploy an application: run it on one server in a way similar to development. Compose can coordinate the containers on that EC2 host, Terraform can describe and provision AWS resources, and GitHub Actions can run checks and automate a release. This is an architecture choice, not a guarantee of availability, security, or scalability.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Before writing configuration, draw the actual request and data paths. Identify the React frontend, the Express/Node API, and MongoDB. For each, record whether it runs in a container, which image builds it, which other services it needs, and where its persistent data resides. MongoDB might be a Compose service, a separate host, or a managed database; choose and document the topology your application actually uses.

  • Decide whether React is built into static assets and served by a web server, or handled another way in your app.
  • Record the API’s listening port and whether it should be reachable from the internet or only through another service.
  • Establish the database connection path and persistence plan; do not assume a container’s writable layer is durable storage.
  • List the environment variables required by each service, and keep credentials out of committed Compose files and workflow examples.

Prepare a production Compose configuration

Docker recommends separating production-specific settings from the base Compose configuration. A production override can remove development code mounts, set the host-port bindings and environment configuration the app requires, add a restart policy, and include supporting services. Those values depend on the repository; do not copy development ports or mounts into production without checking what they expose.

Review the service boundaries

For each service, decide whether it needs a host port at all. A service that only another container uses generally should not be exposed publicly just because it has a container port. Expose only the entry point that the chosen architecture requires, and match that binding to the EC2 security group rules you intend to allow.

Keep environment and data handling explicit

Supply production configuration through a secure mechanism appropriate to your deployment rather than committing passwords or private keys. Specify how persistent database data is stored and backed up based on the selected MongoDB topology. Compose configuration alone does not establish a backup or recovery plan.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Check Docker Docs’ Use Compose in production guidance against your configuration. It identifies production overrides as a way to adjust mounts, ports, environment variables, restart behavior, and supporting services for deployment.

Provision the EC2 infrastructure with Terraform

Write down the infrastructure the app actually needs before applying Terraform: AWS region, network assumptions, EC2 instance, security group, and any additional resources required by the selected database or deployment design. The reviewed documentation does not prescribe a MERN-specific Terraform resource set, instance size, region, or network layout, so those decisions must come from the project requirements.

Use a remote backend for shared automation rather than treating a developer’s local Terraform state as the team’s deployment record. HashiCorp’s S3 backend supports native state locking through use_lockfile; AWS guidance says this is available from Terraform 1.10.0. HashiCorp recommends enabling S3 bucket versioning to aid recovery, and its backend documentation marks DynamoDB-based locking as deprecated.

terraform {
  backend "s3" {
    bucket       = "<state-bucket>"
    key          = "<state-object-key>"
    region       = "<aws-region>"
    use_lockfile = true
  }
}

This is a shape example, not a ready-to-apply backend: replace the placeholders with your state bucket, key, and AWS region, and confirm your Terraform version supports native locking. Restrict access to the state bucket because state can contain sensitive values. Do not put AWS credentials in backend configuration; HashiCorp warns that credentials passed there can be saved in the .terraform directory and plan files. Configure credentials through the mechanism appropriate to the machine or workflow running Terraform.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Restrict access to the EC2 host

Make security group rules match the traffic the application needs, and avoid broad inbound access. AWS EC2 security guidance recommends minimum-required rules. For administrative access, AWS Systems Manager Session Manager can avoid opening inbound SSH and managing an SSH key pair. If your chosen design uses SSH instead, protect the private key and never commit it to the repository; AWS notes that anyone with the private key can connect to instances associated with it.

Keep the AWS identity path clear. When Terraform runs directly on EC2, AWS recommends an attached IAM role through an instance profile so the instance can obtain temporary credentials instead of relying on hardcoded long-lived keys. A GitHub-hosted workflow uses a separate federation path, described below; do not confuse the EC2 role with the workflow’s AWS role.

Let GitHub Actions access AWS with OIDC

GitHub Actions can exchange a GitHub-issued OpenID Connect token for AWS credentials, avoiding long-lived AWS access keys stored as GitHub secrets. The workflow needs id-token: write at workflow or job scope to request that token. That permission does not itself authorize AWS changes: the AWS IAM role still needs suitable permissions, and its trust policy must constrain which repository, branch, or environment may assume it.

GitHub’s OIDC subject format has a date-sensitive qualification: it is changing for repositories created after July 15, 2026, and for repositories that opt into immutable subject claims. As of October 2026, check the actual repository’s subject claim before copying an older trust-policy condition. If the workflow uses a GitHub environment, the subject refers to that environment; configure environment protection rules, including which branches or tags may deploy, as appropriate.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make the workflow steps match the real release path

Document what your pipeline actually does, in order. A common sequence to consider is:

  1. Check out the application source and run the project’s checks.
  2. Build the container images required by the chosen service topology.
  3. Push images to a registry if that is how the EC2 host obtains releases.
  4. Connect to or otherwise trigger the deployment mechanism used by the project.
  5. Recreate the changed service and verify the application through its real health checks.

This list is a planning sequence, not a verified workflow file. The official guidance cited here does not establish a particular registry, remote-deployment mechanism, action version, application test command, or complete MERN pipeline. Include only steps you have configured and confirmed for your repository.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Redeploy changed code correctly

A container restart by itself may continue using the old image. Docker’s production guidance says to rebuild the changed service’s image and recreate its container. Its example for a service named web is:

docker compose build web
docker compose up --no-deps -d web

Replace web with the Compose service name in your project. The --no-deps option avoids recreating dependencies in that example; decide whether it is appropriate for your service graph and release. Test the full update path, including how you detect an unsuccessful deployment and restore a known-good version, before treating it as a dependable release process.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Validate the design before calling it production-ready

  • Confirm the actual React, API, and MongoDB placement, service names, ports, and persistent-data location.
  • Review Compose production settings for development mounts, unnecessary host bindings, restart behavior, and secrets.
  • Check Terraform’s region and network assumptions, remote state access, S3 versioning, and locking support.
  • Review security group ingress and choose an administrative access method deliberately.
  • Verify that GitHub’s OIDC subject matches the IAM trust policy and that the role is limited to the intended deployment.
  • Run a deployment that rebuilds and recreates the changed service, then confirm that the application and its dependencies work as expected.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.