Techblog and Security


Perlite is a web based markdown viewer optimized for Obsidian Notes.

The idea behind this is that you don’t need to convert your Markdown files by yourself or with any script to HTML. The PHP engine analyzes the file structure „as is“. You can put your entire Obsidian vault or Markdown folder/file structure in your web directory and the page will build itself.

It is an open source alternative to obisidian publish. If you want to discuss Perlite, you can join the thread on the Obsidian Forum or join the Perlite Discord Server.


Download and installation instructions


Please use Github to reports bugs. To request or ask for a new feature you can use either the Obsidian Forum or create a new Issue on Github


In version 1.4 I introduced the Graph view, there is now a new sidebar on the right side, where the current graph and direct linked nodes will be displayed.

There is also a possibility to see the whole Graph of all nodes and links, keep in mind that if you have many nodes, loading the whole graph may take some time.

How it works

On visiting the index.php, the site will crawl recursive for all markdown (.md) files starting in the $rootDir. Based on the folder and files structure, the sidebar (left menu) will build up. By clicking a file, a request with the path of the file will be sent to content.php, this checks if this file is in the current folder structure, get the content and call the parsedown.php to convert the markdown to the html. Obsidian links and images will be replaced by valid html links and highlight.js will be called for the code highlighting.

How the graph works

To generate a graph like the above one, its necessary that the information (links) between the files comes from any reliable source, of course it is possible to crawl through each file and check if there is a link to another file, but this costs time and you need to do this for every single file at least after any change. Glad there is a community plugin which can provide us this information. The Metadata Extractor creates a metadata.json with all necessary information.

    "fileName": "Writeup",
    "relativePath": "WriteUps/HackTheBox/Sharp/",
    "backlinks": [
        "fileName": "main infos",
        "link": "Writeup",
        "relativePath": "WriteUps/HackTheBox/Sharp/main"
        "fileName": "Net Desirialization",
        "link": "Writeup",
        "relativePath": "OWASP and Web Attacks/Net",
        "displayText": "../../WriteUps/HackTheBox/Sharp/Writeup"

The PHP engine will read this file and checks for every provided „node“ if the relative path is really available in the actual file structure, if yes it will add it to a new json object. After all nodes are checked and maybe added, the parser will go through the file again to add the links for the newly added nodees. Finally the new json objects will be stored in the html and the javascript engine will handle all the filtering and options. Like only display the current node and direct links or hide nodes without links etc.

How to stage notes to Perlite

There a many different ways and at least this depends a little bit how you host your website. I sync my notes via Github. I push my vault and changes to a private Github repository, from there my web server pulls the data, this can be scheduled by a cron job.

  1. So, first create an account on Depending which OS you are running, install a corresponding GitHub client.
  2. Create and clone a private repository, where you will store your vault
  3. Create a new SSH Key for Read-only access in your repository settings

  1. On your Webserver you need at least a SSH Client, create a new config in /home/username/.ssh/config with the following content
        IdentitiesOnly yes
  1. store your private key in the file /home/username/.ssh/git
  2. now you can clone and pull your repository via your private git key to you web root directory
git clone<username>/notes.git
git -C /var/www/perlite/notes pull

Alternatively, you can use any other cloud based service to sync your files between your local vault and your webserver.

if you have no virtual or dedicated web server, you can just use a simple FTP upload to share your notes.

How to configure web server and php engine

There is already a simple Docker config in the /web/config directory but if you dont want to use Docker or Nginx you should keep in mind to prevent at least access to the following file extensions from the web, because there could be sensitive information inside.

Markdown files

These get parsed by the php engine, the web server don`t need access to them and if access is allowed directly via the web server this can lead to XSS vulnerabilities and unwanted access to hidden files. So you should prevent access to all .md files.

JSON files

Mainly if you use the Metadata Extractor and manually exclude / delete folders or notes from your web directory. This file should not be readable by the web server, all filenames and headlines are still present in this metadata.json if you don`t delete them manually. Only the php engine need access to this file. So you should prevent access to all .json files.

GitHub files and folders

Prevent access to the .git folder because there a all changes, deletions etc. stored from you vault, its pretty clear you don`t want to share these information with the world.

Also nobody need to know about your .gitignore .gitattributes or other files from github.

Obsidian files

.obsidian and .trash, Perlite dont need this folders or any file in that, just make sure, you follow the instructions for the graph and change the path for the metadata.json file, so this will be stored outside of the .obsidian folder, then you can and should delete this folder(s) on your web server or prevent access to it.

Example NGINX Config

server {


        root /var/www/html/perlite;
        index index.php index.html index.htm;

        location ~ \.php$ {
               include snippets/fastcgi-php.conf;
               fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;

        location ~ /\.ht {
                deny all;

        location ~* ^/(.*)/.obsidian/appearance.json$ {
                allow all;

        location ~* ^/(.*)/.obsidian/(.*)/theme.css$ {
                allow all;

        location ~ \.(git|github|obsidian|trash) {
                deny all;

        location ~ \.(md|json)$ {
                deny all;