Can't deploy successfully with Fly.io and PlanetScale

I’m deploying a Rails API server on Fly.io with a database hosted on PlanetScale. After running “fly deploy,” the deployment succeeds, but the server enters a suspended state. The logs indicate a potential issue related to ActiveRecord and SSL:

nrt [info] ActiveRecord::ConnectionNotEstablished (TLS/SSL error: No such file or directory (2)):

Accessing the application yields this error:

To allow requests to these hosts, make sure they are valid hostnames (containing only numbers, letters, dashes and dots), then add the following to your environment configuration:
    config.hosts << "<app-name>.fly.dev"
  

I’ve configured SSL for PlanetScale and set the allowed hosts in production.rb. I’m seeking insights on resolving the ActiveRecord SSL connection issue.

Relevant configurations:

  • production.rb: includes config.hosts << "<app-name>.fly.dev"
  • Dockerfile: includes installation of openssl and ca-certificates
  • database.yml: configures ssl_mode and sslca for production

Any advice on troubleshooting this would be greatly appreciated.

  • config/environments/production.rb
Rails.application.configure do
  config.hosts << "<app-name>.fly.dev"
end
  • Dockerfile
FROM ruby:3.2.2

ENV APP_ROOT /app

RUN apt-get update -qq && apt-get install -y build-essential default-mysql-client vim openssl ca-certificates

WORKDIR ${APP_ROOT}

COPY Gemfile Gemfile.lock ${APP_ROOT}

RUN bundle install

COPY . ${APP_ROOT}

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

EXPOSE 3000

CMD ["rails", "server", "-b", "0.0.0.0"]
  • database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  port: 3306
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default
  username: <%= Rails.application.credentials.planetscale&.fetch(:username) %>
  password: <%= Rails.application.credentials.planetscale&.fetch(:password) %>
  database: <%= Rails.application.credentials.planetscale&.fetch(:database) %>
  host: <%= Rails.application.credentials.planetscale&.fetch(:host) %>
  ssl_mode: verify_identity
  sslca: "/etc/ssl/cert.pem"

production:
  <<: *default
  username: <%= ENV["PLANETSCALE_USERNAME"] %>
  password: <%= ENV["PLANETSCALE_PASSWORD"] %>
  database: <%= ENV["PLANETSCALE_DATABASE"] %>
  host: <%= ENV["PLANETSCALE_HOST"] %>
  ssl_mode: verify_identity
  sslca: "/etc/ssl/certs/ca-certificates.crt"

Rails defaults to development mode unless RAILS_ENV=production is set. Installing ca-certificates creates /etc/ssl/certs/ca-certificates.crt not /etc/ssl/cert.pem.

If you want to switch to production mode (highly recommended), you are going to need quite a few changes to your Dockerfile. Running bin/rails generate dockerfile will produce a much better starting point, and one that will produce a significantly smaller image size. I suspect that you will also need to update your database.yml to extract credentials.

If you wisth to remain in development mode you need to adjust the sslca line in the development section, but after doing so you may not be able to run the result on your development machine.

Thank you for your support.

I have merged a Dockerfile generated by running bin/rails generate dockerfile with my existing one. Here’s the integrated Dockerfile:

  • Dockerfile
# syntax = docker/dockerfile:1
ARG RUBY_VERSION=3.2.2
FROM ruby:$RUBY_VERSION-slim as base

LABEL fly_launch_runtime="rails"

WORKDIR /app

ENV BUNDLE_DEPLOYMENT="1" \
    BUNDLE_PATH="/usr/local/bundle" \
    BUNDLE_WITHOUT="development:test" \
    RAILS_ENV="production" \
    TZ=Asia/Tokyo

RUN gem update --system --no-document && \
    gem install -N bundler

FROM base as build
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y build-essential default-libmysqlclient-dev nodejs npm vim openssl ca-certificates

COPY --link Gemfile Gemfile.lock ./
RUN bundle install && \
    bundle exec bootsnap precompile --gemfile && \
    rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git

COPY --link . .

RUN bundle exec bootsnap precompile app/ lib/

FROM base

RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y curl default-mysql-client && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --from=build /app /app

RUN groupadd --system --gid 1000 rails && \
    useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
    chown -R 1000:1000 db log storage tmp
USER 1000:1000

ENTRYPOINT ["/app/bin/docker-entrypoint"]

EXPOSE 3000

CMD ["rails", "server", "-b", "0.0.0.0"]

The deployment succeeded, but the server keeps going into a suspended state. Here are the error logs I received:

nrt [error] instance refused connection. is your app listening on 0.0.0.0:3000? make sure it is not only listening on 127.0.0.1 (hint: look at your startup logs, servers often print the address they are listening on)
nrt [error] failed to change machine state: machine still active, refusing to start

When I start the Docker container in my local environment, I get the following log, which suggests that the port configuration is correct:

* Listening on http://0.0.0.0:3000

Could you please advise on what might be causing this issue?

Without seeing your logs, I would only be guessing. But knowing that the Dockerfile works locally, most common problems would be: not enough memory or database setup problems. Two links:

Thank you for reaching out for further assistance.

I’ve noticed an important log even though it wasn’t categorized as an error.

nrt [info] /app/bin/docker-entrypoint: line 11: exec: rails: not found

After adding ENV PATH=/app/bin:$PATH to my Dockerfile, the initial errors seem to have been resolved.

However, I’m still facing a challenge.
I got error messages like this many times.

nrt [info] E, [2024-01-26T17:23:51.949453 #305] ERROR -- : [ActionDispatch::HostAuthorization::DefaultResponseApp] Blocked hosts: 172.19.8.74:3000

I’ve already added the following configuration to production.rb :

Rails.application.configure do
  config.hosts << "<app-name>.fly.dev"
end

Is there any other configuration needed in production.rb to address this issue?

The way that config.hosts works is not intuitive. If you remove that, things will work. See:

As you said, after removing config.hosts, I was able to successfully deploy on Fly.io.
I truly appreciate your assistance.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.