How do I configure a Phoenix app to store and serve uploaded images via a Fly.io volume?

I’m trying to set up my Phoenix app to use a volume for file hosting, but right now, uploaded files don’t seem to be getting to the right place.

Locally in development, when I upload a file and then visit a link to it, it shows up just fine. I’m trying to save to and serve the files from a /priv/static/files directory. So I have this in fly.toml:

[mounts]
  source="volume_name"
  destination="/priv/static/files"

and this in endpoint.ex:

  plug(
    Plug.Static,
    at: "/",
    from: :app_name,
    gzip: true,
    only:
      ~w(assets fonts images files favicon.ico robots.txt)
  )

but the /priv/static directory on Fly seems to contain only files and not the assets, images and other directories I would expect that store the other front-end assets, so I’m guessing that that priv directory and the one that Phoenix serves its other assets from are in different places.

Where is Phoenix’s /priv/static directory, and is it possible to wire it up in the way I describe, with the volume linked to /priv/static/files? Or is there an alternative technique I should be trying instead?

The Dockerfile puts everything in /app. You should be able to mount your volume at /app/priv/static/files.

Also if you want to poke around at the filesystem, you can run fly ssh console to get a shell. :slight_smile:

I’ve been trying to poke around with fly ssh console, but the strange thing is I only see entry and app_name directories inside of the app folder, even though the app is clearly successfully serving the images that are checked into the repo at priv/static/images just fine. Even doing an ls **/* from the base directory, I don’t see priv anywhere except for the place where it’s linking to the volume.

Will try setting it to /app/priv/static/files and report back what I find, though; thanks!

This seems like it might be closer, but after making this change, I’m getting eacces errors when I try to write to /app/priv/static/files, as well as when I fired up an iex console and tried to write to /app/priv/static, thought writing a file to just /app/priv worked fine. I’m just using Elixir’s File.write function to in all these cases. Is there some permissions stuff I need to do somewhere to make those writes allowed?

Ah! I think I got a bit further thanks to this thread. I ran Application.app_dir() in production and it returned /app/app_name/lib/app_name-app.version.number and the priv directory at /app/app_name/lib/app_name-app.version.number/priv has the expected asset folders.

If I set the destination for the volume in fly.toml to /app/app_name/lib/app_name-app.version.number/priv/static/files, it shows up there as expected.

Trying to write to the volume still results in eacces errors, though. The Phoenix app does not seem to have permission to write to this directory.

@kurt AH! FOUND THIS AND GOT IT WORKING!

Thank you for your help! Now that I’ve got this figured out, I feel like it’ll be MUCH easier than dealing with DigitalOcean’s S3 API. Love being able to save uploads with normal file read/write commands instead of needing to setup and use a bunch of extra S3 libraries. This is a really nice feature.

I just ended up running chown on the volume via fly ssh console. Just to check, though: is there any reason that ownership assignment might get reassigned back to root on a future deploy, or should that permission setting be more or less permanent at this point? Just want to make sure there isn’t a risk of the permissions issue unexpectedly returning in the future.