Skip to content

Tandoor Update Webserver Issues - Integrated Nginx #3851

Closed

Description

@vabene1111

Tandoor 2.3 Update

With Tandoor update 2.3.0 the migration to the internal nginx server was completed, removing the ability to access the integrated python wsgi server directly. This should not cause issues for people who had already migrated to the internal nginx (see below) but does cause issues for some people. Here are the relevant problems and fixes:

Tandoor Port Change

If you had TANDOOR_PORT set but still pointed your reverse proxy to 8080 you will no longer reach Tandoor. 6adf077.
Fix: point to whatever you configured in TANDOOR_PORT or unbind and point to port 80

Tandoor is not reachable

You are likely still using the old Tandoor v1 setup.
Fix: Remove the nginx as described in the section below.

502 Error after Login

The following error can happen after logging in to Tandoor v2.3.0 if you do not have a reverse proxy or in all versions if your reverse proxy is not configured to correctly forward the client ip address by setting the X-Forwarded-For header.

web_recipes-1  | django.db.utils.IntegrityError: null value in column "ip" of relation "usersessions_usersession" violates not-null constraint
web_recipes-1  | DETAIL:  Failing row contains (2, 2025-10-06 21:33:08.606563+00, null, 2025-10-06 21:33:08.60659+00, vasudujcixxye751c1qtps2leojbif0c, Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20..., {}, 1).

Fix

  • If you do not want to use a reverse proxy upgrade to version 2.3.1 and the issue is fixed.
  • If you want to use a reverse proxy make sure it sets the header. Example for nginx is proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

See also #4126

Unraid

The unraid template is hardcoded to port 8080. The template was updated but it might not update existing installations (see #3851 (comment))

There are two fixes:

Tandoor 2 Update

Tandoor 1 includes gunicorn, a python WSGI server that handles python code well but is not meant to serve mediafiles. Thus it has always been recommended to setup an nginx webserver (not just a reverse proxy) in front of Tandoor to handle mediafiles. The gunicorn server by default is exposed on port 8080

Tandoor 2 now bundles nginx inside the container and exposes port 80 where mediafiles are handles by nginx and all the other requests are (mostly) passed to gunicorn.

To update you must simply change your port or reverse proxy configuration to access port 80 instead of port 8080.

> If you had previously configured `TANDOOR_PORT` to port `80` that configuration is now ignored and gunicorn is exposed on Port `8080`. Since nginx is on port 80 in the new versions your setup should continue to work without any changes.

Accessing 8080 directly is deprecated and will be removed in the future. Sufficient warnings and explanations will be given.

⚠️ UPDATE 2.3.0 changed TANDOOR_PORT to configure the internal nginx instead of gunicorn. This breaks in two cases

  • if you had TANDOOR_PORT set but still pointed your reverse proxy to 8080 6adf077. Fix: point to whatever you configured in TANDOOR_PORT or unbind and point to port 80
  • if you had the pre V2 default setup and pointed your proxy to 8080 which is now no longer exposed. Fix: point your proxy to port 80 and remove the nginx

Should you have any issues with the change feel free to post your questions below, I will try to update this main comment with FAQ's should they arise.

Example

If you were using Traefik for the reverse proxy your Tandoor 1 docker-compose.yml might have looked something like this:

services:
  db_recipes:
    restart: always
    image: postgres:16-alpine
    volumes:
      - ./postgresql:/var/lib/postgresql/data
    env_file:
      - ./.env
    networks:
      - default

  web_recipes:
    image: ghcr.io/tandoorrecipes/recipes
    restart: always
    env_file:
      - ./.env
    volumes:
      - staticfiles:/opt/recipes/staticfiles
      - mediafiles:/opt/recipes/mediafiles
      - nginx:/opt/recipes/nginx/conf.d
    depends_on:
      - db_recipes
    networks:
      - default

  nginx_recipes:
    image: nginx:mainline-alpine
    restart: always
    env_file:
      - ./.env
    volumes:
      - nginx:/etc/nginx/conf.d:ro
      - mediafiles:/media
    labels: # This lables are only examples!
      - "traefik.enable=true"
      - "traefik.http.routers.recipes.rule=Host(`recipes.sienz.family`)||Host(`rezepte.sienz.family`)"
      - "traefik.http.routers.recipes.entrypoints=web_secure"
      - "traefik.http.routers.recipes.tls.certresolver=le_resolver"
    networks:
      - default
      - traefik

networks:
  default:
  traefik: # This is you external traefic network
    external: true


volumes:
  nginx:
  staticfiles:
  mediafiles:
      driver: local
      driver_opts:
        type: 'none'
        o: 'bind'
        device: './mediafiles'

Beginning with Tandoor 2 (beta 6) you can now remove the nginx container and point your Traefik (reverse proxy) directly at Tandoor like this.

services:
  db_recipes:
    restart: always
    image: postgres:16-alpine
    volumes:
      - ./postgresql:/var/lib/postgresql/data
    env_file:
      - ./.env
    networks:
      - default

  web_recipes:
    image: ghcr.io/tandoorrecipes/recipes
    restart: always
    env_file:
      - ./.env
    volumes:
      - staticfiles:/opt/recipes/staticfiles
      - mediafiles:/opt/recipes/mediafiles
    depends_on:
      - db_recipes
    labels: 
      - "traefik.enable=true"
      - "traefik.http.routers.recipes.rule=Host(`your.tandoor.url`)"
      - "traefik.http.routers.recipes.entrypoints=web_secure"
      - "traefik.http.routers.recipes.tls.certresolver=le_resolver"
    networks:
      - default
      - traefik

networks:
  default:
  traefik: # This is you external traefic network
    external: true


volumes:
  staticfiles:
  mediafiles:
      driver: local
      driver_opts:
        type: 'none'
        o: 'bind'
        device: './mediafiles'

You also no longer need to mount the nginx volume to sync the default config from tandoor to the nginx container. Should you need to edit the nginx config for some reason you can do so by mounting the /opt/recipes/http.d/ directory to your host system. Keep in mind that when doing this you will not receive updates on this file in future versions.

Activity

  1. soxism commented on Jul 31, 2025

    @soxism

    Just deployed this and can confirm its working smoothly.

    I had an existing deployment and had defined ports in docker-compose and .env - so it should be noted that those need to change back to port 80.

  2. 99-lives commented on Jul 31, 2025

    @99-lives

    Noting in case anyone else has this issue.

    With this version, you must name your docker container web_recipes, because that's the host that the built-in Nginx config is configured to proxy. If you name your container anything else, as I did, then it won't work. I've opened issue #3856 to track this, if it is indeed considered a bug.

  3. vabene1111 commented on Jul 31, 2025

    @vabene1111
    CollaboratorAuthor

    version, you must name your docker container web_recipes, because that's the host that the built-in Nginx config is configured to proxy. If you name your container anything else, as I did, then it won't work. I've opened issue #3856 to track this, if it is indeed considered a bug.

    thanks for the report, this was not intended and is fixed now.

    I had an existing deployment and had defined ports in docker-compose and .env - so it should be noted that those need to change back to port 80.

    Thanks for the information. I will add a note about this in the migration guide and later remove the port option alltogether.

  4. wilmardo commented on Jul 31, 2025

    @wilmardo
    Contributor

    @vabene1111 would you be willing to accept an PR for this change still? The has moved to stable so quick that I haven't had time to provide proper feedback.

    But I can for sure say that this setup is going to have a lot of issues, bash doesn't forward signals to started processes so nginx will become a zombie when the container is restarted.

    Also it would have been easy to setup nginx on port 8080 and setup a non root user as well.

  5. vabene1111 commented on Jul 31, 2025

    @vabene1111
    CollaboratorAuthor

    I am happy to accept PRs. I wanted it on port 80 so that is on purpose. If you have a better idea on how to run the nginx feel free to suggest (I suggest we start a different issue for the discussion).

    My plan was to deprecated the exposed gunicorn after the first error fixing phase of 2.0.0 in a few weeks maybe,just FYI

  6. tomsinclair94 commented on Jul 31, 2025

    @tomsinclair94

    In my setup I have exposed Tandor on a different port and previously had this in the nginx_recipes section:

        ports:
          - XYZ:80
    

    For this migration to the intergrated nginx, I simply removed the entire block for the nginx_recipes image (as mentioned in the docs) and added my ports: config line to the web_recipes section and everything is working and I can still access Tandoor on this custom port.

    Thanks for the information. I will add a note about this in the migration guide and later remove the port option alltogether.

    Will exposing the internal port 80 to a custom external port still be supported?

    Edit: I believe you may have been referring to removing the option to override the TANDOOR_PORT option inside the .env file?

  7. vabene1111 commented on Jul 31, 2025

    @vabene1111
    CollaboratorAuthor

    Edit: I believe you may have been referring to removing the option to override the TANDOOR_PORT option inside the .env file?

    yes, the option will no longer be necessary in the future because you can override the nginx config to change the port

  8. vabene1111 commented on Aug 8, 2025

    @vabene1111
    CollaboratorAuthor

    note from #3911 :

    if you delete your old nginx make sure to either down the container before changing the docker compose file or to remove the orphaned containers when starting the docker compose without nginx.

  9. TomAFrench commented on Sep 6, 2025

    @TomAFrench

    I'm running into an issue related to image files and how the nginx server is set up.

    Opening my.tandoor.com/media/recipes/recipe_file.jpg in the browser gets a response with the expected picture file being downloaded with the server header set to nginx. However if I open my.tandoor.com then all of the recipe images are white squares (note this is not the placeholder pizza image). If I open the network tab in the browser console then I can see that gunicorn is serving the request to the exact same URL I opened directly earlier and we're getting the tandoor page source being sent instead.

    Requests from my.tandoor.com are then not being routed as expected by nginx but I'm not clear on what I should do to address this, if someone can help I'd be very grateful. I'm running tandoor 2.1.0 in a traefik setup basically identical to that in the OP.

    Edit: Curious, the images are loading fine on my phone.

    Edit 2: Even more strangely this isn't affecting new recipes I'm adding. Only those which I exported from the hosted version of tandoor and reimported into my instance.

  10. paulmaurovich commented on Sep 14, 2025

    @paulmaurovich

    After some debugging and manually looking through http.d/ and nginx/ directories, I have found that doing the following

    • exposing port 80 (instead of 8080)
    • connecting to port 80 via treafik3
    • leaving TANDOOR_PORT unset

    makes the images load properly. Running inside k8s with containerd.

    Setting port 8080 and connecting to it works fine, but this results in non-loading images. If I've read it correctly, connecting to port 8080 is deprecated and 80 is the way to go (now; with v2).

  11. wolsen9 commented on Sep 29, 2025

    @wolsen9

    Just adding my comments to agree with @paulmaurovich , linking to port 80 with Tandoor 2 works as expected while port 8080 left me with no images. The docs still refer to port 8080, so I'm not entirely sure the correct method.

    As for anyone else that may be using Caddy as a reverse proxy, the Tandoor docker compose I'm using is below. Nothing special with Caddy, just reverse proxing to the exposed port. Works with Kitchn as well. I am far from fluent with these networks and proxy forward headers:

    services:
      db_recipes:
        restart: always
        image: postgres:16-alpine
        volumes:
          - postgresql:/var/lib/postgresql/data
        env_file:
          - ./tandoor.env
    
      web_recipes:
        restart: always
        image: vabene1111/recipes
        ports:
          - 2000:80
        env_file:
          - ./tandoor.env
        volumes:
          - staticfiles:/opt/recipes/staticfiles
          - mediafiles:/opt/recipes/mediafiles
        depends_on:
          - db_recipes
    
    volumes:
      staticfiles:
      mediafiles:
      postgresql:
  12. vabene1111 commented on Sep 30, 2025

    @vabene1111
    CollaboratorAuthor

    With the next update (2.3) I will complete the migration to the internal nginx by removing the option to bind directly to gunicorn from outside of the container.

    👍 everyone already using the integrated nginx by pointing to port 80 does not need to change anything if TANDOOR_PORT is not set.

    Gunicorn will be bound to the nginx internally using a unix socket, that means binding it from the outside no longer works (i think, mabye you can bind the socket but you shouldn't).

    The TANDOOR_PORT environment variable will no longer configure gunicorn, it now configures nginx. This means if you had TANDOOR_PORT configured before the update and pointed your reverse proxy to it everything works automatically, as you now just access nginx.

    ⚠️ if you had TANDOOR_PORT set to any port but were still using port 8080 to directly access gunicorn your setup will no longer work. This configuration never made sense so you should either remove TANDOOR_PORT and just point to 8080 (should be the correct way for 99,99% of people) or change TANDOOR_PORT to the port you want to use.

  13. greenbear48 commented on Oct 7, 2025

    @greenbear48

    Hi,

    First, thank you for maintaining the vabene1111/recipes Docker image. It's a fantastic project.

    I'm writing to report two critical issues I encountered after the image was updated on October 5th, 2025. These issues make the latest version unusable for me on Unraid, especially when using a reverse proxy. Downgrading to version 1.5.13 solved all problems.

    Issue 1: Internal Listening Port Changed from 8080 to 80

    Symptom: After the update, the container was completely unreachable via the network.

    Cause: We discovered that the internal listening port of the container changed from the previous 8080 to 80.

    Impact: This breaks the standard Unraid Community Application template for Tandoor, which has the container port locked to 8080. Users are unable to edit this, making the update immediately break their setup.

    Workaround: We had to manually add a new, second port mapping in Unraid (Host Port 8155 -> Container Port 80) to regain access to the web UI.

    Issue 2: Reverse Proxy IP Detection Failure (DB IntegrityError on Login)

    This is the more critical bug.

    Symptom: When accessing the container through a reverse proxy (Nginx Proxy Manager), the login page loads correctly. However, after submitting valid login credentials, the application crashes with a Server Error (500).

    Cause: The container log shows a consistent database error. The application is unable to get the client's real IP address from the reverse proxy headers, causing it to try and write a NULL value to the ip column in the usersessions_usersession table.

    Log Traceback:

    django.db.utils.IntegrityError: null value in column "ip" of relation "usersessions_usersession" violates not-null constraint
    Troubleshooting Steps Taken: We tried every standard environment variable to fix this, but none of them worked on the latest image:

    BEHIND_REVERSE_PROXY=true

    FORWARDED_ALLOW_IPS='*'

    DJANGO_TRUSTED_PROXIES (with various values like 192.168.1.0/24 and the specific WireGuard IP of the proxy)

    None of these variables resolved the 500 error, which strongly suggests the internal Nginx/Gunicorn configuration in the latest image is not correctly processing X-Forwarded-For headers.

    Final Solution & System Info

    Working Solution: The only way to fix the issues was to downgrade the image. By changing the repository in Unraid to vabene1111/recipes:1.5.13, the container started working perfectly again. The listening port reverted to 8080, and the reverse proxy login works without any extra environment variables.

    My Environment:

    Host: Unraid OS

    Reverse Proxy: Nginx Proxy Manager (on a separate server, connected via WireGuard)

    Problematic Image: vabene1111/recipes:latest (as of 2025-10-07)

    Working Image: vabene1111/recipes:1.5.13

    It seems the latest update introduced a breaking change in the networking setup. I hope this detailed report helps you track down and resolve the bug.

    Thanks again for your work!

    Best regards

    greenbear

  14. vabene1111 commented on Oct 8, 2025

    @vabene1111
    CollaboratorAuthor

    @greenbear48 thanks for the summary. While many things are true I cannot agree on some:

    Issue 1: This is not a bug but a feature. The port was changed on purpose as indicated in the changelog. Someone needs to fix the unraid template which is not maintained by me but someone else.

    What would be interesting if someone could change TANDOOR_PORT to 8080, this should also fix the unraid setup.

    Issue 2:
    As far as I have seen in the Issues any user that does use a reverse proxy could resolve the issue by adding the appropriate headers. It is only affecting users not running a reverse proxy at the moment. For everyone that has a reverse proxy make sure this header is present http://172.18.0.4:80/api/recipes/

    for anyone else: please downgrade to 2.2.7 and wait for the next release which hopefully will include a fix.

  15. pinned this issue on Oct 8, 2025
  16. changed the title [-]Integrated Nginx[/-] [+]Tandoor Update Webserver Issues - Integrated Nginx[/+] on Oct 8, 2025
  17. LekoArts commented on Oct 8, 2025

    @LekoArts

    Unraid: Any new installations of the Unraid plugin should work as the author updated the template: https://forums.unraid.net/topic/98179-support-tandoor-recipes-corneliousjd-repo/page/5/#findComment-1582644
    CorneliousJD/Docker-Templates@2826e3a

    I'm not sure if this retroactively also updates existing installations, at least for me it didn't do that.

    I've got my Unraid setting up working by updating the template myself, too. For that you'll need to edit the Docker container, remove the "Port" and re-add it with the Container Port being 80 (previously 8080). Then on the top right switch to "Advanced View" and change WebUI to http://[IP]:[PORT:80]

  18. uncoverbrokkoli commented on Oct 9, 2025

    @uncoverbrokkoli

    Just updated to the newest version. After some hassle it now works fine with my ngnix reverse proxy running in a different container.
    I use the pre-configured site configuration that come with nginx and there is still port 8080 mentioned. Updating it to port 80 resolved my issues. Maybe the nginx configuration defaults can be changed so that it makes updating easier?

  19. vabene1111 commented on Oct 10, 2025

    @vabene1111
    CollaboratorAuthor

    definitely, if you see issues in existing documentation always feel free to fix them. I personally only maintain the docker installation instructions as I simply do not have the time to maintain all the community guides.

  20. update-freak commented on Oct 10, 2025

    @update-freak

    With latest update I got this on my synology nas (DSM 7.3) in docker:

    Image

    (with Tandoor 2.2 it works)

    docker compose:

    services:
      db:
        image: postgres:18-alpine
        container_name: Tandoor-db
        volumes:
          - /volume1/docker/tandoor/db:/var/lib/postgresql
        env_file:
          - stack.env
        restart: always
    
    
      tandoor:
        image: vabene1111/recipes:latest
        container_name: Tandoor
        volumes:
          - /volume1/docker/tandoor/staticfiles:/opt/recipes/staticfiles
          - /volume1/docker/tandoor/mediafiles:/opt/recipes/mediafiles
          - /volume1/docker/tandoor/nginx:/opt/recipes/nginx/conf.d
        env_file:
          - stack.env
        restart: always
        depends_on:
          db:
            condition: service_started
    
    
      nginx:
        image: nginx:mainline-alpine
        container_name: Tandoor-nginx
    
    
        volumes:
          - /volume1/docker/tandoor/staticfiles:/static:ro
          - /volume1/docker/tandoor/mediafiles:/media:ro
          - /volume1/docker/tandoor/nginx:/etc/nginx/conf.d:ro
        ports:
          - 9815:80
        env_file:
          - stack.env
        restart: always
        depends_on:
          - tandoor
    
    

    EDIT: solved it via

    services:
      db:
        image: postgres:18-alpine
        container_name: Tandoor-db
        volumes:
          - /volume1/docker/tandoor/db:/var/lib/postgresql
        env_file:
          - stack.env
        restart: always
    
    
      tandoor:
        image: vabene1111/recipes:latest
        container_name: Tandoor
        volumes:
          - /volume1/docker/tandoor/staticfiles:/opt/recipes/staticfiles
          - /volume1/docker/tandoor/mediafiles:/opt/recipes/mediafiles
        env_file:
          - stack.env
        ports:
          - 9815:80
        restart: always
        depends_on:
          db:
            condition: service_started
    
  21. AdrienPoupa commented on Oct 14, 2025

    @AdrienPoupa
    Contributor

    I'm using a custom Nginx configuration. My setup was broken until I changed the proxy_pass instruction from a port to the socket: AdrienPoupa/docker-compose-nas@e940db7

    I think it is confusing that there are two configurations in the repo at the moment:

  22. TimNiceButDim commented on Nov 16, 2025

    @TimNiceButDim

    Lost all my recipes, cant seem to figure out how to get this docker working anymore :( such a shame, how did an update break everything so badly

  23. laur89 commented on Nov 16, 2025

    @laur89

    Take it as a learning lesson to back up your data.

  24. vabene1111 commented on Nov 18, 2025

    @vabene1111
    CollaboratorAuthor

    there should be absolutely nothing going on about your data when performing the update. Worst that can happen is you rollback to the previous version.

    Data loss is typically related to people not mounting the postgres directory properly.

  25. PiiiRKO commented on Jan 13, 2026

    @PiiiRKO

    Lost all my recipes, cant seem to figure out how to get this docker working anymore :( such a shame, how did an update break everything so badly

    I feel you. Dealing with the same thing. I am not a big tech power user, so figuring this out is pretty beyond my capabilities. I know the recipes are still in the database, tandoor just doesn't want to see them in the new updated instance.

  26. vabene1111 commented on Jan 23, 2026

    @vabene1111
    CollaboratorAuthor

    @PiiiRKO i recommend you open an issue with some information so people can actually help you because like this nobody can do anything. Otherwise the instructions do work for many people so maybe review if you have followed them correctly.

  27. unpinned this issue on Apr 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions