Skip to content

Instantly share code, notes, and snippets.

@vietor
Last active February 18, 2024 19:44
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save vietor/7d604536c0493dc8de95d13ca4a4cce6 to your computer and use it in GitHub Desktop.
Save vietor/7d604536c0493dc8de95d13ca4a4cce6 to your computer and use it in GitHub Desktop.
Nginx render markdown by browser
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/milligram/1.4.1/milligram.min.css">
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/highlight.js/10.1.2/styles/github.min.css">
<script type="application/javascript" src="https://cdn.bootcdn.net/ajax/libs/marked/1.1.1/marked.min.js"></script>
<script type="application/javascript" src="https://cdn.bootcdn.net/ajax/libs/highlight.js/10.1.2/highlight.min.js"></script>
<style rel="stylesheet">
body {
color: #24292e;
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;
}
.container {
margin: 5rem auto;
padding: 4rem;
border: 1px solid #eaecef;
}
.container h1 {
padding-bottom: .3em;
border-bottom: 1px solid #eaecef;
}
code.error {
display: block;
padding: 2rem;
color: #F43;
font-size: 2rem;
line-height: 2rem;
}
</style>
<script>
marked.setOptions({
renderer: new marked.Renderer(),
highlight: function (code, lang) {
const validLanguage = hljs.getLanguage(lang) ? lang : 'plaintext';
return hljs.highlight(validLanguage, code).value;
}
});
const targetFile = location.pathname;
const modify = (t) => document.getElementById('content').innerHTML = t;
const request = fetch(targetFile, {headers: {'Accept': 'text/markdown'}}).then((res) => {
if (!res.ok)
throw new Error(`${res.statusText} (${res.status})`);
return res.text()
})
</script>
<script defer>
request.then((text) => modify(marked(text)))
.catch((err) => modify(`<code class="error">Failed to load ${targetFile}: ${err.message}</code>`))
</script>
</head>
<body>
<div class="container">
<div id="content" />
</div>
</body>
</html>
location = /__md_file {
internal;
allow all;
add_header 'Vary' 'Accept';
default_type text/html;
alias /data/www/md/md-renderer.html;
}
location = /md/md-renderer.html {
deny all;
}
location ~* \.md {
error_page 418 = /__md_file;
add_header 'Vary' 'Accept';
if (!-f $request_filename) {
break;
}
if ($http_accept !~* "text/markdown") {
return 418;
}
}
@markstos
Copy link

Thanks for this. In my fork, I added comments to explain what the Nginx file is doing: https://gist.github.com/markstos/a3275ba81585a9ced1e4f1263d95df59

If I'm reading it correctly, these Markdown pages that are rendered as HTML are returned with the non-standard 418 status code. Is that correct?

Returning a 200 seems desirable. According to the Nginx docs, that's possible with a syntax like this:

error_page 418 =200  /__md_file;

@vietor
Copy link
Author

vietor commented May 29, 2022

Return code 418 is what NGINX internally uses to route the raw markdown file or "md-renderer.html".

@markstos
Copy link

I see that, but isn't it also returned to the requesting user agent? The way I read the code, a 418 error page is being returned, so I presume an 418 status code is returned with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment