🚀 Feature: Get rid of caddy - make backend proxy the requests to frontend too #304

Closed
opened 2025-10-08 00:02:15 +03:00 by OVERLORD · 4 comments
Owner

Originally created by @ItalyPaleAle on GitHub.

Feature description

pocket-id uses caddy within its container to be able to proxy requests to the backend and frontend depending on the path. This has some downsides:

  1. There's an additional process running in the container, which adds complexity-and which could crash (see #323)
  2. By default, caddy listens on port 80 which is a privileged port, so the pocket-id container can't run with runAsUser: 1000 (the container has a built-in script that switches to non-root users when using PID/GID, but the container is still started as root which is considered not best).
  3. While caddy can be disabled, it requires setting up routes externally by hand

I would suggest removing caddy and making the backend process automatically proxy requests to the front-end if it doesn't know how to handle them (e.g. for all paths besides /api and /.well-known).

As a bonus, the Go application could also become a process manager that starts Node.js (and restarts it if it crashes), also fixing #323

Pitch

See description :)

Originally created by @ItalyPaleAle on GitHub. ### Feature description pocket-id uses caddy within its container to be able to proxy requests to the backend and frontend depending on the path. This has some downsides: 1. There's an additional process running in the container, which adds complexity-and which could crash (see #323) 2. By default, caddy listens on port 80 which is a privileged port, so the pocket-id container can't run with `runAsUser: 1000` (the container has a built-in script that switches to non-root users when using PID/GID, but the container is still started as root which is considered not best). 3. While caddy can be disabled, it requires setting up routes externally by hand I would suggest removing caddy and making the backend process automatically proxy requests to the front-end if it doesn't know how to handle them (e.g. for all paths besides `/api` and `/.well-known`). As a bonus, the Go application _could also_ become a process manager that starts Node.js (and restarts it if it crashes), also fixing #323 ### Pitch See description :)
OVERLORD added the feature label 2025-10-08 00:02:15 +03:00
Author
Owner

@ItalyPaleAle commented on GitHub:

You are right, but I don't think I did a good job at explaining the issue :)

My biggest problem is that Caddy is included in the container and it seems that its only purpose is to route requests to the backend or frontend by the path. Having caddy adds complexity and there's something else that can crash (see #323). Caddy can be disabled, and an external proxy can be configured to route requests correctly (that's what I'm doing myself), but it still is more complex than it could be.

The other issue with Caddy is that with the default configuration of the container, it listens on port 80, which is privileged. That means you can't start the container with a securityContext.runAsUser that points to a non-root user. That can be solved by setting CADDY_PORT to a non-privileged port, but it's yet more complexity.

I am suggesting that given that Caddy is only used to route requests by their path, its job could be easily taken over by the Go application (the backend), which would receive all requests and then route to the frontend those that are not for /api or /.well-known. This would mean having one less process to manage, one less port, and a lot less complexity.

@ItalyPaleAle commented on GitHub: You are right, but I don't think I did a good job at explaining the issue :) My biggest problem is that Caddy is included in the container and it seems that its only purpose is to route requests to the backend or frontend by the path. Having caddy adds complexity and there's something else that can crash (see #323). Caddy can be disabled, and an external proxy can be configured to route requests correctly (that's what I'm doing myself), but it still is more complex than it could be. The other issue with Caddy is that with the default configuration of the container, it listens on port 80, which is privileged. That means you can't start the container with a `securityContext.runAsUser` that points to a non-root user. That can be solved by setting `CADDY_PORT` to a non-privileged port, but it's yet more complexity. I am suggesting that given that Caddy is only used to route requests by their path, its job could be easily taken over by the Go application (the backend), which would receive all requests and then route to the frontend those that are not for `/api` or `/.well-known`. This would mean having one less process to manage, one less port, and a lot less complexity.
Author
Owner

@stonith404 commented on GitHub:

Thanks but don't plan to implement this because Caddy is really lightweight, and we would have to use a library in Go that proxies the services. The library would probably be less stable than Caddy. For example, in Pingvin Share, I first also proxied the backend through the frontend, and the library had some strange bugs which led me to set up a separate reverse proxy.

Using the backend as a reverse proxy also adds complexity to our core application code, mixing concerns that are better kept separate.

For the privileged port issue, we could configure Caddy to run on a non-privileged but this would break all existing installations. This probably makes sense to change when we release v1.0.0.

@stonith404 commented on GitHub: Thanks but don't plan to implement this because Caddy is really lightweight, and we would have to use a library in Go that proxies the services. The library would probably be less stable than Caddy. For example, in Pingvin Share, I first also proxied the backend through the frontend, and the library had some strange bugs which led me to set up a separate reverse proxy. Using the backend as a reverse proxy also adds complexity to our core application code, mixing concerns that are better kept separate. For the privileged port issue, we could configure Caddy to run on a non-privileged but this would break all existing installations. This probably makes sense to change when we release `v1.0.0`.
Author
Owner

@kmendell commented on GitHub:

The create-user.sh script only switches to root to create the user with the UID and GID and set permissions on the files etc then switches to that user. Even if no UID or GID is given it will use 1000 and still do the same thing, it doesn't do anything else besides that. Unless im confused on something here.

@kmendell commented on GitHub: The `create-user.sh` script only switches to root to create the user with the UID and GID and set permissions on the files etc then switches to that user. Even if no UID or GID is given it will use 1000 and still do the same thing, it doesn't do anything else besides that. Unless im confused on something here.
Author
Owner

@kmendell commented on GitHub:

I get your point and understand, though i would argue that caddy is not complex compared to many other reverse proxies. Its only a few lines that control whats happening, and while technically its written in go so it can all be done natively that's more code, more build time, and a bigger binary and container size (im just listing possibilities). I will see what stonith404 says about this.

@kmendell commented on GitHub: I get your point and understand, though i would argue that caddy is not complex compared to many other reverse proxies. Its only a few lines that control whats happening, and while technically its written in go so it can all be done natively that's more code, more build time, and a bigger binary and container size (im just listing possibilities). I will see what stonith404 says about this.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/pocket-id-pocket-id-1#304