Hi all,
After following the LiveView guide for live file uploads, I am able to have users upload files. This works great in dev, but I’m questioning the best way to serve the uploads in production.
The uploads directory in the docs is priv/static/uploads
. To serve the files, I added the uploads
dir to the static paths for the Plug.Static
plug, which works great for dev.
However, when deploying on fly.io, I want to store the files on a volume. To do so, I created the volume and mounted it in /mnt/myvolume
. Now, I created some application config to read the location where it should put the uploaded files - priv/static/uploads
for :dev
and /mnt/myvolume/uploads
for :prod
.
This is where I get stuck - it would be best if this is configured in runtime.exs
, so I can change volumes, path, etc with just a environment variable change, and not a whole build via the fly deploy
pipeline. But the plug is configured at compile time in endpoint.ex
:
plug Plug.Static,
at: "/",
from: :my_app,
gzip: false,
only: ~w(assets fonts images favicon.ico robots.txt)
plug Plug.Static,
at: "/uploads",
from: Application.get_env(:my_app, :upload_path)
And config for the above:
dev.exs
config :my_app, :upload_path, "priv/static/uploads"
prod.exs
config :my_app, :upload_path, "/mnt/myvolume/uploads"
The approach above works in serving the files, but I don’t have runtime config control because the options are passed to the plug at runtime.
I tried some implementations from other threads in the forum of configuring plugs at runtime, such as this one: Session cookie domain option - #4 by nietaki
I couldn’t get it to work correctly, so asking for guidance here. Some alternatives I think I could see:
- mount the volume at the location of the
priv/static/uploads
directory, and just let it do it’s thing. I don’t like this because thepriv
directory could change locations. In the release, it is at_build/prod/rel/my_app/lib/my_app-0.1.0/priv
, which could change when I bump versions in mix.exs. - I could also symlink that above directory to the mount location? Again, I don’t like this because the path could change, and this would have to be in the build context of the docker image. And I don’t know if linux would be happy to symlink to a path that doesn’t exist before the volume is mounted?
- I can bite the bullet and get started with S3 uploads. I will do this eventually when I launch my app, but I’m really hoping to hold off with AWS for a little bit longer…
- ???
Thanks!