Writing Technical Documentation (the Linux way)
Write and publish Linux technical documentation using Markdown, AsciiDoc, man pages, DocBook, pandoc, and MkDocs—with CI integration and practical examples.
Before you start
- ▸Basic command-line familiarity (file editing, running commands, make)
- ▸Git installed and a project repository to document
- ▸Python 3 and pip available for MkDocs installation
- ▸Ruby and gem available if using asciidoctor-pdf directly
Technical documentation is a first-class deliverable, not an afterthought. The Linux ecosystem has a rich tradition of plain-text documentation formats—each with distinct strengths—and a solid toolkit for converting, publishing, and maintaining them. Whether you are shipping a man page with your CLI tool, maintaining a project wiki, or producing a multi-format manual, the right format and toolchain matters. This guide covers the practical landscape: Markdown, AsciiDoc, man pages (troff/groff), DocBook's legacy, and the modern tooling that ties it all together.
Choosing the Right Format
Each format exists for a reason. Picking the wrong one creates friction later.
| Format | Best for | Output targets |
|---|---|---|
| Markdown | READMEs, wikis, lightweight docs sites | HTML, PDF (via pandoc) |
| AsciiDoc | Books, manuals, structured technical docs | HTML5, PDF, EPUB, man |
| troff/man | System man pages | Terminal, PostScript |
| DocBook XML | Enterprise documentation, standards bodies | HTML, PDF, man, EPUB |
| reStructuredText | Python projects, Sphinx-based docs | HTML, PDF, man |
For new projects, Markdown handles simple needs and AsciiDoc handles complex ones. Use troff only when you are writing man pages directly; everyone else should generate them from a higher-level format.
Markdown: Fast, Portable, and Everywhere
Markdown is the lingua franca of project documentation. Every major code forge renders it natively. Keep files in a docs/ directory alongside your source code.
Install CommonMark-compliant tooling
# Debian/Ubuntu
sudo apt install pandoc cmark
# Fedora/RHEL
sudo dnf install pandoc cmark
# Arch
sudo pacman -S pandoc cmark
Use CommonMark syntax rather than GitHub-Flavored Markdown when portability matters. Avoid raw HTML inside Markdown if the document will be processed by multiple renderers.
Linting Markdown
markdownlint-cli2 catches heading hierarchy errors, trailing whitespace, and inconsistent list style—the bugs that break rendered output silently.
npm install -g markdownlint-cli2
markdownlint-cli2 "docs/**/*.md"
AsciiDoc: Markdown Grown Up
AsciiDoc supports cross-references, includes, admonitions, tables with spanning cells, and conditional content—features Markdown simply does not have. The reference implementation is Asciidoctor, written in Ruby.
Install Asciidoctor
# Debian/Ubuntu
sudo apt install asciidoctor
# Fedora/RHEL
sudo dnf install asciidoctor
# Arch
sudo pacman -S asciidoctor
# Any distro, via RubyGems (latest version)
gem install asciidoctor asciidoctor-pdf
A minimal AsciiDoc document
cat > myproject.adoc <<'EOF'
= My Project Manual
Author Name <[email protected]>
v1.0, 2024-06-01
:toc:
:source-highlighter: rouge
== Installation
Clone the repository and run the installer.
[source,bash]
----
git clone https://example.com/myproject
cd myproject && sudo make install
----
== Configuration
See <<advanced,Advanced Options>> for tuning.
[[advanced]]
== Advanced Options
TBD.
EOF
# Render to HTML5
asciidoctor myproject.adoc
# Render to PDF
asciidoctor-pdf myproject.adoc
The :toc: attribute auto-generates a table of contents. Cross-references like <<advanced,Advanced Options>> are validated at build time—broken links fail loudly, unlike Markdown.
Writing Man Pages
Man pages use troff macros, specifically the mdoc (BSD-style, preferred for new pages) or man macro set. Writing raw troff is tedious. Use Asciidoctor or pandoc to generate them instead.
Generate a man page from AsciiDoc
cat > mytool.1.adoc <<'EOF'
= mytool(1)
Author Name
:doctype: manpage
:manmanual: User Commands
:mansource: mytool 1.0
== NAME
mytool - frobnicate the widgets
== SYNOPSIS
*mytool* [_OPTIONS_] _FILE_...
== DESCRIPTION
Processes each _FILE_ and applies widget frobnicating.
== OPTIONS
*-v*, *--verbose*::
Print verbose output.
== EXIT STATUS
*0*:: Success.
*1*:: General error.
== SEE ALSO
*grep*(1), *sed*(1)
EOF
asciidoctor -b manpage mytool.1.adoc -o mytool.1
# Verify it renders correctly
man ./mytool.1
Install the man page system-wide
sudo install -Dm644 mytool.1 /usr/local/share/man/man1/mytool.1
sudo mandb
Section numbers matter: 1 = user commands, 5 = file formats, 8 = sysadmin commands. Place the generated file in the matching manN/ directory.
DocBook: The Heritage Format
DocBook is XML-based and verbose by design. Most projects have moved away from writing DocBook directly, but it remains important as an intermediate format. Pandoc can read and write it; the Linux Documentation Project and many enterprise systems still produce DocBook. You will encounter it when maintaining legacy documentation or integrating with publishing pipelines that use DITA or DocBook stylesheets.
# Convert AsciiDoc to DocBook 5 XML
asciidoctor -b docbook5 myproject.adoc -o myproject.xml
# Convert DocBook XML to HTML using xsltproc and the docbook-xsl stylesheets
sudo apt install xsltproc docbook-xsl # Debian/Ubuntu
xsltproc /usr/share/xml/docbook/stylesheet/nwalsh/current/html/docbook.xsl \
myproject.xml > myproject.html
For new projects, treat DocBook as an output target, not an authoring format.
Pandoc: The Universal Converter
Pandoc converts between over 40 formats. It is the practical glue between authoring formats and output targets.
# Markdown → PDF (requires a LaTeX engine)
sudo apt install texlive-latex-base texlive-fonts-recommended # Debian/Ubuntu
pandoc README.md -o README.pdf
# Markdown → man page
pandoc README.md -s -t man -o README.1
# Markdown → EPUB
pandoc docs/*.md -o manual.epub --metadata title="My Manual"
# AsciiDoc → HTML (pandoc reads AsciiDoc since 2.11)
pandoc myproject.adoc -f asciidoc -t html5 -o myproject.html
Use a Makefile or shell script to codify your build steps so that anyone checking out the repository can reproduce the docs with a single command.
cat > Makefile <<'EOF'
.PHONY: docs clean
docs:
asciidoctor myproject.adoc
asciidoctor -b manpage mytool.1.adoc -o mytool.1
clean:
rm -f myproject.html mytool.1
EOF
MkDocs: Static Documentation Sites
MkDocs takes a directory of Markdown files and a YAML config and produces a navigable static site. It is the standard choice for project documentation hosted on GitHub Pages or any static host.
Install and initialize
pip install mkdocs mkdocs-material
mkdocs new myproject-docs
cd myproject-docs
The mkdocs-material theme is the de-facto standard: it is accessible, responsive, and has built-in search. Edit mkdocs.yml:
cat > mkdocs.yml <<'EOF'
site_name: My Project
theme:
name: material
nav:
- Home: index.md
- Installation: install.md
- Configuration: config.md
- Reference: reference.md
EOF
# Local live-reload server
mkdocs serve
# Build static output to site/
mkdocs build
# Deploy to GitHub Pages
mkdocs gh-deploy
Verification and CI Integration
Documentation that is not tested drifts. Add a CI step that builds your docs on every commit.
# .github/workflows/docs.yml skeleton (GitHub Actions)
cat > .github/workflows/docs.yml <<'EOF'
name: Docs
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: sudo apt-get install -y asciidoctor pandoc
- run: make docs
- run: pip install mkdocs mkdocs-material && mkdocs build --strict
EOF
The --strict flag makes MkDocs fail on warnings, including broken internal links. Treat documentation build failures the same as test failures.
Troubleshooting
- Pandoc PDF fails with LaTeX errors — Install
texlive-xetexand pass--pdf-engine=xelatex. The defaultpdflatexengine does not handle Unicode well. - Man page renders with literal asterisks — You have not compiled with
-b manpage; you are viewing the raw AsciiDoc source. Re-run the correct Asciidoctor command. - MkDocs broken links in
--strictmode — Internal links in MkDocs must use the file path (../config.md), not the rendered URL. Fix the link, not the strict flag. - asciidoctor-pdf missing fonts — Run
gem install rougeand ensure theNotofont family is installed, or switch to thedefaulttheme which uses bundled fonts. - mandb reports "whatis parse error" — The
NAMEsection of a man page must be exactly one line in the formatname - descriptionwith no markup. Fix the AsciiDoc source in the== NAMEblock.
Frequently asked questions
- Should I write man pages in raw troff or generate them?
- Generate them. Writing raw troff is error-prone and hard to maintain. Use Asciidoctor with doctype: manpage or pandoc's man output target; both produce correct, portable troff output.
- Is DocBook still relevant for new projects?
- Rarely as an authoring format, but yes as an intermediate or output format. Many enterprise publishing pipelines, the Linux Documentation Project, and DITA-based toolchains still consume DocBook XML, so knowing how to produce it from AsciiDoc or pandoc is useful.
- What is the difference between Asciidoc and AsciiDoc?
- AsciiDoc is the format; Asciidoctor is the current reference implementation in Ruby. The older Python-based 'asciidoc' processor still exists in some package repos but is largely unmaintained—use Asciidoctor for all new work.
- Can MkDocs produce PDF output?
- Not natively. Use mkdocs-with-pdf (a third-party plugin) or build PDF separately via pandoc or Asciidoctor and link to it as a downloadable artifact from your MkDocs site.
- How do I handle documentation for multiple versions of a project?
- Use mike, the MkDocs versioning plugin, which deploys each version to a separate subdirectory on your docs host and maintains a version switcher in the UI. For AsciiDoc-based projects, use the :revnumber: attribute and maintain version branches in git.
Related guides
Bash Loops: for, while and until
Learn all three Bash loop types — for, while, and until — with practical, copy-paste examples covering file iteration, counting, polling, and safe line reading.
Bash Scripting for Beginners
Learn Bash scripting from scratch: shebang lines, variables, conditionals, loops, and arguments, plus a real backup script to tie it all together.
C Pointers Explained
Understand C pointers from first principles: addresses, dereferencing, pointer arithmetic, arrays, common bugs like null dereferences and dangling pointers, and how to use ASan and Valgrind.
A C Programming Tutorial for Linux
Learn C on Linux from hello-world through gcc flags, header files, multi-file projects, make, and the standard library — with real commands and examples.