Go to file
2022-01-28 12:53:35 +05:00
.github Go templates support, XML, JSON, Ingress (#49) 2022-01-27 17:29:49 +05:00
cmd/error-pages Go templates support, XML, JSON, Ingress (#49) 2022-01-27 17:29:49 +05:00
internal Fix for the X-Format header (#51) 2022-01-28 12:53:35 +05:00
schemas Go templates support, XML, JSON, Ingress (#49) 2022-01-27 17:29:49 +05:00
templates Go templates support, XML, JSON, Ingress (#49) 2022-01-27 17:29:49 +05:00
test/hurl Fix for the X-Format header (#51) 2022-01-28 12:53:35 +05:00
.codecov.yml v2: App rewritten in Go (#25) 2021-09-29 20:38:50 +05:00
.dockerignore v2: App rewritten in Go (#25) 2021-09-29 20:38:50 +05:00
.editorconfig v2: App rewritten in Go (#25) 2021-09-29 20:38:50 +05:00
.gitignore Go templates support, XML, JSON, Ingress (#49) 2022-01-27 17:29:49 +05:00
.golangci.yml Flag --default-http-code for the serve subcommand added (#44) 2022-01-03 21:51:30 +05:00
CHANGELOG.md Go templates support, XML, JSON, Ingress (#49) 2022-01-27 17:29:49 +05:00
docker-compose.yml Go templates support, XML, JSON, Ingress (#49) 2022-01-27 17:29:49 +05:00
Dockerfile Go templates support, XML, JSON, Ingress (#49) 2022-01-27 17:29:49 +05:00
error-pages.yml Go templates support, XML, JSON, Ingress (#49) 2022-01-27 17:29:49 +05:00
go.mod Bump github.com/spf13/cobra from 1.2.1 to 1.3.0 (#43) 2022-01-02 07:25:37 +00:00
go.sum Bump github.com/spf13/cobra from 1.2.1 to 1.3.0 (#43) 2022-01-02 07:25:37 +00:00
LICENSE Basic repo files added 2020-07-08 16:12:21 +05:00
Makefile Go templates support, XML, JSON, Ingress (#49) 2022-01-27 17:29:49 +05:00
README.md Go templates support, XML, JSON, Ingress (#49) 2022-01-27 17:29:49 +05:00

HTTP's error pages

Release version Project language Build Status Release Status Coverage Image size License

One day you may want to replace the standard error pages of your HTTP server with something more original and pretty. That's what this repository was created for :) It contains:

  • Simple error pages generator, written on Go
  • Single-page error page templates with different designs (located in the templates directory)
  • Fast and lightweight HTTP server (written on Go also, with the FastHTTP under the hood)
  • HTTP server respects the Content-Type HTTP header (and X-Format) value and responds with the corresponding format
  • Already generated error pages (sources can be found here, the demonstration is always accessible here)
  • Lightweight docker image (~3.7Mb compressed size) with all the things described above
  • Ready to integrate with the Traefik and Ingress-nginx

Also, this project can be used for the Traefik error pages customization.

Installing

Download the latest binary file for your os/arch from the releases page or use our docker image:

Registry Image
Docker Hub tarampampam/error-pages
GitHub Container Registry ghcr.io/tarampampam/error-pages

Using the latest tag for the docker image is highly discouraged because of possible backward-incompatible changes during major upgrades. Please, use tags in X.Y.Z format

To watch the docker image content you can use the dive:

$ docker run --rm -it \
    -v "/var/run/docker.sock:/var/run/docker.sock:ro" \
    wagoodman/dive:latest \
      tarampampam/error-pages:latest
Dive screenshot

Templates

Name Preview
ghost ghost
l7-light l7-light
l7-dark l7-dark
shuffle shuffle
noise noise
hacker-terminal hacker-terminal
cats cats

Note: noise template highly uses the CPU, be careful

Usage

All the examples below will use a docker image with the application, but you can also use a binary. By the way, our docker image uses the unleveled user by default and distroless.

HTTP server

As mentioned above - our application can be run as an HTTP server. It only needs to specify the path to the configuration file (it does not need statically generated error pages). The server uses FastHTTP and stores all necessary data in memory - so it does not use the file system and very fast. Oh yes, the image with the app also contains a configured healthcheck and logs in JSON format :)

For the HTTP server running execute in your terminal:

$ docker run --rm \
    -p "8080:8080/tcp" \
    -e "TEMPLATE_NAME=random" \
    tarampampam/error-pages

And open http://127.0.0.1:8080/404.html in your favorite browser. Error pages are accessible by the following URLs: http://127.0.0.1:8080/{page_code}.html. Another way is to pass the needed error page code (and HTTP response code) using the HTTP header X-Code when requesting an index page.

Additionally, the server respects the Content-Type HTTP header (and X-Format) value and responds with the corresponding format instead of the HTML-formatted response only. The xml and json content types (formats) are allowed at this moment, and its format can be fully customized using a configuration file!

For the integration with ingress-nginx you can start the server with the flag --show-details (environment variable SHOW_DETAILS=true) - in this case, the error pages (json, xml responses too) will contain additional information that passed from the upstream reverse proxy!

Environment variable TEMPLATE_NAME should be used for the theme switching (supported templates are described below).

Cheat: you can use random (to use the randomized theme on server start) or i-said-random (to use the randomized template on each request)

To see the help run the following command:

$ docker run --rm tarampampam/error-pages serve --help
Generator

Create a config file (error-pages.yml) with the following content:

templates:
  - path: ./foo.html # Template name "foo" (same as file name),
                     # content located in the file "foo.html"
  - name: bar # Template name "bar", its content is described below:
    content: "Error {{ code }}: {{ message }} ({{ description }})"

pages:
  400:
    message: Bad Request
    description: The server did not understand the request

  401:
    message: Unauthorized
    description: The requested page needs a username and a password

Template file foo.html:

<html>
<title>{{ code }}</title>
<body>
    <h1>{{ message }}: {{ description }}</h1>
</body>
</html>

And run the generator:

$ docker run --rm \
    -v "$(pwd):/opt:rw" \
    -u "$(id -u):$(id -g)" \
    tarampampam/error-pages build --config-file ./error-pages.yml ./out

$ tree
.
├── error-pages.yml
├── foo.html
└── out
    ├── bar
    │   ├── 400.html
    │   └── 401.html
    └── foo
        ├── 400.html
        └── 401.html

3 directories, 6 files

$ cat ./out/foo/400.html
<html>
<title>400</title>
<body>
    <h1>Bad Request: The server did not understand the request</h1>
</body>
</html>

$ cat ./out/bar/400.html
Error 400: Bad Request (The server did not understand the request)

To see the usage help run the following command:

$ docker run --rm tarampampam/error-pages build --help
Static error pages

You may want to use the generated error pages somewhere else, and you can simply extract them from the docker image to your local directory for this purpose:

$ docker create --name error-pages tarampampam/error-pages
$ docker cp error-pages:/opt/html ./out
$ docker rm -f error-pages
$ ls ./out
ghost  hacker-terminal  index.html  l7-dark  l7-light  noise  shuffle
$ tree
.
└── out
    ├── ghost
    │   ├── 400.html
    │   ├── ...
    │   └── 505.html
    ├── hacker-terminal
    │   ├── 400.html
    │   ├── ...
    │   └── 505.html
    ├── index.html
    ├── l7-dark
    │   ├── 400.html
    │   ├── ...
    ...

Or inside another docker image:

FROM alpine:latest

COPY --from=tarampampam/error-pages /opt/html /error-pages

RUN ls -l /error-pages
$ docker build --rm .

...
Step 3/3 : RUN ls -l /error-pages
 ---> Running in 30095dc344a9
total 12
drwxr-xr-x    2 root     root           326 Sep 29 15:44 ghost
drwxr-xr-x    2 root     root           326 Sep 29 15:44 hacker-terminal
-rw-r--r--    1 root     root         11241 Sep 29 15:44 index.html
drwxr-xr-x    2 root     root           326 Sep 29 15:44 l7-dark
drwxr-xr-x    2 root     root           326 Sep 29 15:44 l7-light
drwxr-xr-x    2 root     root           326 Sep 29 15:44 noise
drwxr-xr-x    2 root     root           326 Sep 29 15:44 shuffle
Custom error pages for your image with nginx

You can build your own docker image with nginx and our error pages:

# File `nginx.conf`

server {
  listen      80;
  server_name localhost;

  error_page 401 /_error-pages/401.html;
  error_page 403 /_error-pages/403.html;
  error_page 404 /_error-pages/404.html;
  error_page 500 /_error-pages/500.html;
  error_page 502 /_error-pages/502.html;
  error_page 503 /_error-pages/503.html;

  location ^~ /_error-pages/ {
    internal;
    root /usr/share/nginx/errorpages;
  }

  location / {
    root  /usr/share/nginx/html;
    index index.html index.htm;
  }
}
# File `Dockerfile`

FROM nginx:1.23-alpine

COPY --chown=nginx \
     ./nginx.conf /etc/nginx/conf.d/default.conf
COPY --chown=nginx \
     --from=tarampampam/error-pages:2.3.0 \
     /opt/html/ghost /usr/share/nginx/errorpages/_error-pages
$ docker build --tag your-nginx:local -f ./Dockerfile .

More info about error_page directive can be found here.

Simple traefik (tested on v2.5.3) service configuration for usage in docker swarm (change with your needs):

version: '3.8'

services:
  error-pages:
    image: tarampampam/error-pages:2.3.0
    environment:
      TEMPLATE_NAME: l7-dark
    networks:
      - traefik-public
    deploy:
      placement:
        constraints:
          - node.role == worker
      labels:
        traefik.enable: true
        traefik.docker.network: traefik-public
        # use as "fallback" for any non-registered services (with priority below normal)
        traefik.http.routers.error-pages-router.rule: HostRegexp(`{host:.+}`)
        traefik.http.routers.error-pages-router.priority: 10
        # should say that all of your services work on https
        traefik.http.routers.error-pages-router.tls: 'true'
        traefik.http.routers.error-pages-router.entrypoints: https
        traefik.http.routers.error-pages-router.middlewares: error-pages-middleware
        traefik.http.services.error-pages-service.loadbalancer.server.port: 8080
        # "errors" middleware settings
        traefik.http.middlewares.error-pages-middleware.errors.status: 400-599
        traefik.http.middlewares.error-pages-middleware.errors.service: error-pages-service
        traefik.http.middlewares.error-pages-middleware.errors.query: /{status}.html

  any-another-http-service:
    image: nginx:alpine
    networks:
      - traefik-public
    deploy:
      placement:
        constraints:
          - node.role == worker
      labels:
        traefik.enable: true
        traefik.docker.network: traefik-public
        traefik.http.routers.another-service.rule: Host(`subdomain.example.com`)
        traefik.http.routers.another-service.tls: 'true'
        traefik.http.routers.another-service.entrypoints: https
        # next line is important
        traefik.http.routers.another-service.middlewares: error-pages-middleware
        traefik.http.services.another-service.loadbalancer.server.port: 80

networks:
  traefik-public:
    external: true

Docker-compose + Traefik

# docker-compose.yml
version: '3.8'

services:
  traefik:
    image: traefik:v2.5
    command:
      #- --log.level=DEBUG
      - --api.dashboard=true # activate dashboard
      - --api.insecure=true # enable the API in insecure mode
      - --providers.docker=true # enable Docker backend with default settings
      - --providers.docker.exposedbydefault=false # do not expose containers by default
      - --entrypoints.web.address=:80 # --entrypoints.<name>.address for ports, 80 (i.e., name = web)
    ports:
      - "80:80/tcp" # HTTP (web)
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    labels:
      traefik.enable: true
      # dashboard
      traefik.http.routers.traefik.rule: Host(`traefik.localtest.me`)
      traefik.http.routers.traefik.service: api@internal
      traefik.http.routers.traefik.entrypoints: web
      traefik.http.routers.traefik.middlewares: error-pages-middleware

  error-pages:
    image: tarampampam/error-pages:2.3.0
    environment:
      TEMPLATE_NAME: l7-dark # set the error pages template
    labels:
      traefik.enable: true
      # use as "fallback" for any NON-registered services (with priority below normal)
      traefik.http.routers.error-pages-router.rule: HostRegexp(`{host:.+}`)
      traefik.http.routers.error-pages-router.priority: 10
      # should say that all of your services work on https
      traefik.http.routers.error-pages-router.entrypoints: web
      traefik.http.routers.error-pages-router.middlewares: error-pages-middleware
      # "errors" middleware settings
      traefik.http.middlewares.error-pages-middleware.errors.status: 400-599
      traefik.http.middlewares.error-pages-middleware.errors.service: error-pages-service
      traefik.http.middlewares.error-pages-middleware.errors.query: /{status}.html
      # define service properties
      traefik.http.services.error-pages-service.loadbalancer.server.port: 8080
    depends_on:
      - traefik

  nginx-or-any-another-service:
    image: nginx:1.21-alpine
    labels:
      traefik.enable: true
      traefik.http.routers.test-service.rule: Host(`test.localtest.me`)
      traefik.http.routers.test-service.entrypoints: web
      traefik.http.routers.test-service.middlewares: error-pages-middleware

After executing docker-compose up you can:

Changes log

Release date Commits since latest release

Changes log can be found here.

Support

Issues Issues

If you will find any package errors, please, make an issue in current repository.

License

This is open-sourced software licensed under the MIT License.