├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── Caddyfile
├── LICENSE
├── README.md
├── demo
├── another.md
├── index-html
│ └── index.html
├── index-md
│ └── index.md
├── index-txt
│ └── index.txt
├── index.md
├── media
│ └── photo.jpg
└── templates
├── justfile
├── screenshot.png
├── templates
├── axist.css
├── body-footer.html
├── body-header.html
├── error.html
├── head.html
├── index.html
└── site.css
└── test.ts
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on: [push]
3 | jobs:
4 | test:
5 | runs-on: ubuntu-latest
6 | steps:
7 | - name: Checkout
8 | uses: actions/checkout@v4
9 | - name: Download and install Caddy
10 | run: |
11 | wget --output-document caddy.deb --quiet https://github.com/caddyserver/caddy/releases/download/v2.7.6/caddy_2.7.6_linux_amd64.deb
12 | sudo dpkg -i caddy.deb
13 | - name: Download and install Deno
14 | run: |
15 | wget --output-document deno.zip --quiet https://github.com/denoland/deno/releases/download/v1.40.3/deno-x86_64-unknown-linux-gnu.zip
16 | unzip deno.zip deno
17 | sudo install deno /usr/local/bin/
18 | - name: Set up just
19 | uses: extractions/setup-just@v2
20 | - name: Run tests
21 | run: just test
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /Caddyfile.test
2 |
--------------------------------------------------------------------------------
/Caddyfile:
--------------------------------------------------------------------------------
1 | # https://github.com/dbohdan/caddy-markdown-site
2 | # Copyright (c) 2021, 2025 D. Bohdan.
3 | # License: MIT.
4 |
5 | http://localhost:8080 {
6 | root * demo
7 |
8 | encode gzip
9 |
10 | file_server
11 | templates
12 |
13 | @templates {
14 | path /templates/*
15 | not path /templates/*.css /templates/*.js
16 | }
17 | handle @templates {
18 | error 403
19 | }
20 |
21 | @markdown {
22 | path_regexp \.md$
23 | }
24 | handle @markdown {
25 | rewrite * /templates/index.html
26 | }
27 |
28 | @markdown_exists {
29 | file {path}.md
30 | }
31 | handle @markdown_exists {
32 | map {path} {caddy_markdown_site.append_to_path} {
33 | default extension
34 | }
35 | rewrite * /templates/index.html
36 | }
37 |
38 | handle_errors {
39 | file_server
40 | templates
41 |
42 | @markdown_index_exists_404 {
43 | file {path}/index.md
44 | expression `{http.error.status_code} == 404`
45 | }
46 | handle @markdown_index_exists_404 {
47 | map {path} {caddy_markdown_site.append_to_path} {
48 | default index
49 | }
50 | file_server {
51 | status 200
52 | }
53 | rewrite * /templates/index.html
54 | }
55 |
56 | handle {
57 | rewrite * /templates/error.html
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2021, 2024-2025 D. Bohdan and contributors
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # caddy-markdown-site
2 |
3 | This project is a proof of concept showing how you can serve Markdown files
4 | as reasonably good-looking minimal web pages
5 | with just the [Caddy](https://caddyserver.com/) web server.
6 | It is not a static site generator; there is no build step.
7 | The project consists of a Caddy configuration file (Caddyfile), HTML [templates](https://caddyserver.com/docs/caddyfile/directives/templates), and CSS files.
8 | You will need some knowledge of Caddy to use and customize the project.
9 | Expect a lot of work, and possibly insurmountable barriers, if you decide to adapt it for anything but a simple website.
10 |
11 |
12 | ## Screenshot
13 |
14 | 
15 |
16 |
17 | ## Requirements
18 |
19 | - Caddy 2.4 or later.
20 | - Optional:
21 | - [Deno](https://deno.land/) 1.31 or later to run the [tests](test.ts)
22 | (`just test`).
23 | - [entr](https://github.com/eradman/entr) for development
24 | (`just dev`).
25 | - [just](https://github.com/casey/just) to run the tasks.
26 |
27 |
28 | ## Features
29 |
30 | - If your page file is `demo/foo.md` and your domain example.com,
31 | you will be able to access the file as example.com/foo with no extension and example.com/foo.md.
32 | - `index.md` serves as the directory index (but `index.html` takes priority).
33 | - You can customize the look of your site without touching the main template.
34 | Edit `templates/{head,header,footer}.html` to do it.
35 | `head.html` links to the style sheets.
36 | - An error page is shown on error.
37 |
38 |
39 | ## Front matter
40 |
41 | Markdown page files can include Caddy template
42 | [front matter](https://caddyserver.com/docs/modules/http.handlers.templates#splitfrontmatter)
43 | in JSON, TOML, or YAML.
44 | The front matter sets variables that configure how a page is presented.
45 |
46 | The following variables are recognized:
47 |
48 | - `lang`: the [`lang`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang) HTML global attribute.
49 | If not specified, defaults to an empty string.
50 | - `text_dir`: the [`dir`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir) HTML global attribute.
51 | Defaults to `auto`.
52 | - `title`: The page title.
53 | Defaults to the request path.
54 |
55 | ### Example
56 |
57 | ```none
58 | ---
59 | lang: en
60 | title: Greeting
61 | ---
62 | Hello, world!
63 | ```
64 |
65 |
66 | ## License
67 |
68 | MIT.
69 |
70 | [`index.html`](templates/index.html) derives from the
71 | [`index.html` template](https://github.com/caddyserver/website/blob/1ff5103c73c921c8faa82ef3342d904a7f6a8e22/src/docs/index.html) used on the Caddy website.
72 |
73 | [`axist.css`](templates/axist.css) is [axist](https://github.com/ruanmartinelli/axist),
74 | a [classless](https://github.com/dbohdan/classless-css) CSS stylesheet.
75 |
76 | [`photo.jpg`](demo/media/photo.jpg) is by Siarhei Plashchynski
77 | [on Unsplash](https://unsplash.com/photos/6FmtLICCvxI).
78 |
79 | > Unsplash grants you an irrevocable, nonexclusive, worldwide copyright license
80 | > to download, copy, modify, distribute, perform, and use photos from Unsplash for free,
81 | > including for commercial purposes, without permission from or attributing the photographer or Unsplash.
82 | > This license does not include the right to compile photos from Unsplash
83 | > to replicate a similar or competing service.
84 |
--------------------------------------------------------------------------------
/demo/another.md:
--------------------------------------------------------------------------------
1 | # Another page
2 |
3 | How exciting.
4 |
5 | ```shell
6 | # This is a code block.
7 | echo 'Hello, world!'
8 | ```
9 |
--------------------------------------------------------------------------------
/demo/index-html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | HTML index
5 |
6 | {{ include "/templates/head.html" }}
7 |
8 |
9 |
10 |