{"id":16573373,"url":"https://github.com/zoomoid/default-backend","last_synced_at":"2026-04-28T18:03:09.639Z","repository":{"id":109352363,"uuid":"420084032","full_name":"zoomoid/default-backend","owner":"zoomoid","description":"Default backend for cluster ingress. Does nothing more than to look pretty and run quickly.","archived":false,"fork":false,"pushed_at":"2021-10-23T15:10:30.000Z","size":293,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-16T03:50:22.583Z","etag":null,"topics":["golang","ingress","kubernetes"],"latest_commit_sha":null,"homepage":"","language":"Go","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/zoomoid.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"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}},"created_at":"2021-10-22T12:07:50.000Z","updated_at":"2021-11-15T14:59:06.000Z","dependencies_parsed_at":null,"dependency_job_id":"c35c921b-0ecb-422c-b4fc-487fbc216474","html_url":"https://github.com/zoomoid/default-backend","commit_stats":{"total_commits":15,"total_committers":1,"mean_commits":15.0,"dds":0.0,"last_synced_commit":"d36ce3502724b5d9239848430da5d6ed29141005"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoomoid%2Fdefault-backend","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoomoid%2Fdefault-backend/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoomoid%2Fdefault-backend/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoomoid%2Fdefault-backend/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zoomoid","download_url":"https://codeload.github.com/zoomoid/default-backend/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242049052,"owners_count":20063501,"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","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":["golang","ingress","kubernetes"],"created_at":"2024-10-11T21:42:01.166Z","updated_at":"2026-04-28T18:03:04.578Z","avatar_url":"https://github.com/zoomoid.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# default-backend\n\nA default HTTP backend that is to be served from ingress controllers, preferably running on Kubernetes,\nor any other default HTTP backend, e.g., the fallback of an NGINX reverse proxy.\n\nIt looks like this:\n\n![light-theme](assets/demo.png)\n\nand even has a built-in, preference-detecting dark mode:\n\n![dark-theme](assets/demo-dark-mode.png)\n\nIt uses CSS's `@media (prefers-color-scheme: dark)` to switch between light and dark!\n\nIt also responds with an HTTP 404 on the root URL, making it a hard-fail backend instead of a soft-failure semantic 404 served with an HTTP 200 status code. This behaviour is up to preference though, it can be changed, see the section below.\n\n## Building\n\nThis is just your regular Golang app:\n\n```\n$ go mod download\n\n$ go build -o ./server\n\n$ ./server\n```\n\nor using Docker\n\n```\n$ docker build .\n```\n\nwhich will produce a small, handy, and easy to secure, distroless image (\u003chttps://github.com/GoogleContainerTools/distroless\u003e).\n\nIf you need a shell, build the alpine image using\n\n```\n$ docker build ./Dockerfile.debug\n```\n\n## Templating custom values\n\nThe website served here is highly customizable, thanks to `spf13/viper` and environment variables or configuration files.\nThe easiest way to customize might be ENV variables, so here are the keys and their defaults:\n\n```sh\nSTATIC_ASSETS_PATH=\"./public/\"\n\nPAGE_TITLE=\"Oops!\"\n\nTITLE=\"We'll be back shortly!\"\n\nIMAGE_ENABLED=true\nIMAGE_URL=\"public/asset.svg\"\n\nBODY=\"We are sorry for the inconvenience.\"\n\nCONTACT_ENABLED=true\nCONTACT_BODY=\"You can always reach us at \u003ca href=\\\"mailto:hello@example.org\\\"\u003ehello@example.org\u003c/a\u003e\"\n\nAUTHOR_ENABLED=true\nAUTHOR_NAME=\"example.org\"\nAUTHOR_URL=\"example.org\"\n\nDARK_THEME_ENABLED=true\n\nTEXT_COLOR=\"#2f2e41\"\nBACKGROUND_COLOR=\"#fff\"\n\nCUSTOM_CODE=false\nCUSTOM_HTML=\"\"\nCUSTOM_CSS=\"\"\n\nSTATUS_CODE=404\n```\n\nbut you can also do this by YAML, which is arguably a lot nicer looking:\n\n```yaml\nstaticAssetsPath: \"./public/\"\nstaticAssetsPrefix: \"/public/\"\npageTitle: \"Oops!\"\ntitle: \"We'll be back shortly!\"\nbody: \"We are sorry for the inconvenience.\"\nauthor:\n  enabled: true\n  name: \"example.org\"\n  url: \"example.org\"\nimage:\n  enabled: true\n  url: \"public/asset.svg\"\ncontact:\n  enabled: true\n  body: You can always reach us at \u003ca href=\"mailto:hello@example.org\"\u003ehello@example.org\u003c/a\u003e\ntheme:\n  textColor: \"#2f2e41\"\n  color: \"#fff\"\n  darkTheme:\n    enabled: true\nraw:\n  enabled: false\n  html: \"\"\n  css: \"\"\n```\n\nThis configmap gives you control over almost all aspects of the HTML page that is delivered to you. \nMost properties should be pretty self-explanatory, but note the `staticAssetsPath` property:\nthis is not relevant for the template itself but rather for the static file server that runs \nunderneath to serve the small image. By default, this runs under the prefix `/public`, but it \ncan be fully customized to fit your needs inside a container: When you mount files from a volume, \nmake sure to converge the mount path and the configured `staticAssetsPath` and the `staticAssetPrefix`\nproperty in case your image you'd like to serve your static assets from another location.\n\nThe dedicated mount point for a configmap file is `/etc/default-backend/config.yaml`. Do NOT mount into `/`,\nas the default configmap is located there and you MUST NOT replace it, as it serves as the kernel for the configuration.\n\n## Running the containers\n\nAs already mentioned, the default Dockerfile builds a distroless container, i.e., it has no shell you can access to perform\nany other operation than running the application. If you need a shell for whatever reason, e.g., patch something\nor plainly experiment, have a look at the `debug` tag: \u003chttps://github.com/zoomoid/default-backend/pkgs/container/default-backend%2Fdebug\u003e. It builds an alpine linux image that has a shell ready to go!\n\n## Usage with docker-compose\n\nThis is very straight-forward, just override the environment variables above from the docker-compose.yaml\nand you are good to go. Same goes with just running from docker (or any other container runtime for that matter),\njust override the respective environment variables\n\n## Usage with Kubernetes\n\nThis small little page is intended to be used as the ingress controller's default backend. For NGINX Ingress this\ncan be done at installation time, e.g., in the helm values file, setting\n\n```yaml\ndefaultBackend:\n  enabled: true\n  name: defaultbackend\n  image:\n    registry: ghcr.io\n    image: zoomoid/default-backend\n    tag: latest\n    pullPolicy: IfNotPresent\n    # nobody user -\u003e uid 65534\n    runAsUser: 65534\n    runAsNonRoot: true\n    readOnlyRootFilesystem: true\n    allowPrivilegeEscalation: false\n  ...\n```\n\nNote that for NGINX ingress, this deployment has [statically configured livenessProbes and readinessProbes\non `/healthz`](https://github.com/kubernetes/ingress-nginx/blob/8611ecb7c97ce286e2e171a7e6e6aa50d2398b0c/charts/ingress-nginx/templates/default-backend-deployment.yaml#L70). The server statically answers with HTTP 200 on this route.\n\nFor other ingress controllers you might have to deploy your own ingress and deployment for the default backend. Since Kubernetes \u003e= 1.18, this can be done with this bit of YAML. Note that your might want to add more specification to deployment, service, and ingress. In particular, handling TLS for this backend might get complicated if not properly done by your ingress controller or you provided a certificate in advance,\nas solutions like cert-manager require a predefined hostname to get certificates for.\n\n```yaml\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: default-backend\nspec:\n  selector:\n    matchLabels:\n      app.kubernetes.io/name: default-backend\n  template:\n    metadata:\n      labels:\n        app.kubernetes.io/name: default-backend\n    spec:\n      containers:\n        - name: default-backend\n          image: ghcr.io/zoomoid/default-backend:latest\n          ports:\n            - containerPort: 8080\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: default-backend\nspec:\n  selector:\n    app.kubernetes.io/name: default-backend\n  ports:\n    - port: 80\n      targetPort: 8080\n---\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n  name: default-backend\nspec:\n  backend:\n    service:\n      name: default-backend\n      port:\n        number: 80\n```\n\n### Configuration\n\nYou can override the default configuration with a configmap of your liking, see the above section on that, like this:\n\n```yaml\napiVersion: v1\nkind: ConfigMap\nmetadata: \n  name: default-backend-config\n  labels:\n    app.kubernetes.io/name: default-backend\ndata:\n  config.yaml: |-\n    ---\n    staticAssetsPath: \"./public/\"\n    staticAssetsPrefix: \"/public/\"\n    pageTitle: \"Oops!\"\n    title: \"We'll be back shortly!\"\n    body: \"We are sorry for the inconvenience.\"\n    author:\n      enabled: true\n      name: \"example.org\"\n      url: \"example.org\"\n    image:\n      enabled: true\n      url: \"public/asset.svg\"\n    contact: \n      enabled: true \n      body: You can always reach us at \u003ca href=\"mailto:hello@example.org\"\u003ehello@example.org\u003c/a\u003e\n    theme:\n      textColor: \"#2f2e41\"\n      color: \"#fff\"\n      darkTheme:\n        enabled: true\n    customCode:\n      enabled: false\n      html: \"\"\n      css: \"\"\n```\n\nor by directly overriding the above specified ENV variables from either a configmap or directly inside the deployment spec.\nYou can mount the configmap from above into a file like this:\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: default-backend\nspec:\n  selector:\n    matchLabels:\n      app.kubernetes.io/name: default-backend\n  template:\n    metadata:\n      labels:\n        app.kubernetes.io/name: default-backend\n    spec:\n      containers:\n        - name: default-backend\n          image: ghcr.io/zoomoid/default-backend:latest\n          ports:\n            - containerPort: 8080\n          volumeMounts:\n            - name: configmap\n              mountPath: /etc/default-backend\n      volumes:\n        - name: configmap\n          configMap:\n            name: default-backend-config\n            items:\n              - key: config.yaml\n                path: config.yaml\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzoomoid%2Fdefault-backend","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzoomoid%2Fdefault-backend","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzoomoid%2Fdefault-backend/lists"}