{"id":33179006,"url":"https://github.com/codelev/millau","last_synced_at":"2025-11-20T21:03:10.589Z","repository":{"id":291393366,"uuid":"977472389","full_name":"codelev/millau","owner":"codelev","description":"Millau is a free ingress proxy and load balancer designed for microservice architectures built on Docker Swarm","archived":false,"fork":false,"pushed_at":"2025-11-13T18:04:59.000Z","size":603,"stargazers_count":27,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-13T20:11:08.877Z","etag":null,"topics":["docker","go","golang","ingress","load-balancer","proxy","swarm"],"latest_commit_sha":null,"homepage":"https://millau.net","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/codelev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":null,"patreon":"millau","open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":null}},"created_at":"2025-05-04T09:39:36.000Z","updated_at":"2025-11-13T18:05:03.000Z","dependencies_parsed_at":"2025-05-25T08:22:20.029Z","dependency_job_id":"1f075ff4-8527-45c3-8b63-ca2d9b1916dc","html_url":"https://github.com/codelev/millau","commit_stats":null,"previous_names":["codelev/millau"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/codelev/millau","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codelev%2Fmillau","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codelev%2Fmillau/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codelev%2Fmillau/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codelev%2Fmillau/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codelev","download_url":"https://codeload.github.com/codelev/millau/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codelev%2Fmillau/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":285511775,"owners_count":27184237,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-20T02:00:05.334Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","go","golang","ingress","load-balancer","proxy","swarm"],"created_at":"2025-11-16T03:00:36.817Z","updated_at":"2025-11-20T21:03:10.584Z","avatar_url":"https://github.com/codelev.png","language":"Java","funding_links":["https://patreon.com/millau","https://www.patreon.com/c/millau"],"categories":["容错组件"],"sub_categories":[],"readme":"# Millau\nMillau (pronounced _mijo_) is a free ingress proxy and load balancer designed for microservice architectures built on Docker Swarm.\n\n![Millau](setup.svg)\n\nTraditional proxies require configuration for each path and host, and must be restarted to apply changes. Modern proxies listen to Docker events and configure routes automatically. While traditional proxies store configuration files on mounted volumes, modern proxies store routes in memory. However, modern proxies do not support load balancing across services - Millau does.\n\nMillau\n- Listens to Docker events for zero restarts\n- Failover retries for guaranteed delivery\n- Written in Golang and available as a slim Docker image\n\n## Comparison\n\n| Product    | Configuration | Multi-service LB | Service discovery | Prometheus metrics | Automatic HTTPS | mTLS    | Image size, MB |\n|------------|---------------|------------------|-------------------|--------------------|-----------------|---------|----------------|\n| NGINX      | File          | Yes              | No                | No                 | No              | Yes     | 192            |\n| HAProxy    | File          | Yes              | No                | Yes                | No              | Yes     | 105            |\n| Envoy      | File          | Yes              | No                | Yes                | No              | Yes     | 191            |\n| Caddy      | File          | Yes              | No                | Yes                | Yes             | Yes     | 49             |\n| Traefik    | Labels        | No               | Yes               | Yes                | Yes             | Yes     | 224            |\n| **Millau** | **Labels**    | **Yes**          | **Yes**           | **Yes**            | **Yes**         | **Yes** | **33**         |\n\n## Performance\n\n| Product    | Test type                         | Avg response (ms) | Shortest response (ms) |\n|------------|-----------------------------------|-------------------|------------------------|\n| NGINX      | GET application/json              | 2.45              | 1.73                   |\n| HAProxy    | GET application/json              | 2.99              | 1.93                   |\n| Caddy      | GET application/json              | 2.80              | 1.66                   |\n| Traefik    | GET application/json              | 2.66              | 1.53                   |\n| **Millau** | GET application/json              | **2.76**          | **1.74**               |\n| NGINX      | POST application/octet-stream 5Mb | 32.24             | 29.27                  |\n| HAProxy    | POST application/octet-stream 5Mb | 23.12             | 20.69                  |\n| Caddy      | POST application/octet-stream 5Mb | 23.81             | 20.98                  |\n| Traefik    | POST application/octet-stream 5Mb | 23.35             | 21.04                  |\n| **Millau** | POST application/octet-stream 5Mb | **22.86**         | **20.53**              |\n\n## Quickstart\n\n1. Create `docker-compose.proxy.yml`:\n    ```dockerfile\n    services:\n      proxy:\n        image: codelev/millau:latest\n        volumes:\n          - /var/run/docker.sock:/var/run/docker.sock:ro\n        ports:\n          - \"8080:80\"\n        networks:\n          - millau\n    networks:\n      millau:\n        external: true\n    ```\n2. Create `docker-compose.service.yml`:\n    ```dockerfile\n    services:\n      whoami:\n        image: traefik/whoami\n        deploy:\n          mode: replicated\n          replicas: 3\n          labels:\n            - \"millau.enabled=true\"\n            - \"millau.port=80\"\n        ports:\n          - \"80\"\n        networks:\n          - millau\n    networks:\n      millau:\n        external: true\n    ```\n3. Create network: `docker network create --driver=overlay millau`\n4. Deploy proxy: `docker stack deploy -c docker-compose.proxy.yml proxy`\n5. Deploy service:  `docker stack deploy -c docker-compose.service.yml service`\n\n## Use Cases\n\n### Blue-Green\n\n```shell\ndocker stack deploy -c docker-compose.bluegreen.yml bluegreen\ncurl -i -H 'Host: company.com' localhost:8080/api/\n# HTTP 200 blue or green\ncurl -i -H 'Host: www.company.com' localhost:8080/api/\n# HTTP 200 blue or green\ncurl -i -H 'Host: green.local' localhost:8080/api/\n# HTTP 200 green\ncurl -i -H 'Host: blue.local' localhost:8080/api/\n# HTTP 200 blue\ncurl -i -H 'Host: company.locall' localhost:8080\n# HTTP 502 No matching services found\ncurl -i -H 'Host: company.local' localhost:8080/apii/\n# HTTP 502 No matching services found\ncurl -k --resolve company.local:8443:127.0.0.1 --connect-to company.local:8443 -H 'Host: company.local' https://company.local:8443/api/\n# HTTP 200 blue or green\ncurl -k --http2 --resolve company.local:8443:127.0.0.1 --connect-to company.local:8443 -H 'Host: company.local' https://company.local:8443/api/\n# HTTP 200 blue or green\ndocker stack rm bluegreen\n```\n\n### Ingress\n\n```shell\ndocker stack deploy -c docker-compose.ingress.yml ingress\ncurl -i localhost:8080\n# HTTP 200 backend\ndocker stack rm ingress\n```\n\n### Failover\n\n```shell\ndocker stack deploy -c docker-compose.failover.yml failover\ncurl localhost:8080/rest/echo\n# HTTP 200\ndocker stack rm failover\n```\n\n### Maintenance Mode\n\n```shell\ndocker stack deploy -c docker-compose.spa.yml spa\ncurl -H 'Host: company.com' localhost:8080\n# homepage\ndocker service scale spa_homepage=0\ncurl -H 'Host: company.com' localhost:8080\n# maintenance page\ndocker service scale spa_homepage=1\ncurl -H 'Host: company.com' localhost:8080\n# homepage\ndocker stack rm spa\n```\n\n### Docker Compose\n\n```shell\ndocker compose up -d\ncurl -i localhost:8080/rest/echo\n# HTTP 200\ncurl -k --resolve company.local:8443:127.0.0.1 --connect-to company.local:8443 https://company.local:8443/rest/echo\ncurl -k --http2 --resolve company.local:8443:127.0.0.1 --connect-to company.local:8443 https://company.local:8443/rest/echo\n# HTTP 200\ndocker compose down\n```\n\n## Telemetry\n\nMillau exposes the following endpoints on port `9100`:\n- Healthcheck `/`:\n    - responds `up` and `200 OK` when healthy,\n    - responds `down` and `503 Service Unavailable` when unhealthy.\n- Prometheus metrics `/metrics`:\n\n| Metric                                 | Description                                              |\n|----------------------------------------|----------------------------------------------------------|\n| **Ingress**                            |                                                          |\n| `millau_ingress_open_connections`      | The current count of open connections by port.           |\n| `millau_ingress_requests_total`        | The total count of requests received by port.            |\n| `millau_ingress_requests_bytes_total`  | The total size of requests in bytes handled by port.     |\n| `millau_ingress_responses_bytes_total` | The total size of responses in bytes handled by port.    |\n| **Load Balancer**                      |                                                          |\n| `millau_lb_successful_requests_total`  | The total count of requests handled by service.          |\n| `millau_lb_failed_requests_total`      | The total count of requests not handled by service.      |\n| `millau_lb_requests_bytes_total`       | The total size of requests in bytes handled by service.  |\n| `millau_lb_responses_bytes_total`      | The total size of responses in bytes handled by service. |\n| `millau_lb_retries_total`              | The count of retries made for service.                   |\n| `millau_lb_status`                     | Current service status, `0` for `down` or `1` for `up`.  |\n| `millau_lb_request_duration_seconds`   | Request handling histogram by service.                   |\n| `millau_topology`                      | Requests routed to services.                             |\n\nMillau has an official [Grafana dashboard](https://grafana.com/grafana/dashboards/23474-millau-ingress-proxy-and-load-balancer/).\nYou can try it out locally using the `docker-compose.yml`, which sets up Millau, Echo service, Prometheus and Grafana together.\n\n![Grafana](grafana-a.png)\n![Grafana](grafana-b.png)\n![Grafana](grafana-c.png)\n\nOnce the stack is running, log in Grafana at http://localhost:3000 with username `admin` and password `admin`.\nThe [millau.json](https://github.com/codelev/millau/tree/main/monitoring/millau.json) is already installed and ready to use.\n\n## Configuration\n\n### Logging Levels\n\n- **FATAL**: Indicates an unrecoverable error; the process will exit.\n- **ERROR**: Indicates a proxy failure; the process continues running.\n- **WARN**: Indicates client or microservice misbehavior; the process continues running.\n- **INFO**: Indicates normal functional behavior. Default level.\n- **DEBUG**: Indicates step‑by‑step functional behavior.\n\n ```dockerfile\n services:\n   proxy:\n     image: codelev/millau:latest\n      environment:\n        - LOGGING=DEBUG\n      ...\n ```\n\n### HTTP and HTTPS Ports\nBy default, the HTTP and HTTPS ports are `80` and `443`. You can change them as follows:\n\n ```dockerfile\n services:\n   proxy:\n     image: codelev/millau:latest\n      environment:\n        - HTTP=8080\n        - HTTPS=8443\n      ...\n ```\n\n### Automatic HTTPS\nBy default, ACME API is `https://api.buypass.com/acme/directory` (Buypass AS Certificate Authority, Norway). \nYou can change is as follows:\n\n ```dockerfile\n services:\n   proxy:\n     image: codelev/millau:latest\n      environment:\n        - ACME=https://acme-v02.api.letsencrypt.org/directory\n      ...\n ```\n\n### HTTP Host Matching\nThe matching logic selects the services whose `millau.hosts` label matches the domain hierarchy.\nIt prioritizes:\n- exact matches,\n- longest suffix.\n\n| Configured          | Requested       | Selected  |\n|---------------------|-----------------|-----------|\n| `one.com` `two.com` | `one.com`       | `one.com` |\n| `one.com` `two.com` | `www.two.com`   | `two.com` |\n| `one.com` `two.com` | `three.two.com` | `two.com` |\n| `one.com` `local`   | `blue.local`    | `local`   |\n| `*` `two.com`       | `two.com`       | `two.com` |\n| `*` `two.com`       | `one.com`       | `*`       |\n| `*` `*`             | `one.com`       | `*` `*`   |\n\n\n### HTTP Path Matching\nThe matching logic selects the services whose `millau.path` label matches the beginning of the request path. \nIt prioritizes:\n- exact matches,\n- longest prefix.\n\n| Configured                       | Requested          | Selected        |\n|----------------------------------|--------------------|-----------------|\n| `/api/` `/`                      | `/api/`            | `/api/`         |\n| `/api/` `/`                      | `/api`             | `/`             |\n| `/api/` `/`                      | `/file.html`       | `/`             |\n| `/api/` `/`                      | `/api/x`           | `/api/`         |\n| `/api/` `/`                      | `/api/x/`          | `/api/`         |\n| `/api/` `/`                      | `/api/x/file.html` | `/api/`         |\n| `/api/` `/` `/file.html`         | `/file.html`       | `/file.html`    |\n| `/file` `/api/` `/` `/file`      | `/file.html`       | `/file` `/file` |\n| `/api/` `/` `/file` `/file.html` | `/file.html`       | `/file.html`    |\n| `/api/` `/` `/api/`              | `/api/`            | `/api/` `/api/` |\n\n\n### Self-Signed TLS Certificate\nGenerates a base64-encoded certificate and private key:\n\n```shell\nopenssl genrsa -out company.local.key 2048\nopenssl req -new -key company.local.key -out company.local.csr\nopenssl x509 -req -days 365 -in company.local.csr -signkey company.local.key -out company.local.cert\nbase64 -w 0 company.local.key \u003e company.local.key.b64\nbase64 -w 0 company.local.cert \u003e company.local.cert.b64\n```\n\n### Free Commercial License\nAdding a license key to your Millau instance removes debugging information from HTTP traffic. You can get the license free of charge in a minute at https://millau.net/license and add it as follows:\n\n ```dockerfile\n services:\n   proxy:\n     image: codelev/millau:latest\n      environment:\n        - LICENSE=my-license-key\n      ...\n ```\n\n## Support\nThe license key also gives you access to support. Feel free to send a message or schedule a call at https://millau.net/support.\n\nPlease note that Millau is a non-commercial project, so constant availability isn't guaranteed. However, you're always welcome to report issues on GitHub https://github.com/codelev/millau/issues.\n\n## Contributing\nThere are three ways you can support Millau:\n1. Use Millau in your stack.\n2. Sponsor at https://www.patreon.com/c/millau\n3. Star this GitHub repository.\n\nEvery user, issued license, and star helps attract the attention of potential investors. The final goal is to raise €20,000 to establish Millau as the standard ingress proxy for Docker Swarm and release it under an open-source license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodelev%2Fmillau","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodelev%2Fmillau","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodelev%2Fmillau/lists"}