diff --git "a/docs/10_\360\237\223\221_Description.md" "b/docs/10_\360\237\223\221_Description.md" index 372e2f38a6168e613b1b932853b13353859d53a6..7fbf9f88e1518065a2ee47400586a90a1df6abfd 100644 --- "a/docs/10_\360\237\223\221_Description.md" +++ "b/docs/10_\360\237\223\221_Description.md" @@ -1,6 +1,19 @@ +## Why? + +At our institute we have about 50 domains for redirections only. +If all rewrite rules are inside wbserver definitions then no non-sysadmin would be able to get an overview over all redirect domains and their rules to point anywhere with what redirect code. + +All domains with redirects only point to the same web that executes the redirects. + +The redirects are handled in JSON files. So it can be put into a repository and can reproduce the history of changes. + +Next to the redirec functionality for the public web there is a web ui for showing all domains, redirects in a sortable, searchable table. Domains and redirects can be tested. + + + ## Requirements -* PHP 8 (up to PHP 8.3) +* PHP 8 (up to PHP 8.4) * Webserver (docs describe usage for Apache httpd) ## Features diff --git "a/docs/20_\342\226\266\357\270\217_Installation.md" "b/docs/20_\342\226\266\357\270\217_Installation.md" index 37b0e1ab2e027512d75931467406b3b74d0284ca..000ccd9d06cfd92a0263346a9f0a2cde87b4f67a 100644 --- "a/docs/20_\342\226\266\357\270\217_Installation.md" +++ "b/docs/20_\342\226\266\357\270\217_Installation.md" @@ -2,8 +2,16 @@ ### Get the files -The repository contains a subfolder *public_html*. Run `git clone` or extract the downloaded archive 1 level above webroot. The document root of the web must point -to the public_html directory. The config folder is outside the webroot. +The repository contains a subfolder *public_html*. Run `git clone` or extract the downloaded archive 1 level above webroot. + +In this example the software will be installed into a webroot `/var/www/links/public_html`: + +```shell +mkdir /var/www/ +git clone https://git-repo.iml.unibe.ch/iml-open-source/redirect-handler.git links +``` + +The document root of the web must point to the public_html directory. The config folder is outside the webroot. ```text . @@ -23,21 +31,89 @@ to the public_html directory. The config folder is outside the webroot. └── readme.md ``` -### Redirect all requests to index.php +### Webserver + +This is the basic idea how it works: + +* Create on or multiple vhosts with document root /var/www/links/public_html +* optional: one extra domain eg. links.example.com points to /var/www/links/public_html too - and is restricted with ip restriction, basic auth, whatever. + +#### Redirect all requests to index.php Redirect all requests to the index.php. Activate the .htaccess or (better) add the config to the vhost config. ```text -RewriteEngine On -RewriteBase / -RewriteCond %{REQUEST_FILENAME} !-f -RewriteCond %{REQUEST_FILENAME} !-d -RewriteRule ^.*$ /index.php [L] +<VirtualHost *:80> + ServerName redirects.example.com + ServerAlias www.redirect-domain-1.com ... www.redirect-domain-N.com + + DocumentRoot "/var/www/links/public_html" + ServerSignature Off + + ErrorLog "/var/log/apache2/links_error.log" + CustomLog "/var/log/apache2/links_access.log" combined + + # --- Allow access on webroot + <Directory "/var/www/links/public_html"> + Options -Indexes -FollowSymLinks -MultiViews + AllowOverride None + Require all granted + </Directory> + + ## Rewrite rules + RewriteEngine On + + RewriteRule ^(.*)$ index.php [QSA,L] + +</VirtualHost> ``` In the DNS point all hostnames with redirects only to this server (i.e. with a CNAME). -If you don't have a single vhost in the webserver then additionally add the -domains to "catch" as ServerAlias. +#### Web ui + +The web ui is a viewer only - no configuration can be changed. +It shows all domains, redirects and is helpful to keep an overview. + +This web points to the same document root - should be protected. In the example below is an ip restriction with an additional basic auth (snippet only). + +```text +<VirtualHost *:443> + ServerName links.example.com + DocumentRoot "/var/www/links/public_html" + ServerSignature Off + + ErrorLog "/var/log/apache2/links_error.log" + CustomLog "/var/log/apache2/links_access.log" combined + + # --- Allow access on webroot + <Directory "/var/www/links/public_html"> + Options -Indexes -FollowSymLinks -MultiViews + AllowOverride None + Require all granted + + <RequireAll> + # ip restriction: networks with access + <RequireAny> + Require ip 192.168.100.0/24 + Require ip 192.168.200.0/24 + </RequireAny> + + # and additional basic auth + Require valid-user + AuthType Basic + # ... basic auth config here + </RequireAll> + + </Directory> + + SSLEngine on + SSLCertificateFile "/etc/ssl/certs/links.example.com.fullchain.cer" + SSLCertificateKeyFile "/etc/ssl/certs/links.example.com.key.pem" + SSLCertificateChainFile "/etc/ssl/certs/links.example.com.fullchain.cer" + SSLCACertificatePath "/etc/ssl/certs" + +</VirtualHost> +``` \ No newline at end of file diff --git "a/docs/30_\342\232\231\357\270\217_Configuration.md" "b/docs/30_\342\232\231\357\270\217_Configuration.md" index 9045a308fd74ee3c2befba62caf6be3faa0789a0..cb6580c058bb023e3b507fdd9a849518c335d381 100644 --- "a/docs/30_\342\232\231\357\270\217_Configuration.md" +++ "b/docs/30_\342\232\231\357\270\217_Configuration.md" @@ -21,6 +21,8 @@ Let's start with an example for a `redirects_<FQDN>.json`: ```json { + "comment": "Example redirect web", + "httponly": true, "direct":{ "/heise": {"code": 307, "target": "https://www.heise.de" } }, @@ -33,10 +35,14 @@ Let's start with an example for a `redirects_<FQDN>.json`: } ``` -There are 2 required sections to define redirects: +The keys are -* direct -* regex +| Key | Type | comment | +| --- |--- | --- +| comment | string | optional: short description for this domain | +| httponly | bool | optional: flag if the redirects work on http only. Default: false (redirect definitions are the same for http and https) | +| direct | array | required: list of redirects with strings | +| regex | array | required: list of redirects with regex | The section "direct" will be scanned first and has priority. The json will be read into a hash ... if you define a direct rule twice then diff --git "a/docs/40_\360\237\226\245\357\270\217_Web_ui.md" "b/docs/40_\360\237\226\245\357\270\217_Web_ui.md" index c69d22a1be4209d3f63264bd8fdd9896b8b4b67c..5ee6e8be789841f82c8adca79087c5852e9715fb 100644 --- "a/docs/40_\360\237\226\245\357\270\217_Web_ui.md" +++ "b/docs/40_\360\237\226\245\357\270\217_Web_ui.md" @@ -25,7 +25,7 @@ In the table you see the columns * **Host** - the hostname/ FQDN that has a redirect rule * 🔷 Domain with config entries - * ◻️ Alias pointng to the config of another domain + * ▪️ Alias pointng to the config of another domain * **Ip address** - the found ip of the fqdn. * 🟢 green = domain is on the same ip like the redirect tool. * 🟠 yellow = domain is on another domain (= the config from here does not work because redirect is handled on another system) @@ -36,12 +36,22 @@ In the table you see the columns * **Code** - http response code for redirection * **Target** - target url -## Http header +### Test connection + +You can click a link to a hostname, a linked redirect or target url. In an overlay window you get the status for the http test. + +### Http header If click on the link of the host you get a live view of a response of a http HEAD request to the webroot of this domain. The redirects of the type "direct" have a linked "From" field value. If you click on it you get a live view of the http response header of `https://[Server]/[From]`. + + +If the connect failed there is no http response header to show. To get an idea what is wrong you get the curl error message. The you can estimate the problem - is it a missing DNS entry, a network problem, timeout, whatever. + + + ## Config If you click on the linked text "config" you get the content of the config file for this domain with all its redirects. diff --git a/docs/images/admin_ui.png b/docs/images/admin_ui.png index a7f9671a7a69da673f55571a7e127a94848f8b09..e3c36b2946632c22b21a9ee80a81e40b0022dde8 100644 Binary files a/docs/images/admin_ui.png and b/docs/images/admin_ui.png differ diff --git a/docs/images/admin_ui_box_connect_failed.png b/docs/images/admin_ui_box_connect_failed.png new file mode 100644 index 0000000000000000000000000000000000000000..c30be6b0137b6197e39a0364bb465da350567a41 Binary files /dev/null and b/docs/images/admin_ui_box_connect_failed.png differ diff --git a/docs/images/admin_ui_box_http_ok.png b/docs/images/admin_ui_box_http_ok.png new file mode 100644 index 0000000000000000000000000000000000000000..ea2e0c841d756ef3707abfd0c5a93a4494652577 Binary files /dev/null and b/docs/images/admin_ui_box_http_ok.png differ diff --git a/docs/style.css b/docs/style.css index 45383c3288f17a74d88fc2ffca48307f794d4592..90a0bc938f147608a1d4fd11952e4825f076862c 100644 --- a/docs/style.css +++ b/docs/style.css @@ -1,6 +1,6 @@ /* override css elements of daux.io blue theme - version 2023-11-10 + version 2024-10-31 */ :root { /* Axels Overrides */ @@ -8,22 +8,24 @@ --link-color: #228; --brand-color: var(--color-text); --brand-background: var(--body-background); - --code-tag-border-color: #d8d8d8; + --code-tag-background-color: #f0f3f3; + --code-tag-border-color: #dee; + --code-tag-box-shadow: none; --hr-color: none; + --pager-background-color: #f8fafa; + --pager-border-color: none; --search-field-background: none; --search-field-border-color: none; --sidebar-background: var(--body-background); --sidebar-border-color: none; - --sidebar-link-active-background: #e8f4f6; - --sidebar-link-active-background: #eee; + --sidebar-link-active-background: #f0f4f6; + --toc--inner-border-color: none; /* Axels custom values */ - --axel_bg-toc: var(--body-background); + --axel_bg-toc: #f8fafa; --axel_bg-toc-head: #f8f8f8; --axel_brand-background: none; --axel_brand-pre-background: rgb(255, 0, 51); - ; --axel_brand-pre-background-hover: rgb(255, 0, 51); - ; --axel_h1_header: none; --axel_h1: #111; --axel_h1-bg: none; @@ -34,12 +36,13 @@ --axel_h2-hero-bottom: 2px solid #912; --axel_h3: #333; --axel_h3-bottom: 0px solid #ddd; - --axel_h4: #444; - --axel_hero_bg: #f8f8f8; + --axel_h4: #666; + --axel_h5: #888; + --axel_hero_bg: #faf8f6; --axel_img-border: 2px dashed #ccc; --axel_nav-bg: #fcfcfc; --axel_nav-buttomborder: #ddd; - --axel_pre-background: #f8f8f8; + --axel_pre-background: #faf8f6; --axel-th-background: #e0e4e8; --axel-article-nav-border-top: 0px dotted #ddd; } @@ -58,6 +61,7 @@ --sidebar-background: var(--body-background); --sidebar-border-color: none; --sidebar-link-active-background: #333; + --sidebar-link-color: var(--link-color); /* Axels custom values */ --axel_bg-toc: var(--body-background); --axel_bg-toc-head: #333; @@ -76,6 +80,8 @@ --axel_h2-hero-bottom: 2px solid #712; --axel_h3: #589; --axel_h3-bottom: 0px solid #333; + --axel_h4: #478; + --axel_h5: #278; --axel_hero_bg: #242424; --axel_img-border: 2px dashed #555; --axel_nav-bg: #242424; @@ -122,7 +128,25 @@ a.Brand { /* ---------- page content ---------- */ .s-content { - padding-top: 1em; + padding-top: 6em; +} + +/** +h1::before{color: #aaa;content: 'h1: ';} +h2::before{color: #aaa;content: 'h2: ';} +h3::before{color: #aaa;content: 'h3: ';} +h4::before{color: #aaa;content: 'h4: ';} +h5::before{color: #aaa;content: 'h5: ';} +h6::before{color: #aaa;content: 'h6: ';} +*/ +h2::before{color: #888;content: ': : ';} +h3::before{color: #ccc;content: '> ';} +h4::before{color: #ccc;content: '_ ';} + +.s-content h1::before{ + color: #f00; + content: 'FEHLER: Keine Überschrift 1 in einer Markdown-Datei für Daux verwenden! Mit H2 beginnen!'; + content: '!! h1 !! '; } .s-content h1 { @@ -144,8 +168,14 @@ a.Brand { border-bottom: var(--axel_h2-bottom); } -h1:first-of-type { +.Page__header > h1:first-of-type { margin-top: 0em; + margin-left: -1em; + padding-left: 1em; + position: fixed; + min-width: 100%; + background: var(--body-background); + box-shadow: 0 2em 1em var(--body-background); } h2:first-of-type { @@ -170,6 +200,13 @@ img{ .s-content > h4 { color: var(--axel_h4); + font-size: 140%; + font-weight: bold; + margin: 2em 0; +} + +.s-content > h5 { + color: var(--axel_h5); font-size: 135%; font-weight: bold; margin: 2em 0; @@ -189,6 +226,8 @@ ul.TableOfContents a{ } .s-content pre { background: var(--axel_pre-background); + border-radius: 0.5em; + padding: 1rem; } /* FIX smaller fnt size in tables */ @@ -240,13 +279,6 @@ div.hero h2 { } /* ---------- TOC ---------- */ -@media(min-width:1700px) { - .TableOfContentsContainer { - position: fixed; - right: 2em; - top: 1em; - } -} .TableOfContentsContainer { background-color: var(--axel_bg-toc); @@ -256,14 +288,18 @@ div.hero h2 { .s-content .TableOfContentsContainer h4 { background-color: var(--axel_bg-toc-head); border-top-left-radius: 1em; + border-bottom: 2px solid var(--axel_bg-toc-bottom-border); font-size: 1.1em; margin: 0; - padding: 0; + padding: 0.3em; + display: none; } .TableOfContentsContainer__content { - border-width: 1px; + border-width: 0px; font-size: 0.5em; + height: inherit; + overflow: auto; } ul.TableOfContents ul { @@ -271,17 +307,27 @@ ul.TableOfContents ul { padding-left: 1em; } +.TableOfContents a:hover{ + text-decoration: underline; +} + +@media(min-width:1700px) { + .TableOfContentsContainer { + background: none; + position: fixed; + right: 2em; + top: 4em; + height: 90%; + } +} + /* ----- Icons on links --- */ .EditOn a::before{ content: '✏️ '; } -.Links a[href^="https://github.com/"]::before { - content: '🌐 '; -} - -.Links a[href^="https://git-repo.iml.unibe.ch/"]::before { +.Links a::before { content: '🌐 '; } diff --git a/readme.md b/readme.md index da271843ca6810186ea9b715a5dafc14612803c4..f03652a5f7c2a4647b42edde0113de3e76d658a0 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,7 @@ -# IML Redirect # +# IML Redirect -Redirect urls of any domain that points here. +Redirect tool for multiple domains (that point here). Author: Axel Hahn; Institute for Medical Education; University of Bern @@ -11,4 +11,16 @@ Author: Axel Hahn; Institute for Medical Education; University of Bern - - - - \ No newline at end of file +## Screenshots + +Admin web ui with all configured domains and their redirects: + + + +Urls, Redirects and target links can be tested. You see the http reponse header. Redirects will be highlighted. + + + +If a connection fails you get the curl error. + +