yum upgrades for production use, this is the repository for you.
Active subscription is required.
Transform Markdown files into beautifully rendered HTML pages on-the-fly with the NGINX Markdown module. This powerful filter module eliminates preprocessing steps, enabling you to serve documentation sites, wikis, and blogs directly from .md files with full SEO support through YAML front matter parsing.
Why Use the NGINX Markdown Module?
Traditional documentation workflows require a build step to convert Markdown to HTML before deployment. This creates friction in development cycles and complicates content updates. The NGINX Markdown module solves this problem by converting Markdown to HTML at request time, directly within NGINX.
Key benefits include:
- Zero build steps – Deploy Markdown files directly, no static site generator needed
- Dynamic SEO metadata – Extract titles, descriptions, and keywords from YAML front matter
- GitHub Flavored Markdown – Full support for tables, task lists, strikethrough, and autolinks
- Custom templates – Wrap content in your own HTML templates with placeholder substitution
- Proxy support – Convert Markdown from upstream servers, not just local files
- Security controls – Choose between strict, filtered, or unrestricted HTML passthrough
How the NGINX Markdown Module Works
The module operates as an NGINX output filter, intercepting responses before they reach the client. When a request matches a location with markdown_filter on, the module:
- Parses YAML front matter (if enabled) – Extracts metadata like
title,description, and custom fields - Converts Markdown to HTML – Uses the robust cmark-gfm library (GitHub’s CommonMark implementation)
- Applies template substitution – Replaces
{{placeholders}}in your HTML template with front matter values - Sets correct headers – Automatically sets
Content-Type: text/html;charset=utf-8
The conversion happens entirely in memory with no disk I/O beyond reading the source file. This makes it efficient for production use.
Installing the NGINX Markdown Module
The module is available through the GetPageSpeed repository for both RHEL-based and Debian/Ubuntu systems.
RHEL, CentOS, AlmaLinux, Rocky Linux
sudo dnf install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf install nginx-module-markdown
Then load the module in your nginx.conf (add at the very top, before the events block):
load_module modules/ngx_markdown_filter_module.so;
Debian and Ubuntu
First, set up the GetPageSpeed APT repository, then install:
sudo apt-get update
sudo apt-get install nginx-module-markdown
On Debian/Ubuntu, the package handles module loading automatically. No
load_moduledirective is needed.
Verifying Installation
Confirm the module is loaded by checking for its directives:
strings /usr/lib64/nginx/modules/ngx_markdown_filter_module.so | grep markdown_
You should see output listing all available directives like markdown_filter, markdown_template, etc.
Configuration Directives Reference
The NGINX Markdown module provides eight directives, all valid only in location context:
| Directive | Default | Description |
|---|---|---|
markdown_filter |
off |
Enable Markdown to HTML conversion |
markdown_template |
— | Path to HTML template file |
markdown_front_matter |
off |
Parse YAML front matter for placeholder substitution |
markdown_unsafe |
off |
Allow raw HTML passthrough in Markdown |
markdown_gfm_tagfilter |
off |
Filter dangerous HTML tags (script, iframe, style, etc.) |
markdown_gfm_tasklist |
off |
Enable - [ ] / - [x] checkbox syntax |
markdown_gfm_strikethrough |
off |
Enable ~~strikethrough~~ syntax |
markdown_gfm_autolink |
off |
Auto-link bare URLs and email addresses |
Understanding the Directives
markdown_filter – The master switch. Set to on to enable conversion for matching requests.
markdown_template – Specifies an HTML template file. Templates use {{placeholder}} syntax for dynamic content. The special {{content}} placeholder marks where converted Markdown appears.
markdown_front_matter – When enabled, parses YAML between --- markers at the start of Markdown files. Extracted values become available as template placeholders.
markdown_unsafe – By default, raw HTML in Markdown is escaped (shown as <!-- raw HTML omitted -->). Enable this to allow HTML passthrough. Use with caution – consider combining with markdown_gfm_tagfilter.
markdown_gfm_tagfilter – When markdown_unsafe is on, this filters dangerous tags. It removes <script>, <iframe>, <style>, <textarea>, <title>, and <xmp>. Safe HTML like <strong> and <em> passes through.
markdown_gfm_tasklist – Converts - [ ] Todo and - [x] Done into HTML checkboxes.
markdown_gfm_strikethrough – Converts ~~deleted text~~ into <del>deleted text</del>.
markdown_gfm_autolink – Converts bare URLs and email addresses into clickable links.
Basic Configuration Example
The simplest configuration converts all .md files to HTML:
server {
listen 80;
server_name docs.example.com;
root /var/www/docs;
location ~ \.md$ {
markdown_filter on;
}
}
With this configuration, requesting /guide.md serves the Markdown content as HTML with proper text/html content type.
Using Templates for Professional Documentation
Templates transform raw HTML output into complete, styled pages. Create a template file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{title}}</title>
<meta name="description" content="{{meta.description}}">
<meta name="keywords" content="{{meta.keywords}}">
<link rel="stylesheet" href="/css/docs.css">
</head>
<body>
<nav><!-- Your navigation here --></nav>
<main class="content">
{{content}}
</main>
<footer><!-- Your footer here --></footer>
</body>
</html>
Configure NGINX to use this template:
location ~ \.md$ {
markdown_filter on;
markdown_front_matter on;
markdown_template /etc/nginx/templates/docs.html;
}
YAML Front Matter for SEO
Front matter provides metadata for SEO and template customization. Place YAML between --- markers at the start of your Markdown file:
---
title: Getting Started Guide
meta:
description: Learn how to install and configure the NGINX Markdown module
keywords: nginx, markdown, documentation, tutorial
robots: index, follow
author: Documentation Team
---
# Getting Started
Your content here...
Front Matter Features
- Nested keys – Access with dot notation:
{{meta.description}} - Automatic quote stripping – Values like
"quoted string"render without quotes - Graceful fallback – Missing placeholders render as empty strings
- Backward compatible – Files without front matter work normally
GitHub Flavored Markdown Features
Enable GFM extensions for modern Markdown syntax:
location ~ \.md$ {
markdown_filter on;
markdown_front_matter on;
markdown_template /etc/nginx/templates/docs.html;
markdown_gfm_strikethrough on;
markdown_gfm_tasklist on;
markdown_gfm_autolink on;
markdown_gfm_tagfilter on;
}
GFM Extension Examples
Tables (always enabled):
| Feature | Status |
|---------|--------|
| Tables | ✓ |
| Task Lists | ✓ |
Task Lists (markdown_gfm_tasklist on):
- [x] Install NGINX
- [x] Install markdown module
- [ ] Deploy to production
Strikethrough (markdown_gfm_strikethrough on):
~~deprecated feature~~ replaced with new implementation
Autolinks (markdown_gfm_autolink on):
Visit https://www.getpagespeed.com for more modules.
Contact us at support@example.com
Security Best Practices
The module provides three security levels for handling raw HTML in Markdown. This is similar to how the NGINX security headers module protects against XSS attacks.
Strict Mode (Default – Most Secure)
Raw HTML is escaped and shown as comments:
location ~ \.md$ {
markdown_filter on;
# markdown_unsafe is off by default
}
Input: <script>alert("xss")</script>
Output: <!-- raw HTML omitted -->
Filtered Mode (Balanced)
Safe HTML allowed, dangerous tags filtered:
location ~ \.md$ {
markdown_filter on;
markdown_unsafe on;
markdown_gfm_tagfilter on;
}
Input: <strong>Bold</strong> and <script>alert("xss")</script>
Output: <strong>Bold</strong> and (script tag removed entirely)
Unrestricted Mode (Use with Caution)
All HTML passes through – only use for trusted content:
location ~ \.md$ {
markdown_filter on;
markdown_unsafe on;
# NO tagfilter - dangerous!
}
Warning: Never enable unrestricted mode for user-contributed content. Always use
markdown_gfm_tagfilter onwhen accepting untrusted Markdown.
Working with Proxy and Upstream Servers
The module works seamlessly with proxied content, enabling headless CMS workflows. For optimal performance with proxied content, consider combining with NGINX caching strategies:
location /blog/ {
proxy_pass http://cms-backend;
markdown_filter on;
markdown_front_matter on;
markdown_template /etc/nginx/templates/blog.html;
}
This configuration fetches Markdown from your CMS backend and converts it to HTML before serving to clients.
Performance Considerations
The NGINX Markdown module is designed for production use with minimal overhead:
- In-memory conversion – No temporary files or disk I/O beyond reading source
- Static linking – The cmark-gfm library is statically linked, eliminating runtime dependencies
- Template caching – Templates are parsed at configuration time, not per-request
- Streaming processing – Content is processed as it arrives, minimizing memory usage
For high-traffic documentation sites, consider adding caching:
location ~ \.md$ {
markdown_filter on;
markdown_front_matter on;
markdown_template /etc/nginx/templates/docs.html;
# Cache converted output
proxy_cache_valid 200 1h;
add_header X-Cache-Status $upstream_cache_status;
}
Troubleshooting Common Issues
Module Not Loading
If NGINX fails to start after adding load_module:
# Check if module file exists
ls -la /usr/lib64/nginx/modules/ngx_markdown_filter_module.so
# Verify NGINX version matches module version
nginx -v
rpm -q nginx-module-markdown
403 Forbidden on Markdown Files
SELinux may block access. Fix with:
chcon -Rt httpd_sys_content_t /path/to/markdown/files/
restorecon -Rv /path/to/markdown/files/
Template Placeholders Not Substituted
Ensure markdown_front_matter on is set and your Markdown file has valid YAML front matter:
---
title: My Title
---
Content here...
Raw HTML Not Rendering
By default, raw HTML is escaped. Enable with:
markdown_unsafe on;
Configuration Changes Not Taking Effect
The module caches template and extension settings at startup. If changes don’t appear after nginx -s reload, perform a full restart:
systemctl stop nginx
systemctl start nginx
This ensures all module state is reinitialized with the new configuration.
Complete Production Configuration
Here’s a production-ready configuration for a documentation site:
server {
listen 80;
listen 443 ssl;
server_name docs.example.com;
root /var/www/docs;
ssl_certificate /etc/letsencrypt/live/docs.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/docs.example.com/privkey.pem;
# Redirect HTTP to HTTPS
if ($scheme = http) {
return 301 https://$host$request_uri;
}
# Serve Markdown as HTML
location ~ \.md$ {
markdown_filter on;
markdown_front_matter on;
markdown_template /etc/nginx/templates/docs.html;
markdown_gfm_strikethrough on;
markdown_gfm_tasklist on;
markdown_gfm_autolink on;
markdown_gfm_tagfilter on;
# Security headers
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
}
# Static assets
location /css/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
Conclusion
The NGINX Markdown module transforms how you serve documentation, blogs, and content sites. By eliminating build steps and enabling real-time conversion, you can focus on writing content.
Key takeaways:
- Install from GetPageSpeed repository with a single
dnf installcommand - Use templates with YAML front matter for SEO-optimized pages
- Enable GFM extensions for modern Markdown features
- Apply appropriate security settings based on your content trust level
For more information, see the module documentation and GitHub repository.
