[//]: # ( ) [//]: # ( Logo) [//]: # ( )

Caddy Manager

A UI for managing Caddy configuration files
Explore the docs »

Report Bug (label bug) · Request Feature (label enhancement) [//]: # ( View Demo) [//]: # ( ·)

Table of Contents
  1. About The Project
  2. Getting Started
  3. Usage
  4. Roadmap
  5. Contributing
  6. License
  7. Contact
  8. Acknowledgments
## About The Project [//]: # ([![Product Name Screen Shot][product-screenshot]](https://example.com)) Caddy Management is an opinionated UI for managing Caddy configuration files. It is designed to be simple and easy to use. The architecture is based on the following principles: - There has been a Caddy container running on the host machine - The Caddy container is having its configuration files organized as: - A Caddyfile contains the global configuration, and ending with the line `import *.caddy` - Other proxy configurations are saved in individual `*.caddy` files

(back to top)

### Built With [![DotNet][DotNet]][DotNet-url] [![Gitea][Gitea]][Gitea-url] [![Docker][Docker]][Docker-url] * DotNet 9 with Blazor and [MudBlazor](https://mudblazor.com/) * Source code and container registry are stored with Gitea * Docker is used for containerization with DotNet container publishing

(back to top)

## Getting Started Given that there has already been a Caddy container running on the host machine, the following steps are required to set up the Caddy Manager using Docker compose. ### Prerequisites These software are required to be installed on the host machine: * Docker. Follow the instructions at [https://docs.docker.com/get-docker/](https://docs.docker.com/get-docker/) * Caddy container. Follow the instructions at [https://caddyserver.com/docs/install](https://caddyserver.com/docs/install#docker) * The Caddy container is having its configuration files organized at: ```yaml volumes: - /path/to/configs:/etc/caddy ``` ### Global Caddy configuration Add this directive at the end of your caddy configuration (global): ``` import *.caddy ``` This is to have the caddy files managed by this application be imported and work as expected. ### Installation with Docker compose ```yaml services: caddy: image: caddy:latest container_name: caddy restart: always network_mode: "host" security_opt: - label:disable volumes: - /root/compose/caddy/config:/etc/caddy - /etc/localtime:/etc/localtime:ro caddy-manager: image: ghcr.io/daothanhduy305/caddymanager container_name: caddy-manager restart: always environment: ASPNETCORE_ENVIRONMENT: "Production" CaddyService__ConfigDir: "/config" DockerService__CaddyContainerName: "caddy" # Path to the Caddyfile as seen from inside the caddy container. Must match the container side of the # caddy container's config volume. Defaults to /etc/caddy/Caddyfile, so this line is optional above. DockerService__CaddyConfigPathInContainer: "/etc/caddy/Caddyfile" # Shared key for the HTTP API (see "HTTP API" below). Leave it out to keep the API closed. Api__Key: "change-me" # To have the access to the caddy config file user: "1000:1000" # The .NET GC sizes its heap against the cgroup limit, so this both caps the worst # case and makes the runtime self-tune downward. Raise it if you run many configs. mem_limit: 256m memswap_limit: 256m ports: - "8080:8080" volumes: - /root/compose/caddy/config:/config - /var/run/docker.sock:/var/run/docker.sock ```

(back to top)

## Usage Currently, the Caddy Manager is able to: - List all the Caddy configuration files - Edit the content of the Caddy configuration files by clicking on the file name - Create and manage the caddy files - Edit the global Caddy configuration file by using the tab "Global Cadddyfile" - Apply configuration changes with a graceful `caddy reload` (no dropped connections, and Caddy validates the configuration first, so a broken file is reported back instead of taking the proxy down) - Restart caddy container on demand - Parse simple information from the caddy configurations - Do all of the above over HTTP, for scripts and other services (see below) ### HTTP API The same operations are exposed as a JSON API, documented with OpenAPI: - Interactive documentation: `/scalar` - OpenAPI document: `/openapi/v1.json` Every request needs the shared key in the `X-Api-Key` header. The key comes from `Api:Key` (environment variable `Api__Key`). **While no key is configured the API is disabled and every endpoint answers `503`** — nothing is exposed by accident. | Method | Endpoint | Description | | --- | --- | --- | | `GET` | `/api/configurations` | List the reverse proxy configurations | | `GET` | `/api/configurations/{name}` | Get one configuration with its raw content | | `POST` | `/api/configurations` | Create a configuration (`{ "fileName": "...", "content": "..." }`) | | `PUT` | `/api/configurations/{name}` | Replace a configuration's content (`{ "content": "..." }`) | | `POST` | `/api/configurations/{name}/rename` | Rename a configuration (`{ "newFileName": "..." }`) | | `DELETE` | `/api/configurations/{name}` | Delete a configuration | | `GET` | `/api/caddyfile` | Get the global Caddyfile | | `PUT` | `/api/caddyfile` | Replace the global Caddyfile (`{ "content": "..." }`) | | `POST` | `/api/caddy/reload` | Graceful `caddy reload` | | `POST` | `/api/caddy/restart` | Restart the Caddy container | `{name}` is the file name without the `.caddy` extension, as shown in the UI. ```shell curl -H "X-Api-Key: change-me" http://localhost:8080/api/configurations curl -X POST http://localhost:8080/api/configurations \ -H "X-Api-Key: change-me" -H "Content-Type: application/json" \ -d '{"fileName":"example","content":"example.com {\n\treverse_proxy 10.0.0.2:8080\n}"}' curl -X POST -H "X-Api-Key: change-me" http://localhost:8080/api/caddy/reload ``` Renaming moves the file only; if the global Caddyfile imports the old name, update that import yourself (the UI warns about this too). > Note: the app redirects HTTP to HTTPS, so a direct `curl http://...` against the container port > gets a `307`. Add `-L`, call it over HTTPS, or go through your reverse proxy.

(back to top)

## Roadmap - [x] Parse the caddy files to get more information, i.e. the domain names, the proxy addresses, etc. See the [open issues](https://github.com/daothanhduy305/CaddyManager/issues) for a full list of proposed features (and known issues).

(back to top)

## Contributing Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again! 1. Fork the Project 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 4. Push to the Branch (`git push origin feature/AmazingFeature`) 5. Open a Pull Request ## License Distributed under the GNU GPLv3 License. See `COPYING` for more information.

(back to top)

## Contact Ebolo - [@duydao](https://duydao.org) - daothanhduy305@gmail.com Project Link: [CaddyManager](https://github.com/daothanhduy305/CaddyManager)

(back to top)

## Acknowledgments Use this space to list resources you find helpful and would like to give credit to. I've included a few of my favorites to kick things off! * [Choose an Open Source License](https://choosealicense.com) * [GitHub Emoji Cheat Sheet](https://www.webpagefx.com/tools/emoji-cheat-sheet) * [Malven's Flexbox Cheatsheet](https://flexbox.malven.co/) * [Malven's Grid Cheatsheet](https://grid.malven.co/) * [Img Shields](https://shields.io) * [GitHub Pages](https://pages.github.com) * [Font Awesome](https://fontawesome.com) * [React Icons](https://react-icons.github.io/react-icons/search)

(back to top)

[contributors-shield]: https://img.shields.io/github/contributors/othneildrew/Best-README-Template.svg?style=for-the-badge [contributors-url]: https://github.com/othneildrew/Best-README-Template/graphs/contributors [forks-shield]: https://img.shields.io/github/forks/othneildrew/Best-README-Template.svg?style=for-the-badge [forks-url]: https://github.com/othneildrew/Best-README-Template/network/members [stars-shield]: https://img.shields.io/github/stars/othneildrew/Best-README-Template.svg?style=for-the-badge [stars-url]: https://github.com/othneildrew/Best-README-Template/stargazers [issues-shield]: https://img.shields.io/github/issues/othneildrew/Best-README-Template.svg?style=for-the-badge [issues-url]: https://github.com/othneildrew/Best-README-Template/issues [license-shield]: https://img.shields.io/github/license/othneildrew/Best-README-Template.svg?style=for-the-badge [license-url]: https://github.com/othneildrew/Best-README-Template/blob/master/LICENSE.txt [linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555 [linkedin-url]: https://linkedin.com/in/othneildrew [product-screenshot]: images/screenshot.png [DotNet]: https://img.shields.io/badge/dotnet-563D7C?style=for-the-badge&logo=dotnet&logoColor=white [DotNet-url]: https://dotnet.microsoft.com/en-us/ [Gitea]: https://img.shields.io/badge/Gitea-green?style=for-the-badge&logo=gitea&logoColor=white [Gitea-url]: https://about.gitea.com/ [Docker]: https://img.shields.io/badge/Docker-blue?style=for-the-badge&logo=docker&logoColor=white [Docker-url]: https://www.docker.com/