CORS help for API requests

I'm trying to get the API to work from another webapp, but I keep getting CORS errors. In the immich-proxy container, I tried mapping an nginx.conf file to /etc/nginx/conf.d/default.conf to add the CORS setting, but I keep getting read/write errors in the container. What's the correct way to configure CORS? The webapp that's trying to access the API is a Quasar + Django app using Axios for the API call. docker-compose.yml (just the immich-proxy container) (running via Portainer on an Unraid server): immich-proxy: container_name: immich_proxy image: ghcr.io/immich-app/immich-proxy:${IMMICH_VERSION:-release} environment: - IMMICH_SERVER_URL - IMMICH_WEB_URL ports: - 2283:8080 depends_on: - immich-server - immich-web restart: always volumes: - /mnt/user/appdata/immich-app/nginx.conf:/etc/nginx/conf.d/default.conf:rw - immich-proxy-conf:/etc/nginx/conf.d volumes: immich-proxy-conf: Log output from the immich-proxy container: /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh 10-listen-on-ipv6-by-default.sh: info: can not modify /etc/nginx/conf.d/default.conf (read-only file system?) /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-set-env-variables.envsh /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh 20-envsubst-on-templates.sh: Running envsubst on /etc/nginx/templates/default.conf.template to /etc/nginx/conf.d/default.conf /docker-entrypoint.d/20-envsubst-on-templates.sh: line 53: can't create /etc/nginx/conf.d/default.conf: Permission denied
22 Replies
ddshd
ddshd2y ago
You should either put another reverse proxy in front of the Immich proxy with your settings or (since you already created a full nginx.conf) rebuild the immich proxy locally with your updated config Here is the immich_proxy files (https://github.com/immich-app/immich/tree/main/nginx). Just updated the conf in the template folder and build it locally
tmorgan497
tmorgan497OP2y ago
I'm inexperienced with rebuilding docker images. Is there any documentation on how the build process for the immich docker image works?
ddshd
ddshd2y ago
Replace the immich-proxy entry with
immich-proxy:
container_name: immich_proxy
build:
context: ./nginx/
dockerfile: Dockerfile
environment:
# Make sure these values get passed through from the env file
- IMMICH_SERVER_URL
- IMMICH_WEB_URL
ports:
- 2283:8080
depends_on:
- immich-server
restart: always
immich-proxy:
container_name: immich_proxy
build:
context: ./nginx/
dockerfile: Dockerfile
environment:
# Make sure these values get passed through from the env file
- IMMICH_SERVER_URL
- IMMICH_WEB_URL
ports:
- 2283:8080
depends_on:
- immich-server
restart: always
Assuming ./nginx/ is the folder you got from github. Your extra config should be in ./nginx/templates/default.conf.template. Then you can run docker-compose up -d --build
tmorgan497
tmorgan497OP2y ago
When I do that, I get errors in the immich-proxy container:
2023/09/17 20:34:24 [emerg] 1#1: host not found in upstream "${IMMICH_SERVER_HOST}" in /etc/nginx/conf.d/default.conf:15

nginx: [emerg] host not found in upstream "${IMMICH_SERVER_HOST}" in /etc/nginx/conf.d/default.conf:15
2023/09/17 20:34:24 [emerg] 1#1: host not found in upstream "${IMMICH_SERVER_HOST}" in /etc/nginx/conf.d/default.conf:15

nginx: [emerg] host not found in upstream "${IMMICH_SERVER_HOST}" in /etc/nginx/conf.d/default.conf:15
Do I need to explicitly set those env variables?
ddshd
ddshd2y ago
Try docker-compose up -d --force-recreate --build
tmorgan497
tmorgan497OP2y ago
Yeah, unfortunately I get the same errors when I force recreate and rebuild the images. I even tried starting a fresh immich stack up with the new nginx settings and got the same error.
ddshd
ddshd2y ago
You put the changes into the files in the template folder correct?
tmorgan497
tmorgan497OP2y ago
yes. I hardcoded the host:port in default.conf.template because I was still getting errors where it was saying host not found in upstream
ddshd
ddshd2y ago
Did that work?
tmorgan497
tmorgan497OP2y ago
Unfortunately it did not. It's just weird because I can make API calls from postman on my local PC without issue, but when I make API calls from my quasar app (also running from my local PC) I get the CORS error.
ddshd
ddshd2y ago
If you look at the headers from postman do you see the CORS header in the response
tmorgan497
tmorgan497OP2y ago
Nothing in the request or response headers in postman would indicate to me that CORS headers are being applied. I'll look back into modifying the nginx config to make sure it adds the headers. I'm an nginx noob so I'll have to read up a bit. Basically, immich is running in a docker container (with a mostly standard compose file based on the github version). The docker container is running on Unraid so maybe I can just setup another nginx container and proxy through that for the API calls and overwrite the immich nginx config basically
No description
ddshd
ddshd2y ago
What did you change to the normal nginx config From a quick google search you need to add
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Origin *;
tmorgan497
tmorgan497OP2y ago
Well just to test it, I added another nginx layer by spinning up a dedicated nginx container and adding the add_header 'Access-Control-Allow-Origin' '*' to it and it seems to work now. This will work for now since I'm already using nginx for other apps too. Although, I don't really know how secure this method is, but since I'm doing most everything over Tailscale, maybe it doesn't matter 🤷‍♂️. @ddshd thank you for helping me diagnose this!
ddshd
ddshd2y ago
You can check the nginx logs and see if you tell what host the requests are coming from (or some docs for your service that says which host the request should come from) and you can replace the * with that host to lock it down
tmorgan497
tmorgan497OP2y ago
Makes sense. Thanks again!
jrasm91
jrasm912y ago
This is a header that tells clients if they should be able to render/access the data from another domain. Specifically, it is used to prevent badguy.com from loading an iframe with youbank.com. CORS access control is always a pain, but is needed if you are accessing data from a different domain than the one the data is coming from. If your webapp has a server component, you can also get around this by adding a route to your web app like /immich-api that forwards the request to immich or your reverse proxy. Then the request is made to the same server that is hosting the webapp and CORS isn't applicable anymore.
tmorgan497
tmorgan497OP2y ago
Which version is more secure: adding a server-side route to immich, or adding addresses to Access-Control-Allow-Origin?
jrasm91
jrasm912y ago
In both situations the data is still available to everyone all the time. Adding the headers or not adding the headers only impacts the security implications of the immich api being used/embedded in another domain (like phishing attacks, etc.) I guess the TLDR is it probably has minimal security implications for you. In my experience dealing with CORS itself is a huge headache though. Are you going to authenticate the immich api with a cookie or api key? A cookie isn't set by default unless you include withCredentials: true in the xhr/fetch request. That might or might not be easy to add. cookies on the same domain are included/sent by default though.
ddshd
ddshd2y ago
imo the CORS header is easier because you can whitelist certain domains you want to allow and also avoid additional traffic through your app. Just let the app on a certain domain hit the api directly Though you can have your server disallow certain admin paths from other domains than your own to make it more secure (Personally I don’t allow most of the admin or delete endpoints to be hit from the outside at all)
jrasm91
jrasm912y ago
Specifying cors doesn't prevent somebody from using it in say, a mobile app. Afaik flutter http library doesn't check it. Adding cors rules doesn't prevent someone from accessing it in the first place. It is something that is enforced client-side
ddshd
ddshd2y ago
Well I was assuming it was like a webapp accessed through a normal browser which would be enforcing that unless you disable it (an annoyance)

Did you find this page helpful?