Deploy phoenix app to AWS Lightsail

I’m trying to deploy a Phoenix app to AWS Lightsail using containers. My Dockerfile was generated by Phoenix, and the app starts running, receives requests, and responds with a 200 status. However, Lightsail shows the message ‘Took too long.’

[18/out./2024:13:15:04] [deployment:9] Creating your deployment
[18/out./2024:13:15:23] [deployment:9] Started 1 new node
[18/out./2024:13:16:16] 13:16:16.980 [warning] setting ssl: true on your database connection offers only limited protection, as the server's certificate is not verified. Set "ssl: [cacertfile: path/to/file]" instead
[18/out./2024:13:16:16] 13:16:16.980 [warning] setting ssl: true on your database connection offers only limited protection, as the server's certificate is not verified. Set "ssl: [cacertfile: path/to/file]" instead
[18/out./2024:13:16:18] 13:16:18.201 [info] Migrations already up
[18/out./2024:13:17:14] 13:17:14.190 [warning] setting ssl: true on your database connection offers only limited protection, as the server's certificate is not verified. Set "ssl: [cacertfile: path/to/file]" instead
[18/out./2024:13:17:14] 13:17:14.190 [warning] setting ssl: true on your database connection offers only limited protection, as the server's certificate is not verified. Set "ssl: [cacertfile: path/to/file]" instead
[18/out./2024:13:17:14] 13:17:14.190 [warning] setting ssl: true on your database connection offers only limited protection, as the server's certificate is not verified. Set "ssl: [cacertfile: path/to/file]" instead
[18/out./2024:13:17:14] 13:17:14.191 [warning] setting ssl: true on your database connection offers only limited protection, as the server's certificate is not verified. Set "ssl: [cacertfile: path/to/file]" instead
[18/out./2024:13:17:14] 13:17:14.191 [warning] setting ssl: true on your database connection offers only limited protection, as the server's certificate is not verified. Set "ssl: [cacertfile: path/to/file]" instead
[18/out./2024:13:17:14] 13:17:14.192 [warning] setting ssl: true on your database connection offers only limited protection, as the server's certificate is not verified. Set "ssl: [cacertfile: path/to/file]" instead
[18/out./2024:13:17:14] 13:17:14.192 [warning] setting ssl: true on your database connection offers only limited protection, as the server's certificate is not verified. Set "ssl: [cacertfile: path/to/file]" instead
[18/out./2024:13:17:14] 13:17:14.192 [warning] setting ssl: true on your database connection offers only limited protection, as the server's certificate is not verified. Set "ssl: [cacertfile: path/to/file]" instead
[18/out./2024:13:17:14] 13:17:14.192 [warning] setting ssl: true on your database connection offers only limited protection, as the server's certificate is not verified. Set "ssl: [cacertfile: path/to/file]" instead
[18/out./2024:13:17:14] 13:17:14.191 [warning] setting ssl: true on your database connection offers only limited protection, as the server's certificate is not verified. Set "ssl: [cacertfile: path/to/file]" instead
[18/out./2024:13:17:14] 13:17:14.291 [info] Running JoinsApiWeb.Endpoint with Bandit 1.5.7 at :::4000 (http)
[18/out./2024:13:17:14] 13:17:14.396 [info] Access JoinsApiWeb.Endpoint at https://joins-api.ke5s51qty1nj0.us-east-1.cs.amazonlightsail.com
[18/out./2024:13:19:52] [deployment:9] Took too long
[18/out./2024:13:21:03] 13:21:03.285 request_id=F_-Orsk-SIzkJWcAAA_y [info] GET /api/health
[18/out./2024:13:21:03] 13:21:03.285 request_id=F_-Orsk-SIzkJWcAAA_y [debug] Processing with JoinsApiWeb.HealthCheckController.index/2
[18/out./2024:13:21:03] Parameters: %{}
[18/out./2024:13:21:03] Pipelines: [:api]
[18/out./2024:13:21:03] 13:21:03.285 request_id=F_-Orsk-SIzkJWcAAA_y [info] Sent 200 in 596µs
[18/out./2024:13:21:03] 13:21:03.321 request_id=F_-OrsthsaxgyOkAABAC [info] GET /api/health
[18/out./2024:13:21:03] 13:21:03.321 request_id=F_-OrsthsaxgyOkAABAC [debug] Processing with JoinsApiWeb.HealthCheckController.index/2
[18/out./2024:13:21:03] Parameters: %{}
[18/out./2024:13:21:03] Pipelines: [:api]
[18/out./2024:13:21:03] 13:21:03.321 request_id=F_-OrsthsaxgyOkAABAC [info] Sent 200 in 305µs
[18/out./2024:13:21:03] 13:21:03.323 request_id=F_-OrsuLE4WhwgsAABAS [info] GET /api/health
[18/out./2024:13:21:03] 13:21:03.324 request_id=F_-OrsuLE4WhwgsAABAS [debug] Processing with JoinsApiWeb.HealthCheckController.index/2
[18/out./2024:13:21:03] Parameters: %{}
[18/out./2024:13:21:03] Pipelines: [:api]
[18/out./2024:13:21:03] 13:21:03.324 request_id=F_-OrsuLE4WhwgsAABAS [info] Sent 200 in 241µs
[18/out./2024:13:21:03] 13:21:03.332 request_id=F_-OrswHLhHxsMgAABAi [info] GET /api/health
[18/out./2024:13:21:03] 13:21:03.332 request_id=F_-OrswHLhHxsMgAABAi [debug] Processing with JoinsApiWeb.HealthCheckController.index/2
[18/out./2024:13:21:03] Parameters: %{}
[18/out./2024:13:21:03] Pipelines: [:api]
[18/out./2024:13:21:03] 13:21:03.332 request_id=F_-OrswHLhHxsMgAABAi [info] Sent 200 in 557µs
[18/out./2024:13:21:03] 13:21:03.349 request_id=F_-Ors0Pdt_eBhgAABAy [info] GET /api/health
[18/out./2024:13:21:03] 13:21:03.349 request_id=F_-Ors0Pdt_eBhgAABAy [debug] Processing with JoinsApiWeb.HealthCheckController.index/2
[18/out./2024:13:21:03] Parameters: %{}
[18/out./2024:13:21:03] Pipelines: [:api]
[18/out./2024:13:21:03] 13:21:03.349 request_id=F_-Ors0Pdt_eBhgAABAy [info] Sent 200 in 282µs
[18/out./2024:13:21:03] 13:21:03.385 request_id=F_-Ors8vAyQfWyUAABBC [info] GET /api/health
[18/out./2024:13:21:03] 13:21:03.385 request_id=F_-Ors8vAyQfWyUAABBC [debug] Processing with JoinsApiWeb.HealthCheckController.index/2
[18/out./2024:13:21:03] Parameters: %{}
[18/out./2024:13:21:03] Pipelines: [:api]
[18/out./2024:13:21:03] 13:21:03.385 request_id=F_-Ors8vAyQfWyUAABBC [info] Sent 200 in 244µs

prod.exs

config :joins_api, JoinsApiWeb.Endpoint,
  # force_ssl: [rewrite_on: [:x_forwarded_proto]],
  cache_static_manifest: "priv/static/cache_manifest.json"

runtime.exs

config :joins_api, JoinsApi.Repo,
    ssl: true,
    ssl_opts: [verify: :verify_none],
    url: database_url,
    pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
    socket_options: maybe_ipv6,
    queue_target: 5000,
    queue_interval: 5000

host = System.get_env("PHX_HOST") || "example.com"
port = String.to_integer(System.get_env("PORT") || "4000")

config :joins_api, JoinsApiWeb.Endpoint,
    url: [host: host, port: 443, scheme: "https"],
    http: [
      # Enable IPv6 and bind on all interfaces.
      # Set it to  {0, 0, 0, 0, 0, 0, 0, 1} for local network only access.
      # See the documentation on https://hexdocs.pm/bandit/Bandit.html#t:options/0
      # for details about using IPv6 vs IPv4 and loopback vs public addresses.
      ip: {0, 0, 0, 0, 0, 0, 0, 0},
      port: port
    ],
    secret_key_base: secret_key_base

My deployment:

--public-endpoint '{"containerName":"${{ env.AWS_LIGHTSAIL_SERVICE_NAME }}","containerPort": 4000,"healthCheck":{"path":"/api/health","intervalSeconds": 300,"timeoutSeconds": 120,"healthyThreshold": 2,"unhealthyThreshold": 10}}' \
          --containers '{
            "${{ env.AWS_LIGHTSAIL_SERVICE_NAME}}": {
              "image": "${{ steps.upload_image.outputs.image_name }}",
              "environment": {
                "PHX_HOST": "${{ secrets.PHX_HOST }}",
                "DATABASE_URL": "${{ secrets.DATABASE_URL }}",
                "SECRET_KEY_BASE": "${{ secrets.SECRET_KEY_BASE }}",
                "AWS_ACCESS_KEY_ID": "${{ secrets.AWS_ACCESS_KEY_ID }}",
                "AWS_SECRET_ACCESS_KEY": "${{ secrets.AWS_SECRET_ACCESS_KEY }}",
                "AWS_REGION": "${{ secrets.AWS_REGION }}",
                "TOKEN_SIGNING_SECRET": "${{ secrets.TOKEN_SIGNING_SECRET }}",
                "PHX_SERVER": "true"
              },
              "ports": {
                "4000": "HTTP"
              }
            }
          }'

I also added EXPOSE 4000 to the Dockerfile.

Has anyone else experienced the same issue?