Standalone docker image
:bulb: The Idea
Is there any reason why we need nginx inside the docker container apart from authentication. If not could we have a docker image without nginx (and we can remove supervisord as well) and let docker do the orchestration, and traefik (in my case) handle the reverse proxy as well as authentication.
I could send a PR for this feature. Thank you very much!
:hammer: Breaking Feature
We could publish both images: the normal one and the one with -standalone suffix so there won't be any breaking changes.
Per documentation, gunicorn is advised to run behind a nginx environment which is why it is the way it is. The nginx instance also serves the static files.
If you run just a gunicorn instance in a docker container, everything will still work provided you use the API to create/modify your configuration directly through it (no simple helper front-end). The other nice thing with the current design is that I can use a script to ensure the correct user/group permissions are set on startup which was a problem people had issues with earlier in the development. The script allows one to disable ipv6 or ipv4 if they wish too (yet another feature request).
Anyway, That's the long winded answer to why it is the way it is. 🙂
If you did a simple container, would this just sit beside the full scale one granting one to choose?What were your thoughts here?
Thank you for your response. For my usecase I don't need nginx.
If you choose another proxy server you need to make sure that it buffers slow clients when you use default Gunicorn workers. Without this buffering Gunicorn will be easily susceptible to denial-of-service attacks.
I think popular reverse proxies should already have a similar feature (traefik yes in my case). Also I don't intent to expose apprise at all so I don't need a reverse proxy.
If you run just a gunicorn instance in a docker container, everything will still work provided you use the API to create/modify your configuration directly through it (no simple helper front-end).
I copy all my configurations to the docker volume with APPRISE_STATEFUL_MODE=simple so it is not a problem for me. I even set /config to read-only so this has no use for me at all.
The other nice thing with the current design is that I can use a script to ensure the correct user/group permissions are set on startup which was a problem people had issues with earlier in the development.
We can still setup an entrypoint script and call to gunicorn in the end so I don't think there will be much problem.
The script allows one to disable ipv6 or ipv4 if they wish too (yet another feature request).
I saw some potential improvements for this one actually.
For the current setup, we only need to tell nginx to listen on IPv4 and/or IPv6. Because it will forward the request to gunicorn on localhost:8080 which is an IPv4 address, we don't need to tell gunicorn to listen on IPv6 in both cases.
https://github.com/caronc/apprise-api/blob/3fde6d00914b6a538f9003c5d940b909fdce42a7/apprise_api/etc/nginx.conf#L58
For the standalone setup, could we add an environment variable like GUNICORN_BIND_ADDRESSES=0.0.0.0:8080,[::]:8080 and tell the configuration file to read that ? It could also address feature request like #210 and if we go this way, we should just set GUNICORN_BIND_ADDRESSES=127.0.0.1:8080 for the nginx setup.
If you did a simple container, would this just sit beside the full scale one granting one to choose?What were your thoughts here?
They are all of my thoughts. Could you tell me what do you think about them ? Thank you!
Hi @vnghia
I have had success serving Apprise api via Traefik using docker image caronc/apprise:1.2.0.
It does result in double proxying first via Nginix in the container, and then Traefik externally. But it seems to work fine.
The fact it works with Traefik is perhaps not the point you are making. But I thought I'd share my docker-compose yaml config below in case it helps.
#------------------------------------------------------------------------------
networks:
traefik:
external: true
#------------------------------------------------------------------------------
services:
apprise:
image: caronc/apprise:1.2.0
container_name: apprise
hostname: apprise
networks:
- traefik
environment:
- TZ=UTC
- PUID=1000
- PGID=1000
- APPRISE_WORKER_COUNT=1
- APPRISE_STATEFUL_MODE=simple
volumes:
- ./attach:/attach
- ./config:/config
labels:
- traefik.enable=true
- traefik.docker.network=traefik
- traefik.http.routers.apprise.tls=true
- traefik.http.routers.apprise.entrypoints=websecure
- traefik.http.routers.apprise.rule=Host(`apprise.apps.lan`)
- traefik.http.services.apprise.loadbalancer.server.port=8000
restart: unless-stopped
#------------------------------------------------------------------------------
# apprise api can be found at https://apprise.apps.lan
#------------------------------------------------------------------------------
I'm with @caronc on this issue.
Proxying via nginx by default does provide some security guarantees out of the box and I think that is a very decent design decision.
The provided nginx can be extended via overrides and that is already documented - again nice one @caronc
I do understand that you (dear reader) might have a preferred proxy mechanism but any project has to work within a wider framework. @caronc is comfortable working with nginx and they are probably the sole (or at least rather lonely) dev here. They get to call the shots. End of!
My recent deployment of Apprise involves three proxies, one of which is the built in nginx! Yes that is mad but there are good reasons for each one.
Can I close this one out?
Keep in mind that the nginx configuratoin that ships with Apprise has a lot of hooks allowing you to override settings if you need to. You can include these hooks when deploying your container. In the latest PR i have pending, i got rid of port 8080 to avoid confusion.
Apprise will soon 'only' listen on port 8000 (hosted via the internal nginx server); PR that does this #265
Yes thank you for all your suggestions and awesome apprise :D