Serving images not working

Hello,

I am trying to serve pictures using caddy with no success.
Let me share with you my setup/ stack:

  • Frontend : React
  • Backend : Node/Express
  • Hosted on a Hetzner Server
  • Webserver : Caddy
  • Backend and Frontend are both running in separate containers
    (Caddy is one of those containers serving the static frontend after it has been built)

This is my docker-compose.yml file:

services:

  frontend:
    build: ./frontend
    ports: 
      - "5002:5002"
      - "443:443"
      - "80:80"

    # Retrieving the profile pictures from the server
    volumes:
      - "/srv/personioClone/profilePictures:/srv/personioClone/profilePictures"

  backend:
    build: ./backend
    ports:
      - "5001:5001"

    # Saving the pictures on the server
    volumes:
       - "/srv/personioClone/profilePictures:/usr/src/app/profilePictures"

volumes:
  profilePictures:

And this is my caddy configuration:

www.pilexlaflex.com {
    # Set this path to your site's directory.
    root * /var/www/html/build

     handle_path /profilePicture/* {
      root * /srv/personioclone/profilePictures
      header Content-Type image/jpeg
      file_server
    }

    # Fall back
    try_files {path} /index.html

    # Enable the static file server.
    file_server
}

www.pilexlaflex.com:5002 {
    reverse_proxy backend:5001
}

Based on my setup and my caddy config, I am supposed to serve a pictures if I write this URL:
https://www.pilexlaflex.com/profilePicture/JoeRahme.jpg

However this is not working.

The only pictures that caddy is serving are the images located here:
https://www.pilexlaflex.com/static/media/image.png

Can anyone explain to me why this is happening?

Thank you

type or paste code here

Please fill out the help topic template as per the forum rules.

I don’t see exactly how you’re running Caddy (unless Caddy is your frontend container?) Please show how you’re running Caddy, show your Caddy logs, show your Caddy version, etc.

Please use backticks ` or brackets <> around links in your post otherwise the forum transforms them into a link using the page’s title.

1 Like

Hi @francislavoie ,

Thank you for your quick reply.
I have edited my previous message and added the backticks so you can see the actual url of the images I was trying to serve.
Regarding the rest of your questions:
Yes. The frontend container is actually Caddy serving the (static) frontend.
Here is the Dockerfile:

FROM caddy:latest
COPY Caddyfile /etc/caddy/Caddyfile
WORKDIR /var/www/html/build
COPY build/ /var/www/html/build/
EXPOSE 80
EXPOSE 443
EXPOSE 5002
CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile"]

As you can, see I am using the latest image of Caddy.
Finally regarding logs, the only way I know to see Caddy logs is by doing :
docker logs your_container_name
Now because of this issue : Too many certificates created - #2 by Mohammed90
I am now unable to create the Caddy container anymore ( maybe because the limit of SSL certificate has been reached) and cannot see the logs.

Maybe you can guide me and explain to me how to do it?

Thanks a lot :slight_smile:

You need to persist the /data volume as per our docs, otherwise you’re throwing away your certs every time you recreate the Docker stack. See Keep Caddy Running — Caddy Documentation for our recommended setup.

You probably need this to be inside a handle block, because try_files has a higher directive order than handle_path so it gets sorted to run before it. That means that the path gets rewritten to /index.html for the images before it can get handled.

1 Like

Very interesting.

I just checked the documentation you shared and compared it with the way I am creating my docker compose and my docker file.

Question 1:

It seems that a Dockerfile is not needed? Do I simply create a docker-compose without a Dockerfile?

Please check the revised docker compose file and let me know if this is now correct:

services:

  caddy:
    image: caddy:builder-alpine
    restart : unless-start
    ports: 
      - "5002:5002"
      - "443:443"
      - "80:80"

    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./site:/srv
      - caddy_data:/srv/personioClone/profilePictures

  backend:
    build: ./backend
    ports:
      - "5001:5001"

    # Saving the pictures on the server
    volumes:
       - "/srv/personioClone/profilePictures:/usr/src/app/profilePictures"

volumes:
  profilePictures:

Question 2:

Is it a best practice to have caddy in a container and serve the (static) frontend after it has been built?
What I have currently is a Backend service ( running in a container) and I was not sure if I had to put the frontend in a container or Caddy.
But after discussing with some people, I concluded that Caddy is a process and the frontend is not ( after being compiled). Therefore It made sense to me to have Caddy in a container.
Was I right?

Question 3:

Is my Caddy configuration now correct?

www.pilexlaflex.com {
    # Set this path to your site's directory.
    root * /var/www/html/build

    # Handle specific path for profile pictures
    handle_path /profilePicture/* {
        root * /srv/personioclone/profilePictures
        header Content-Type image/jpeg
        file_server
    }

    # Handle the main site
    handle {
        try_files {path} /index.html
        file_server
    }
}

www.pilexlaflex.com:5002 {
    reverse_proxy backend:5001
}

Question 4:

Are you French? :slight_smile:

Thanks again for your help

Yeah you could. You can just mount any files or config you need. A Dockerfile is probably only needed if you need to make a custom build of Caddy.

You’re still missing a /data volume, this is absolutely necessary to ensure you don’t lose your TLS certs when you recreate the container.

You probably don’t need the port 5002 mapping. Why not just use a different subdomain for that instead, like api.pilexlaflex.com or something? Or even you could serve it under a subpath like handle /api*, that way you don’t need a separate port.

Either way is valid. You could ship a container with the static frontend already built inside it, or you could just mount the frontend with a volume. Just depends what works best for you.

Caddy just needs access to the files to serve them, obviously. How you get those to Caddy doesn’t matter as much.

Correct, your frontend is just files served from disk. You could run Caddy on the host (not inside Docker) if you wanted to, but running it in Docker is also perfectly valid.

Seems fine. Does it work?

You probably don’t need the header Content-Type line, unless your files don’t use .jpg extensions. The file_server will set the content type correctly based on the file extensions, automatically (using the mailcap package preinstalled in the container, which installs the mime types files).

French Canadian, but not from Quebec :sweat_smile: but I work in English.

1 Like

@francislavoie thank you for your help.
Everything is working now.
The main problem was the way I was using volumes .
I also followed your recommendation regarding the Caddyfile configuration.
The issue I encoutered regarding the volume syntax (Volumes | Docker Docs)
was that I felt that it was supposed to be as follows:

- path on the container : path on the server

If you look at the documentation on docker :

services:
  frontend:
    image: node:lts
    volumes:
      - myapp:/home/node/app
volumes:
  myapp:

/home/node/app seems to be like the server path.

But this is not the case.

For my docker compose to work as expected I needed to do :

- path on the server : path on the container

However I did not see this written black on white in the docker docs.

Anyways, my problem is solved and I manage to serve the profile pictures of my users whenever they login :slight_smile:

French Canadian, but not from Quebec :sweat_smile: but I work in English.

Working in french would be such a pain with the punctuation :slight_smile:
English is the best to work, I agree.

Thank you again, you were of great help.

1 Like

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