PJUllrich
Use Fly.io internal DNS for resolving Database_URL
I am trying to use fly.io to deploy a simple Phoenix + Ecto app, but have problems connecting Ecto to the provisioned Postgres instance.
I created a postgres instance with flyctl postgres create and attached it to the application with flyctl postgres attach --postgres-app my-app-postgres. This adds a DATABASE_URL environment variable to the application context, which I read out in my releases.exs. I checked and my application receives the correct DATABASE_URL. Unfortunately, Postgresx cannot connect to the database and fails with the error:
Postgrex.Protocol (#PID<0.2945.0>) failed to connect: ** (DBConnection.ConnectionError)
tcp connect (my-app-postgres.internal:5432): non-existing domain - :nxdomain
The problem seems to be Fly’s own DNS resolver, which should resolve the my-app-postgres.internal part in the DATABASE_URL to an IP address. I saw that the LiveView-Counter example project uses a custom DNS Strategy to resolve the APP_NAME.internal URLs. I wondered whether I can set a similar strategy for Ecto to use.
My assumption is that Ecto tries to resolve the my-app-postgres.internal URl with a public DNS instead of the Fly.io internal DNS, which is responsible for the .internal-URLs in the internal network of Fly.
My question is therefore: Do you know how I could configure Phoenix or Ecto to use the internal DNS for the .internal-URLs?
I saw a similar question, where the network_mode in the docker-compose.yml was used to let Phoenix discover other services through the host network, but with Fly.io, one can only use a Dockerfile and not a docker-compose.yml file to create the application. So, I wouldn’t know how to set the network_mode inside the Dockerfile.
Edit: I set the private_network=true flag in my fly.toml file, but it didn’t help:
app = "my-app"
kill_signal = "SIGINT"
kill_timeout = 5
[experimental]
private_network=true
[[services]]
internal_port = 4000
protocol = "tcp"
[services.concurrency]
hard_limit = 25
soft_limit = 20
[[services.ports]]
handlers = ["http"]
port = "80"
[[services.ports]]
handlers = ["tls", "http"]
port = "443"
[[services.tcp_checks]]
grace_period = "1s"
interval = "15s"
port = "4000"
restart_limit = 6
timeout = "2s"
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #performance










First 9 of 9 Posts
Exadra37
@mrkurt will be the right person to help you here.
mrkurt
Ecto doesn’t speak IPv6 by default in Phoenix. Will you try adding this to your Ecto repo config?
We need better docs for Elixir apps.
PJUllrich
Yes, that did the trick. Thank you very much!
mrkurt
No problem! I just submitted a PR to make this work magically with new Phoenix apps: Enable IPv6 for Ecto by mrkurt · Pull Request #4289 · phoenixframework/phoenix · GitHub
PJUllrich
I threw together a quick blog post about how to get started with Elixir and fly.io.
https://www.peterullrich.com/deploy-phoenix-with-flyio
@mrkurt if you want to use parts or the entire blog post for your docs, you have my permission to do so
Thanks again for your help!
mrkurt
Oh wow that’s amazing.
Exadra37
Instead you can delete
prod.secret.exs, delete also everything from theprod.exsfile but don’t delete it, and move everything inside such files toruntime.exs.This may cause issues when the target you are building for is using different Phoenix/Elixir/Erlang versions from the ones you have in your host, unless you remove some folders and the lock files:
To compile the release prefer instead:
This is not necessary at all:
Also, as a best security practice an app should run in its own unprivileged dedicate user in the system, therefore you shouldn’t use this:
I would recommend instead this Dockerfile:
PJUllrich
Ah thanks a lot for the feedback! Just a few quick comments:
Yes, you’re right about this. I didn’t want to change the generated application more than necessary to keep the blog post short, but I’d probably remove this as well.
I added those folders (and now also the
*-lock-files, thanks for that!) to the.dockerignore-file, which has the same effect, right?May I ask what is the advantage of putting all these steps into a single
RUN? Is it to prevent that these sub-steps are cached so that if e.g.mix releasefails, also the assets are re-compiled instead of cached?Thanks, I removed it.
Ah, that’s very good to know! I changed it in my Dockerfile, will evaluate it tomorrow, and change the blog post once I could check that it works. Thanks for that as well!
Exadra37
If you pay attention the commands I suggested have slight differences and they come directly from the Elixir docs. You can keep them separated, but you may want to adopt the official way of doing it.
For me the Dockerfile is to build a production release, therefore I prefer to not use cache at all, I even use the
--no-cacheflag on the command line.In development I use this Dockerfile: