Skip to content

Instantly share code, notes, and snippets.

@JamesCullum
Last active March 28, 2024 04:30
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JamesCullum/6604e504318dd326a507108f59ca7dcd to your computer and use it in GitHub Desktop.
Save JamesCullum/6604e504318dd326a507108f59ca7dcd to your computer and use it in GitHub Desktop.
docker-compose.yml for immich with WAF, DDoS protection, image resizing and without port forwarding

Setup Immich via Docker Compose with WAF, CDN, DDoS protection, no port forwarding and automated image resizing

In this guide, we are using the docker compose setup that is recommended by the Immich team. Once everything is configured and running in your local network, we can expand on it.

The first recommended step is to use Cloudflare Tunnel to make your local instance globally available. This is free and you benefit from the native DDoS protection, WAF and CDN from Cloudflare. The cloudflared daemon basically makes an outgoing connection to Cloudflare and makes the designed interfaces available on the internet, without granting access to undesired parts of the network.

Start off by creating a Cloudflare account, going into the "Zero Trust" portion of the account and add a new tunnel. Give it a name and choose a domain that you want your instance to be available on. You can use the "Access" components (SSO/VPN) to lock down the access, if you want. Once you have to choose a local agent, select "Docker" and copy the token from the instructions. Add the following command into your docker-compose.yml and add your valid tunnel token.

  cloudflared:
    container_name: cloudflared
    image: cloudflare/cloudflared:latest
    depends_on:
      - immich-server
    restart: always
    command: 'tunnel --no-autoupdate run --token YOUR-TOKEN'

Use docker compose to start this container, the UI should show your node being online now. Now switch to "Public hostname" , add the desires subdomain for your immich instance, leave path empty and for the service you configure HTTP with immich_proxy:8080 as destination. Once saved, your cloudflared daemon will automatically update and your immich is now available on the internet.

If you would like your pictures to be automatically resized - a feature which the Immich maintainers have declined - you can add the following code to your docker-compose.yml. Feel free to change the dimensions you are looking for.

  upload-proxy:
    container_name: upload_proxy
    image: ghcr.io/jamescullum/multipart-upload-proxy:main
    environment:
      - IMG_MAX_WIDTH=1920
      - IMG_MAX_HEIGHT=1080
      - FORWARD_DESTINATION=http://immich-server:3001/api/asset/upload
      - FILE_UPLOAD_FIELD=assetData
      - LISTEN_PATH=/api/asset/upload
    restart: always

You need to route uploads to this container now, which is easy to do via Cloudflare tunnel. Create a new public hostname, use api/asset/upload as path and direct it via HTTP to upload_proxy:6743. Submit and move this public hostname above the previous one.

Screenshot immich with cloudflare tunnel

Now all file uploads will be proxied and images automatically resized before being uploaded to Immich.

@Stiggler
Copy link

Hi @JamesCullum ,

thanks for this. Relly helped and it is working great.
I have one question though.
How would I update, as soon as there is a new version for immich available?

If I use this guide, will the cloudflare container still be in there?
https://immich.app/docs/install/docker-compose#step-4---upgrading

Many thanks!
Steffen

@JamesCullum
Copy link
Author

Hey @Stiggler you use the same commands as you linked - the configuration decides what containers are used. So no change there.

@Stiggler
Copy link

Great!!
Many many thanks!

@aviv926
Copy link

aviv926 commented Oct 22, 2023

Can confirm it still works? I didn't see that these variables exist ( - IMG_MAX_WIDTH= - IMG_MAX_HEIGHT=)
https://immich.app/docs/install/environment-variables

@JamesCullum
Copy link
Author

Yes, the variable is for the modification, not the original container - hence you won't see it in the official docs

@aviv926
Copy link

aviv926 commented Oct 23, 2023

Yes, the variable is for the modification, not the original container - hence you won't see it in the official docs

The options of - IMG_MAX_WIDTH= - and IMG_MAX_HEIGHT= are options that exist in general in yml?
Sorry for the question, but I'm new to this whole thing, and I want to set up immich the best way I can before switching to it from Google Images
Could you please explain where the options of - IMG_MAX_WIDTH= - and IMG_MAX_HEIGHT= come from?

In addition, is it possible to set that the images in the original quality will be kept for 30 days and then be converted?
Where you can see all the options that exist in terms of variables

Thank you so much!!

@JamesCullum
Copy link
Author

The config sets environment variables, which can be used by any tool with any name for any purpose. In my case, the compression proxy I wrote utilizes them so that you can change the settings to your liking. I would recommend starting to read up on Docker and the docker-compose.yml file - unless you are a developer it will however be difficult to fully get the grasp.

As this is a proxy that compresses images on upload, you cannot execute any action 30 days later. For this, you would need to interact with Immich later - certainly possible, but a lot more work, and given the stance of the Immich developers about compression, you might waste a lot of time keeping your code up-to-date.

@aviv926
Copy link

aviv926 commented Oct 31, 2023

The config sets environment variables, which can be used by any tool with any name for any purpose. In my case, the compression proxy I wrote utilizes them so that you can change the settings to your liking. I would recommend starting to read up on Docker and the docker-compose.yml file - unless you are a developer it will however be difficult to fully get the grasp.

As this is a proxy that compresses images on upload, you cannot execute any action 30 days later. For this, you would need to interact with Immich later - certainly possible, but a lot more work, and given the stance of the Immich developers about compression, you might waste a lot of time keeping your code up-to-date.

Thank you for the information!
Is it possible to set it to be only for a specific user in Immich?
In addition, if you can send me sources that I can read about it, I will be happy to research and learn
I prefer to read from sources you used in writing this file

Thanks for your help and work!

@athornfam2
Copy link

Hi @JamesCullum Thanks for bringing this onto the Immich platform especially with it being turned down from the maintainers. Do you have anything in the works to compress images?

@JamesCullum
Copy link
Author

Hey @athornfam2 can you clarify what you mean? This tutorial compresses images on upload. Do you also mean compressing them at a later point? My use case is satisfied with my simple modification, but maybe someone else is willing to go through all necessary modifications for that to work.

@Stiggler
Copy link

Stiggler commented Nov 21, 2023

Hi @JamesCullum ,
this has been working for me very well.
Since there were the changes in the immich version 1.88, when they removed the proxy and web containers I tried to update the file myself.
Immich is working, but I can't access it via cloudflare tunnel.

What I did in the file I changed:
cloudflared: container_name: cloudflared image: cloudflare/cloudflared:latest depends_on: - immich-proxy

to

cloudflared: container_name: cloudflared image: cloudflare/cloudflared:latest depends_on: - immich-server

Is that correct?
And in the cloudflare tunnel config, do I need to change http://upload_proxy:6743 and http://upload_proxy:8080 to sth. else?

Couldn't figure it out myself.

Your help is much appreciated!
Best
Stigg

EDIT: Found it. Logically I used the port from the server (immich_server:3001), instead of http://upload_proxy:8080.
Didn't find anything regarding upload proxy, but uploads seem to be working

@JamesCullum
Copy link
Author

JamesCullum commented Nov 21, 2023

Hey @Stiggler thank you for letting me know that 1.88.0 dropped. It is indeed necessary to update the Cloudflare tunnel configuration and the dependency in the compose file. I've updated the guide above to represent this - it's working fine for me like this.

@Stiggler
Copy link

Hey @Stiggler thank you for letting me know that 1.88.0 dropped. It is indeed necessary to update the Cloudflare tunnel configuration and the dependency in the compose file. I've updated the guide above to represent this - it's working fine for me like this.

Perfect, many many thanks!

@telgareith
Copy link

This needs to be updated to use cloudflared's TUNNEL_TOKEN environment variable. Currently, you're exposing the token to anyone/thing that can list processes.

Also, more compose file updates for the newest version.

@JamesCullum
Copy link
Author

@telgareith I'm not sure if I understand the threat scenario you mean - any user with access to Docker on the same instance will have access to any secrets in a container, no matter how it's managed. It's not a good idea to share a Docker server with people you don't trust.

Yes, docker compose file was updated again. There was no change needed here, but I noticed that I didn't update one part of the documentation last time and fixed it now (FORWARD_DESTINATION was missing the /api part)

@telgareith
Copy link

telgareith commented Dec 17, 2023

it's not even a "threat scenario" - It's about doing things correctly, and not teaching people bad habits. You use Environment Variables in your own container...

Just need to change cloudflared to:

  cloudflared:
    container_name: cloudflared
    image: cloudflare/cloudflared:latest
    depends_on:
      - immich-server
    environment:
      - TUNNEL_TOKEN = YOUR-TOKEN
    restart: always
    command: 'tunnel --no-autoupdate run'

And I said "anyone/thing that can list processes," for a reason: non admin users and logging. OOM kill, container start, container stop, process fault, too many to name... All result in TUNNEL_TOKEN in the logs.

Finally: Storing compose files somewhere every user on the machine can access them is bad practice.

@Ranger-NF
Copy link

Ranger-NF commented Dec 19, 2023

Just a quick question, how could I automatically resize the pictures I upload over mobile app without using cloudflare tunnel? (ie, connecting over local network)
Does simply adding the following to docker-compose file make that work?

    upload-proxy:
    container_name: upload_proxy
    image: ghcr.io/jamescullum/multipart-upload-proxy:main
    environment:
      - IMG_MAX_WIDTH=1920
      - IMG_MAX_HEIGHT=1080
      - FORWARD_DESTINATION=http://immich-server:3001/api/asset/upload
      - FILE_UPLOAD_FIELD=assetData
      - LISTEN_PATH=/api/asset/upload
    restart: always

NB: I'm still in my early phase of using docker 😅

@JamesCullum
Copy link
Author

@telgareith Thank you for providing an alternative version for the Tunnel using an environment variable.

@Ranger-NF Sadly not. You need all requests to go to Immich with the exception of the file upload API, which should go to the resizing proxy. If you really don't want to use the Cloudflare tunnel (really try to give it a shot - it's free and has many great benefits), then you will need another container as reverse proxy in front of your application.

@Ranger-NF
Copy link

Ranger-NF commented Dec 22, 2023

@telgareith Thank you for providing an alternative version for the Tunnel using an environment variable.

@Ranger-NF Sadly not. You need all requests to go to Immich with the exception of the file upload API, which should go to the resizing proxy. If you really don't want to use the Cloudflare tunnel (really try to give it a shot - it's free and has many great benefits), then you will need another container as reverse proxy in front of your application.

I would love to use cloudflare tunnels, but I don't own any domain. So that option is out of the question...

Let me know if there are any solutions for this!

@JamesCullum
Copy link
Author

Hmm so you only want Immich available via home wifi and static IP? A DynDNS provider might help you out and solve two problems at once.

Cloudflare tunnel does not require a domain and will generate you a free one: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/trycloudflare/

@tehniemer
Copy link

The use of multipart in the image name gives me hope that this does chunked uploads to get around Cloudflare's 100mb limit, is that the case or am I suffering from wishful thinking?

@JamesCullum
Copy link
Author

JamesCullum commented Jan 21, 2024

Multipart is a subcomponent of the HTTP form protocol to allow file uploads - the proxy does not circumvent any limitations. I did not find the limitation you mentioned in tunnel documentation.

@tehniemer
Copy link

OK, thanks for the info, I'm using Traefik2 as my reverse proxy and Cloudflare as my DNS provider, and Cloudflare has the limitation.

@JamesCullum
Copy link
Author

JamesCullum commented Jan 23, 2024

Your DNS provider has nothing to do with filesize limits. Check your reverse proxy or client for that.

I didn't find such a limitation for the Cloudflare tunnel either, so it looks like your problem is somewhere else.

@tehniemer
Copy link

tehniemer commented Jan 23, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment