Compare commits

...

6 Commits

Author SHA1 Message Date
Sven Vogel 9733bd2f07 bind address can be configured by environment variables 2023-11-24 23:42:32 +01:00
Sven Vogel 6e2f5d4b1a added Makefile 2023-11-24 23:42:14 +01:00
Sven Vogel f55717de17 added dockerfile 2023-11-24 23:42:05 +01:00
Sven Vogel 9912389ea7 completed go rewrite 2023-11-24 23:22:19 +01:00
Sven Vogel 6cc60cdd16 initialized go project 2023-11-24 20:00:35 +01:00
Sven Vogel c80e13b2e0 removed php files 2023-11-24 18:59:48 +01:00
14 changed files with 131 additions and 164 deletions

View File

@ -1,10 +1,13 @@
FROM erseco/alpine-php-webserver
LABEL maintainer="Sven Vogel <sven.vogel123@web.de>"
LABEL version="1.0.1"
FROM golang:1.20-alpine
WORKDIR /usr/src/app
COPY php/index-inlined-minified.php /var/www/html/index.php
COPY php/messages.php /var/www/html/messages.php
COPY nginx.conf /etc/nginx
# pre-copy/cache go.mod for pre-downloading dependencies and only redownloading them in subsequent builds if they change
COPY go.mod index-inlined-minified.html main.go ./
RUN go mod download && go mod verify
# Let runit start nginx & php-fpm
CMD [ "/bin/docker-entrypoint.sh" ]
RUN go build -v -o /usr/local/bin/app ./...
ENV PORT=8000
ENV BIND=0.0.0.0
CMD ["app"]

12
Makefile Normal file
View File

@ -0,0 +1,12 @@
compile-web:
cd web && inliner page.html > ../index-inlined-minified.html
run:
go run .
docker-build:
docker build -t errorpages .
docker-run:
docker run -itd --rm -p 8000:8000 -e BIND="0.0.0.0" -e PORT="8000" --name errorpages errorpages

View File

@ -3,7 +3,8 @@
"go",
"gopls",
"nodejs",
"nodePackages.vscode-html-languageserver-bin"
"nodePackages.vscode-html-languageserver-bin",
"nodePackages.inliner"
],
"nixpkgs": {
"commit": "f80ac848e3d6f0c12c52758c0f25c10c97ca3b62"

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module Homelab/Errorpages
go 1.19

File diff suppressed because one or more lines are too long

92
main.go Normal file
View File

@ -0,0 +1,92 @@
package main
import (
"errors"
"fmt"
"html/template"
"log"
"net/http"
"os"
"strconv"
)
type StatusData struct {
Code string
Message string
Response int
}
var Statuses = map[string]string{
"401": "You are not authorized to access the resource",
"404": "The requested resource couldn't be found",
"403": "Access to the resource was denied for the server",
"405": "Method not supported by the server",
"407": "You are no authorized to access the resource",
"408": "Request timed out",
"410": "The requested content is permanently gone",
"414": "Requested URI is too long",
"415": "Unsupported media type",
"500": "The server encountered an internal error",
"501": "Method not supported by the server",
"502": "Requested endpoint encountered an error",
"503": "Service is currently unavailable",
"504": "Requested endpoint is unreachable",
"505": "Protocol version not supported",
"511": "Requested endpoint requires authentication for proxy",
}
func isStatusCode(code string) (int, error) {
num, err := strconv.Atoi(code)
if err != nil {
return 500, errors.New("not a number")
}
if num > 99 && num < 512 {
return num, nil
}
return 500, errors.New("Invalid range")
}
func genStatus(request string) StatusData {
// create and init page status
var status StatusData
status.Code = "500"
status.Message = fmt.Sprintf("Invalid error response code recieved: %.5s[..]", request)
status.Response = 500
// check if we have a valid status code
var code, err = isStatusCode(request)
if err == nil {
status.Code = request
status.Message = fmt.Sprintf("Interrupted unsupported error response: %s", request)
status.Response = code
}
// set custom status message if present
description, ok := Statuses[request]
if ok {
status.Message = description
}
return status
}
func main() {
// load template
tmpl, err := template.ParseFiles("index-inlined-minified.html")
if err != nil {
log.Fatal(err)
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
status := genStatus(r.URL.Path[1:])
// set status code to propagate http error code
w.WriteHeader(status.Response)
tmpl.Execute(w, status)
})
var address = fmt.Sprintf("%s:%s", os.Getenv("BIND"), os.Getenv("PORT"))
log.Fatal(http.ListenAndServe(address, nil))
}

View File

@ -1,104 +0,0 @@
worker_processes 1;
error_log stderr warn;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
# Define custom log format to include reponse times
log_format main_timed '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'$request_time $upstream_response_time $pipe $upstream_cache_status';
access_log /dev/stdout main_timed;
error_log /dev/stderr notice;
keepalive_timeout 65;
# Write temporary files to /tmp so they can be created as a non-privileged user
client_body_temp_path /tmp/client_temp;
proxy_temp_path /tmp/proxy_temp_path;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
# Default server definition
server {
listen 8080 default_server;
server_name _;
sendfile off;
# Increase proxy buffers for large requests
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
# Upload limit
client_max_body_size 2M;
client_body_buffer_size 128k;
root /var/www/html;
index index.php index.html;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to index.php
try_files $uri $uri/ /index.php?q=$uri&$args;
}
# Redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/lib/nginx/html;
}
# Pass the PHP scripts to PHP-FPM listening on 127.0.0.1:9000
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_index index.php;
fastcgi_intercept_errors off;
include fastcgi_params;
}
location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
expires 5d;
}
# Deny access to . files, for security
location ~ /\. {
log_not_found off;
deny all;
}
# Allow fpm ping and status from localhost
location ~ ^/(fpm-status|fpm-ping)$ {
access_log off;
allow 127.0.0.1;
deny all;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
}
}
# Include other server configs
include /etc/nginx/conf.d/*.conf;
gzip on;
gzip_proxied any;
gzip_types text/plain application/xml text/css text/js text/xml application/x-javascript text/javascript application/json application/xml+rss;
gzip_vary on;
gzip_disable "msie6";
}

View File

@ -1,35 +0,0 @@
<?php
const RESPONSES = [
// Currently supported responses
// See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#server_error_responses
401 => "You are not authorized to access the resource",
404 => "The requested resource couldn't be found",
403 => "Access to the resource was denied for the server",
405 => "Method not supported by the server",
407 => "You are no authorized to access the resource",
408 => "Request timed out",
500 => "The server encountered an internal error",
501 => "Method not supported by the server",
502 => "Requested endpoint encountered an error",
503 => "Service is currently unavailable",
504 => "Requested endpoint is unreachable",
511 => "Requested endpoint requires authentication for proxy",
];
function get_status_message($uri): array
{
$status = "501";
$message = "The received status is unsupported by this server: `" . substr($uri, 0, 10) . "`";
$int_code = 501;
$code = intval(trim(str_replace("/", "", $uri)));
if (key_exists($code, RESPONSES)) {
$int_code = $code;
$status = (string) $code;
$message = RESPONSES[$code];
}
return [$status, $message, $int_code];
}

View File

@ -163,4 +163,4 @@ div {
100% {
background-position: calc(100% + 8rem) 0;
}
}
}

View File

@ -1,11 +1,3 @@
<?php
include "messages.php";
global $response;
$response = get_status_message($_SERVER["REQUEST_URI"]);
http_response_code($response[2]);
?>
<!doctype html>
<html lang="en">
<head>
@ -13,6 +5,7 @@ http_response_code($response[2]);
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="darkreader-lock"> <!-- Request dark reader to ignore this site. See: https://github.com/darkreader/darkreader/blob/main/CONTRIBUTING.md#disabling-dark-reader-on-your-site -->
<title>Montehaselino - Automatic Status Response</title>
<link href="master.css" rel="stylesheet"/>
</head>
@ -24,14 +17,15 @@ http_response_code($response[2]);
<img id="mountain" src="res/svg/error-page-overlay.svg" alt="">
<div id="rocks"></div>
<h1>ERROR</h1>
<?php
global $response;
echo "<h2>" . $response[0] ."</h2>";
echo "<h3>" . $response[1] . "</h3>";
?>
<h2>{{.Code}}</h2>
<h3>{{.Message}}</h3>
<a href="javascript:window.history.back();">Go Back</a>
<hr>
<div class="subtle">This is an automatically generated error response page.<br>Please contact administration if you feel this shouldn't be here.</div>
<div class="subtle">
This is an automatically generated error response page. <br>
Please contact administration if you feel this shouldn't be here.
</div>
</div>
</body>
</html>
</html>

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB