Rustmark

Rustmark is a simple Markdown server written in Rust. It is intended to be easy to use, easy to fork and customise, and easy to deploy.

Rustmark exists as a crate on crates.io to establish presence and gain visibility and awareness, and because there are plans for it to become useful as a binary. It is not intended to be used as a library, and is not published as such. (See the Usage section for more information.) It may also be useful to able to run it and see it working before then using it as a foundation for a new project.

The main sections in this README are:

Content

The entry point for reading the Markdown files is the index page. If you are here to read the content (for instance if you are using a Git system to preview the Markdown, such as GitHub or Gitea), start there.

An example showing available Markdown features is also provided, along with some Guidelines for use.

Features

The main high-level points of note are:

More details are available about the supported Markdown features, along with examples.

Authentication

Rustmark features Terracotta's custom-rolled authentication system, providing a basic session-based setup. However, it is highly recommended to store the user credentials securely in a database. That is currently outside the scope of this project, for a number of reasons, primarily the ambition to provide a simple system that can be extended to use any database required. You will probably also want to store the sessions in a database instead of in memory.

The authentication system is set up to make it easy to configure routes as either public or protected, and is fully-implemented including a login page, logout action, and handling of every part of the authentication journey and the possible situations.

Databases

Rustmark very purposefully does not include any kind of database integration. There are so many, and such a plethora of crates to choose from, that this is best left open. Database interaction is very straightforward and so this is a simple addition to make.

Why Rustmark?

The intention is to provide a simple system that is easy to maintain, and focused on developer documentation — or at least, documentation written by people who are comfortable working in Markdown with text editors, and committing their changes to a Git repository.

There are many tools available to provide wiki-style functionality in very friendly ways, the leading product (arguably) being Notion. Coda also deserves an honourable mention, but Confluence, although widely used due to the popularity of Jira, lags a long way behind.

So why not just use Notion?

Notion is a great product, with some excellent and powerful features, and it is also very easy to use. However, it does not feature any kind of approval process, meaning that it is all too easy for incorrect information to creep in — and the more pages there are to keep an eye on, the worse this problem becomes. Although Notion does have page edit history, and change alerts, it is not possible to require that changes are approved before they are published. Locking edit access is not really a solution, as it would prevent the very people who are most likely to need to make changes from doing so, and focus the work on a small number of specific people.

Therefore, the primary purpose of Rustmark is to provide a simple, easy-to-use system for publishing developer-focused documentation, with a simple approval process managed through standard Git pull requests. It is not intended to be a replacement for Notion, or any other wiki-style system, and it is quite likely best to use both in tandem, with Notion for general documentation and pages that non-techies need to edit.

If it works with Git server Markdown previewing, why not just use that?

Most Git server systems provide a Markdown preview feature, which is great for those people that have access to Git. But what if the documentation needs to be accessible to people who do not have access to the Git server? Although Rustmark is aimed at developers, that particular focus is in the context of editing. It also needs to be accessible to non-developers - plus, browsing pages on a Git server is not always the most user-friendly experience.

Additionally, this approach allows for a lot of flexibility in terms of styling and presentation, customisation, and hosting.

What about GitHub Pages?

GitHub Pages is a great way to host static content, and it is very easy to use. However, not everyone uses or wants to use GitHub, and there are constraints on the free accounts that may not make it the ideal choice for some people. There are also limitations on the amount of customisation that can be performed, and it is not possible to do anything dynamic, as ultimately it is based on Jekyll.

Why not Jekyll, or Hugo, or one of the other static site generators?

There are many, many static site generators available, and each has their pros and cons. Jekyll, being written in Ruby, is not very performant. Hugo is written in Go, and is very fast, but it is not the easiest to customise. Gatsby is written in JavaScript, and is very customisable, but it is also very complex, heavily dependent upon React, and requires a lot of dependencies. They are just some of the most popular and widely-known systems. mdBook is perhaps a close contender, and Rust-based, but it still has critical differences.

Each system has had key decisions made about it which differentiate it from the others. One key decision that Rustmark makes is to use Markdown files as the source of the content, but also to mantain compatibility with general Git server previewing. Most regular static site generators use some flavour of templating language, and those that use Markdown do not provide quite the same focus or features as Rustmark.

With Rustmark, it's possible to easily share things like README files between different repositories, without worrying about conversion or compatibility, which is a benefit for dev teams. Rustmark also has no JavaScript dependencies, and indeed hardly any JavaScript at all.

Additionally, there was a desire to write something in Rust!

Why run it as a server? Why not just generate static content?

It is totally possible to generate static content from the Markdown files, and then host that content on a static web server. If that is a requirement then the build output can be used directly, and there is then technically no need to run the server. Indeed, being able to do this in a more formal manner may end up being a feature of Rustmark.

However, there are three compelling reasons for running it as a server:

  1. It allows self-managed authentication, which can be extended as required in a way that is not possible with a static site alone (and HTTP auth is not exactly ideal).
  2. Everything is packaged up as one single binary, which is easy to deploy and run.
  3. It allows for dynamic content and features, such as search (not currently implemented), which is not possible with a static site. Rustmark provides a decent springboard for building a more complex system, if required.

Additionally, because Rustmark has a web sever built in, there is zero secondary setup required to get started. Just run the binary, and it works. Of course, some people will want to run it behind a reverse proxy, and that is also possible.

With everything being in one binary, isn't that a limiting factor?

Yes. Although, it has been tested with a repository containing over 10,000 Markdown files, which is 550MB of Markdown, and it works just fine. It is unlikely that many people will have a repository that large, and if they do, they probably have bigger problems to worry about!

Still, it is a valid concern, and it is something that may be addressed in the future, probably with a configuration setting to control whether everything is built into the binary or left externally to be deployed alongside it.

Usage

The Rustmark repository is designed so that it can be forked, and content added. As such, it is best to keep in line with the existing structure and intended usage, to make updates from the upstream repository easier to merge and apply.

Note that Rustmark is not designed to be used as a library, and its existence on crates.io is as a binary. This is to establish presence, but also there are plans for it to become useful in a standalone capacity without having to clone the full repository.

Getting started

The Rustmark repository is intended to be forked, although you may not want to do so in an explicit manner (i.e. by clicking the "Fork" button on GitHub). Instead, the recommended approach is to clone the repository, and then push it to a new location. This will give you a clone with all the commit history, but without the link to the upstream repository, so it will not be counted as a fork by GitHub. This is ideal if you want to add content and customise the application for your own use, and also want to be able to merge in Rustmark updates, but do not want to contribute back to the upstream repository.

Alternatively, you can use the repository as a template, and create a new repository based on it. The Rustmark repository is set up as a template repository on GitHub, so that you can easily click the "Use this template" button to create a new repository based on it. You can then clone your new repository and start working on it. This will give you a starting point where you have all the project files, but none of the commit history. This is beneficial if you want to make extensive changes to the project, and are not bothered about being able to merge in Rustmark updates.

Regarding forking and cloning, you should be aware of the following points:

For these reasons, forking in the GitHub-recognised sense is not recommended, and cloning and pushing to a new repository is the preferred route for standard use cases.

Structure

Rustmark is based on Terracotta, which is a web application template. This document focuses on Rustmark, but if you want to know more about the underlying application structure, you should refer to the Terracotta structure documentation.

Markdown files should be placed in the content directory, along with any images and other files that need to be protected by the same authentication as the rendered Markdown pages. Public images should be placed in the static/img path, and will be served from the /img URL path.

All of the content and static material is included in the compiled binary, making it very straightforward to deploy.

Customisation

If any customisations are required, they should be placed in the js/custom.js and css/custom.css files. These files are included after the default CSS and JavaScript, and so can be used to override the default behaviour. These files will not be modified when updating from the upstream repository.

Note that the custom.js file is only included in the rendered Markdown pages, once logged in, and not in the general system pages such as the login page. The custom.css file is included in all pages.

This document focuses on how to use and customise Rustmark, but if you are wanting to make more extensive changes, you should refer to the Terracotta documentation. You can also find information there about the coding standards used.

Setup

The steps to set up this project are simple and standard. You need a reasonably-recent Rust environment, on a Linux machine. There are currently no special requirements beyond what is needed to build a standard Rust project.

Note that these instructions are for building the application yourself, which will usually be in context of having created a new Rustmark project by cloning, forking, or possibly using the Rustmark repository as a template. In this case these steps will apply for your new project. You can also download the crate using cargo install rustmark, which will install the latest version of Rustmark from crates.io, but this currently is not particularly useful beyond letting you poke at the default, running application without having to clone the repository and build it yourself, to see if you like it. See the Getting started section for more information on creating a project using based on Rustmark.

Environment

There are some key points to note about the environment you choose:

Typically, you will set up Rust using rustup, which is the recommended way to install Rust. The stable toolchain is targeted, as the focus is on stability and correctness, rather than bleeding-edge features.

Once you have Rust installed, you can build the project using cargo build. This will download and compile all dependencies, and build the project. You can then run the project using cargo run.

Configuration

Rustmark is configured using a TOML file. The default configuration file is Config.toml, which should be placed in the same directory as the binary. The configuration settings (and file) are optional, and if not provided, Rustmark will use default values for all configuration options.

It is also possible to pass configuration parameters from the command line, as environment variables. The environment variables take precedence over the configuration file options.

Running

Rustmark can be run using the cargo run command, or by running the compiled binary directly. The server will listen on port 8000 by default, and will serve content from the markdown and static directories. The markdown directory contains the Markdown files to be rendered, and the static directory contains the static files to be served.

Testing

You can run the test suite using cargo test. This will run all unit and integration tests.

Note that, at present, there are no tests written specifically for this project, as it is mostly a combination of other crates from the Rust ecosystem. Tests might be added when the project is more mature and sensible things to test have been clearly identified.

Documentation

You can build the developer documentation using cargo doc. This will generate HTML files and place them into target/doc. You can then open the documentation in your browser by opening target/doc/rustmark/index.html.

Building the documentation for local development use will also provide you with links to the source code.

Deployment

You can build the project in release mode by using cargo build --release. Everything required for deployment will be contained in the single binary file produced. It is recommended to run upx on the executable before deployment, to reduce the file size.

The resulting binary file can then be copied to the deployment environment, and run directly. This will often be in a Docker or Kubernetes container, but that is outside the scope of this document.

A typical build script might look like this:

sh cargo build --release upx --best target/release/rustmark scp target/release/rustmark you@yourserver:/path/to/deployment/directory

Legal

Disclaimer

The name "Rustmark" is a combination of the words "Rust" and "Markdown". There is no affiliation with the Rust project or the Rust Foundation, nor any intent to imply any.

Attributions

This project uses the Rust logo as a default, due to being written in Rust. The logo is freely usable under the CC-BY (Creative Commons Attribution) license.

An image of Ferris the crab (the Rust mascot) is used to illustrate the Markdown content examples. This image is sourced from rustacean.net and is in the Public Domain, so can be freely used.

This project uses the Bulma CSS framework, which is published under the MIT license and free to use without restriction.

The Font Awesome icons are published under the CC-BY (Creative Commons Attribution) license, and the webfonts under the SIL OFL (Open Font License). They are freely usable, along with the CSS code used to display them, which is released under the MIT license.

The Twemoji graphics used to stylise Unicode emojis are published by Twitter under the CC-BY (Creative Commons Attribution) license, and are freely usable, along with the Twitter JavaScript code used to transform them, which is released under the MIT license.