Deploy Remix to AWS Lightsail with Docker

Deploy your Remix app to Amazon Lightsail Containers using Docker

  • Alexandro Martínez
    by Alexandro Martínez
    3 months ago
  • TLDR: Watch the video instead.

    Before getting started, make sure to meet the following requirements:

    1) Set up Docker-related files



    FROM --platform=linux/amd64 node:18-bookworm-slim as base

    ENV NODE_ENV production

    RUN apt-get update && apt-get install -y openssl

    FROM base as deps

    WORKDIR /myapp

    ADD package.json ./ RUN npm install --production=false --legacy-peer-deps

    FROM base as production-deps

    WORKDIR /myapp

    COPY --from=deps /myapp/node_modules /myapp/node_modules ADD package.json ./ RUN npm prune --production --legacy-peer-deps

    FROM base as build

    WORKDIR /myapp

    COPY --from=deps /myapp/node_modules /myapp/node_modules

    ADD prisma . RUN npx prisma generate

    ADD . . RUN npm run build

    FROM base

    ENV PORT="8080" ENV NODE_ENV="production"

    WORKDIR /myapp

    COPY --from=production-deps /myapp/node_modules /myapp/node_modules COPY --from=build /myapp/node_modules/.prisma /myapp/node_modules/.prisma

    COPY --from=build /myapp/build /myapp/build COPY --from=build /myapp/public /myapp/public COPY --from=build /myapp/package.json /myapp/package.json COPY --from=build /myapp/ /myapp/ COPY --from=build /myapp/prisma /myapp/prisma

    RUN chmod +x /myapp/

    CMD ["./"]

    If you're wondering why I'm using --legacy-peer-deps it's because React 19 hasn't released yet, and some libraries complain on version mismatch.


      "scripts": {
        "build": "remix vite:build",
        "start": "remix-serve ./build/index.js"
      "dependencies": {
      "devDependencies": {

    npm run start

    The #!/bin/sh line is to make the file compatible accross operating systems.



    2) Building the Image

    Ensure that your docker image can be built correctly:

    docker build -t saasrock-dev .

    After it's built, you should have the image displayed on Docker Desktop:


    Or use the docker command:

    docker images

    3) Testing the Container

    Run the docker image in a container:

    docker run -p 8080:8080 --env-file .env saasrock-dev:latest

    You should have the following output or similar:


    And make sure the application is running correctly at localhost:8080:


    Now we're ready to deploy to AWS Lightsail.

    4) Create an AWS Lightsail Container

    You can either create a container service from your terminal or from the Amazon Lightsail dashboard:

    aws lightsail create-container-service --region us-east-1 --service-name saasrock-dev-service --power nano --scale 1

    This is creating a Nano instance ($7/m):


    Check the status with the following command:

    aws lightsail get-container-services --region us-east-1 --service-name saasrock-dev-service --query "containerServices[].state"

    If it's still pending, you'll just get a PENDING status:


    I'd say wait around 3 minutes and check again. You can also check the container status at the Amazon Lightsail dashboard:


    5) Deploy the Container

    Run the following command to push your image:

    aws lightsail push-container-image --region us-east-1 --service-name saasrock-dev-service --label latest --image saasrock-dev:latest

    This pushes the image to the container service, but does not deploy it.

    Create a local configuration aws-lightsail-containers.json, and add it in your .gitignore as we're going to define the environment variables:

      "serviceName": "saasrock-dev-service",
      "containers": {
        "saasrock-dev-service": {
          "image": "saasrock-dev:latest",
          "environment": {
            "DATABASE_URL": "your_database_url_here",
          "ports": {
            "80": "HTTP"
      "publicEndpoint": {
        "containerName": "saasrock-dev-service",
        "containerPort": 80

    Make sure to update the service/container name, and your environment vars, and deploy it:

    aws lightsail create-container-service-deployment --region us-east-1 --cli-input-json file://aws-lightsail-containers.json

    If everthing worked, you should get a JSON output in the terminal.


    Check the deployment status with the following commands:

    aws lightsail get-container-services --region us-east-1  --query "containerServices[].nextDeployment.state"

    aws lightsail get-container-services --region us-east-1 --query "containerServices[].currentDeployment.state"

    You should get the following output:


    And once it's deployed, get the URL with the following command:

    aws lightsail get-container-services --region us-east-1 --query "containerServices[].url"

    That's it! Your app should be live!


    And if you check your Amazon Lightsail dashboard, you should see your container service:


    6) Deploy a new Version

    Build the image again:

    docker build -t saasrock-dev .

    and push the new image:

    aws lightsail push-container-image --region us-east-1 --service-name saasrock-dev-service --label latest --image saasrock-dev:latest

    You should get a new image name:

    Digest: sha256:71e4e122c1af0c8da686e35921ac1ccab452369145f8164094116d19ddac8c37
    Image "saasrock-dev:latest" registered.
    Refer to this image as ":saasrock-dev-service.latest.2" in deployments.

    Take that name (in my case :saasrock-dev-service.latest.2) and put it in the aws-lightsail-containers.json file:

      "containers": {
        "saasrock-dev-service": {
          "image": ":saasrock-dev-service.latest.2",

    And redeploy the image as a new container deployment:

    aws lightsail create-container-service-deployment --region us-east-1 --cli-input-json file://aws-lightsail-containers.json

    Known Issues

    🔴 Unable to start container process: exec: "./": permission denied: unknown

    Assign permissions, rebuild the image and run the container again.

    chmod +x
    docker build -t saasrock-dev .
    docker run -p 8080:8080 --rm --env-file .env saasrock-dev:latest

    Or, in your Dockerfile make sure to assign permissions:

    RUN chmod +x /myapp/
    ENTRYPOINT [ "./" ]

    🔴 if (!origin) throw Error("Dev server origin not set")

    Make sure that you're not setting NODE_ENV manually in your environment.

    🔴 PrismaClientInitializationError: the URL must start with the protocol...

    Make sure to remove double quotes in your DATABASE_URL variable:


    🔴 Can't reach database server at localhost...

    If you're running a local database like me (postgres), you can use host.docker.internal instead of localhost.


    🔴 exec /usr/local/bin/ exec format error

    This means that you built your image in an Apple Silicon machine (M1, M2, M3...), make sure to have the --platform flag in your Dockerfile:


    FROM --platform=linux/amd64 node:18-bookworm-slim as base

    Or when building the image (better explanation here):

    DOCKER_DEFAULT_PLATFORM=linux/amd64 docker build -t saasrock-dev .


    We respect your privacy.

    TLDR: We use cookies for language selection, theme, and analytics. Learn more.