How to Convert PDF, Word and ODT to Markdown Locally with MarkForge

MarkForge self-hosted document to Markdown conversion interface

Running a local AI system such as Ollama, Open WebUI, or a Retrieval-Augmented Generation (RAG) application often means preparing a collection of PDF files, Microsoft Word documents, and LibreOffice files. These formats are useful for everyday work, but they are not always easy to parse or index correctly.

MarkForge converts these files into Markdown, a simple text format suitable for local AI knowledge bases. In this guide, we will install the Punctiq version of MarkForge using Docker on Ubuntu Linux and convert documents without sending them to an external service.

MarkForge self-hosted document to Markdown conversion interface
MarkForge’s self-hosted document conversion interface. Source: Punctiq project repository.

What Is MarkForge?

MarkForge is an open-source, self-hosted document converter. It supports batch processing, Markdown previews, extraction of figures, optional AI-assisted cleanup, and ZIP exports containing converted documents and associated files.

Document type Supported extension
PDF .pdf
Microsoft Word .docx
Legacy Microsoft Word .doc
OpenDocument Text .odt

Important: Several unrelated projects also use the MarkForge name. This article covers github.com/Punctiq/markforge. Its supported Office document formats do not include Excel, PowerPoint, or OpenDocument spreadsheet/presentation files.

Why Markdown for Local AI?

Markdown is plain text with lightweight structure. It can preserve headings, paragraphs, lists, simple tables, and image references without the additional formatting data found in Word files and PDFs.

For a local RAG system, Markdown content can be split into smaller sections, embedded, and stored in a vector database. Keeping the headings can also make the retrieved passages easier to understand. However, conversion is not a guarantee of accurate extraction. Tables, equations, and multi-column pages still need to be checked.

Step 1: Install MarkForge with Docker

We will use Docker on Ubuntu. The project’s Docker image includes dependencies such as LibreOffice and Pandoc.

Clone the source repository:

git clone https://github.com/Punctiq/markforge.git
cd markforge

Copy the example environment file:

cp .env.example .env

Edit .env and check the following settings:

FLASK_ENV=production
AUTH_ENABLED=false

LLM_PROVIDER=openai
LLM_API_KEY=
LLM_BASE_URL=

With the API key left empty, MarkForge can perform normal document conversion without invoking an external AI model. Keep AUTH_ENABLED=false only if the application remains restricted to your own machine or another trusted environment.

Build and start the application:

docker compose up -d --build

Open http://127.0.0.1:8010 in a browser on the Docker host. The provided Compose configuration binds port 8010 to the host’s loopback address, rather than exposing the service directly to the local network or internet.

Check whether the service is responding:

curl http://127.0.0.1:8010/api/v1/health

Step 2: Convert PDF, Word, and ODT Files

  1. Open the MarkForge web interface.
  2. Select a .pdf, .docx, .doc, or .odt document.
  3. Disable AI Cleanup for conversion without LLM calls.
  4. Start conversion and inspect the resulting Markdown preview.
  5. Download the Markdown or the ZIP package containing the output and figures.

The ZIP package is helpful when a document has figures that need to remain together with the Markdown file.

Automate a conversion with curl

MarkForge also provides a conversion API. For example, to convert manual.pdf into a ZIP package:

curl -f \
  -F "file=@manual.pdf" \
  -F "ai_cleanup=false" \
  -F "output_format=zip" \
  http://127.0.0.1:8010/api/v1/convert \
  -o manual.zip

This approach can be adapted to a local document-processing script. Check the API response and converted content before automatically indexing the output.

PDF limitation: This version uses PyMuPDF to extract existing text. Image-only scanned pages without selectable text are not automatically processed with OCR. Perform OCR separately before conversion if your PDF consists of scanned pages.

Step 3: Optional AI Cleanup with Ollama

MarkForge can optionally send extracted Markdown to an LLM for formatting cleanup. It supports OpenAI-compatible endpoints, including a locally hosted Ollama server.

For MarkForge installed directly on the same host as Ollama, a basic configuration is:

LLM_PROVIDER=ollama
LLM_MODEL=qwen3:4b
LLM_BASE_URL=http://127.0.0.1:11434/v1
LLM_API_KEY=ollama

Use a model that you actually have installed. Docker users must change the endpoint: inside the MarkForge container, 127.0.0.1 refers to the container itself, not the machine running Ollama. Configure a reachable host or Docker network address before enabling cleanup.

Safe, Balanced, and Aggressive cleanup modes are available. For technical, academic, and compliance-related documents, begin with Safe mode and compare the output against the original document. An LLM may alter terminology, numbers, or meaning while attempting to improve formatting.

Step 4: Import Markdown into a Local AI Knowledge Base

After conversion, place the Markdown files and extracted figures inside a local folder:

knowledgebase/
??? student-regulations.md
??? research-guidelines.md
??? server-documentation.md
??? figures/
    ??? diagram-01.png
    ??? diagram-02.png

You can then import the documents into an Open WebUI knowledge collection or process them in a custom RAG pipeline. For lengthy material, splitting content by section headings often makes chunks more useful than splitting at arbitrary positions.

Before indexing, check headings, reading order, tables, equations, citations, and references to images. Keep a copy of the source file for future verification.

Why Privacy Matters When Converting Documents

Many websites offer free PDF-to-Markdown and Word-to-Markdown conversion. While convenient, uploading files to a service you do not control may expose confidential information.

This is particularly important for documents containing student records, unpublished academic manuscripts, internal technical specifications, contracts, financial details, or other personal information.

When using a third-party service, you may not have full visibility into document retention, server logging, subcontractors, or how uploaded data is processed. Privacy claims should be checked against the provider’s actual terms and technical practices.

Self-hosting reduces unnecessary exposure by keeping processing on infrastructure under your control. It does not automatically guarantee privacy. If you enable a remote LLM provider for AI cleanup, extracted document content may still leave your network.

For sensitive documents, keep conversion local, disable cloud cleanup, restrict access to the MarkForge server, and secure temporary files and converted outputs. Never expose an unauthenticated document converter directly to the public internet.

Final Thoughts

MarkForge provides a straightforward way to convert PDF, Word, and OpenDocument Text files into Markdown for Ollama, Open WebUI, and other local AI workflows. Its self-hosted installation is useful when the documents should remain on your own computer or trusted server.

For a private RAG knowledge base, the recommended workflow is simple: convert locally, inspect the Markdown, and then index only the verified content.

Project: Punctiq MarkForge on GitHub
License: Apache License 2.0

renogybt-emulator: A Python Emulator for Renogy BT-1 and BT-2

I’ve put my latest project on GitHub: renogybt-emulator, a Python library and command-line tool that emulates the Bluetooth interface exposed by Renogy BT-1 and BT-2 modules connected to an MPPT solar charge controller.

The aim is to make it easier to develop and test solar-monitoring software without needing a physical controller, solar panels or batteries on the desk.

 

TLDR;
This software make a Linux computer behave like a Renogy solar charge controller over Bluetooth, so you can test your apps without physical solar equipment.

 

Demo Screenshots From Official Renogy Mobile Application

How it works

The BT-1 and BT-2 modules provide Bluetooth Low Energy (BLE) access to Renogy equipment, using RS232 and RS485 respectively on the controller side. My emulator runs on a Linux computer with a BLE adapter and presents the Bluetooth services and simulated controller data that a compatible client expects.

 

Underneath, it implements the BLE GATT services and characteristics used for communication, together with a Modbus RTU responder. A client sends a request over Bluetooth, and the emulator replies with values from its simulated register bank. Those values include battery voltage, charging current, solar power, temperatures and load status.

This lets a monitoring application connect to an emulated device and exercise its normal communication path.

 

Continue reading “renogybt-emulator: A Python Emulator for Renogy BT-1 and BT-2”

Critical PHP Flaws: How to Update PHP 8.3, 8.4 and 8.5

Updated 22 October 2026. Commands below target Ubuntu/Debian package installations.

PHP has released emergency fixes for CVE-2026-109618 and CVE-2026-109619, both rated critical at CVSS 9.2. They can allow unauthenticated remote code execution. One involves unsafe out-of-memory cleanup; the other involves stale internal state across requests. Apache mod_php has a demonstrated attack before application code runs. PHP-FPM also requires patching. See the official announcement.

1. Check and update PHP

Back up your database, application files and configuration. Identify every runtime:

php -v
php --ini
dpkg -l 'php*' 'libapache2-mod-php*'

The CLI version may differ from the website. Check each virtual host, FPM pool, container and hosting panel.

Branch First fixed upstream version
PHP 8.3 8.3.36
PHP 8.4 8.4.27
PHP 8.5 8.5.12

Install these or later supported security releases. For PHP 8.3-FPM:

sudo apt update
apt-cache policy php8.3-common php8.3-fpm
sudo apt upgrade
sudo php-fpm8.3 -t
sudo systemctl restart php8.3-fpm

Substitute 8.4 or 8.5 for your installed branch. Review package upgrades, including extensions. If Apache uses mod_php:

sudo apache2ctl configtest
sudo systemctl restart apache2

Check vendor backports. Ubuntu fixes include 8.3.6-0ubuntu0.24.04.13 for 24.04 and 8.5.4-0ubuntu1.5 for 26.04. Compare complete revisions against Ubuntu’s security notice. Other repositories need their own advisories. An older-looking version can contain the fix.

Confirm the web runtime afterward and test login, uploads and database access. Updating WordPress or OJS alone does not update PHP.

2. Update containers separately

Host updates do not patch container PHP. Confirm a patched image exists, then replace app with your Compose service:

docker compose pull app
docker compose up -d --no-deps app
docker compose exec app php -v

Custom images require an updated base image and rebuild. Preserve persistent data. Shared-hosting users should request the exact patched revision.

3. Limit requests before PHP

In Nginx’s relevant server block:

client_max_body_size 8m;

Or inside the Apache virtual host:

LimitRequestBody 8388608

See the Nginx and Apache documentation. These impose an 8 MiB body limit. Adjust for legitimate uploads. In the active web runtime’s php.ini:

post_max_size = 8M
upload_max_filesize = 6M
max_file_uploads = 5
max_input_vars = 1000
max_input_nesting_level = 32
session.upload_progress.enabled = 0

Typical Ubuntu paths are /etc/php/8.3/fpm/php.ini for FPM and /etc/php/8.3/apache2/php.ini for mod_php. Adjust the branch number. php --ini reports CLI configuration only.

Test these example values. Disable file uploads if unused. Apply upload-progress settings at startup, then restart workers; application code and FPM .user.ini are too late for the confirmed early path.

Test Nginx with sudo nginx -t before reloading, or Apache with sudo apache2ctl configtest. These limits reduce exposure; they do not fix either CVE.

4. Emergency mitigation while patching

Prefer removing public PHP access and serving a static maintenance page. A PHP maintenance plugin still invokes PHP.

The OOM advisory recommends this incomplete emergency measure in the relevant FPM pool, such as /etc/php/8.3/fpm/pool.d/www.conf:

php_admin_value[memory_limit] = -1

This removes one controllable OOM trigger but permits unlimited per-request PHP memory, increasing denial-of-service risk. Use frontend limits and suitable cgroup/container boundaries. Underlying allocation failures remain dangerous; do not substitute RLIMIT_AS or RLIMIT_DATA. Audit overrides and restart all workers. Restore suitable finite PHP limits after patching.

For PHP 8.5, also set fatal_error_backtraces=0 in startup configuration. Remove invalid or obsolete per-request INI settings. These address specific stale-state paths only. Hiding warnings provides no protection.

5. Retire public PHP 7.4 applications

PHP 7.4 reached upstream end of life on 28 November 2022. Retire unused applications or migrate them to supported PHP. Legacy source patches and vendor fixes exist, but require explicit verification and should support temporary migration arrangements.

Remove forgotten subdomains, restrict administration through VPN/access policies, and keep FPM off public port 9000. Review logs, unexpected files, accounts and scheduled tasks. Patching does not remove existing backdoors. If compromise is suspected, isolate the system and preserve evidence. Follow NCSC guidance.

How to Recover PDF Passwords with pdfcrack and NVIDIA-Accelerated Hashcat

Forgotten the password to an old PDF? You can try recovering it locally on Linux with pdfcrack.

This guide covers recovery of the password needed to open a PDF. Use it on your own files or files you have permission to recover.

 

IMPORTANT: pdfcrack runs on the CPU and has no built-in CUDA or NVIDIA GPU support. For NVIDIA acceleration, use Hashcat instead.

Start with a small password dictionary

A dictionary is a text file containing one password candidate per line. Start with a short list of passwords you remember using, then try common-password lists. This keeps the first attempt quick and helps check that the setup works before running a larger job.

Download the small SecLists file on Ubuntu:

wget -O common-passwords.txt 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Passwords/Common-Credentials/10k-most-common.txt'

You can also make a shorter first pass:

head -n 1000 common-passwords.txt > small.txt

This takes the first 1,000 lines. It does not guarantee that they are the best candidates. Extract compressed dictionaries before using them. A larger dictionary takes longer and still cannot recover a password that is absent from the list.

Recover a PDF password with pdfcrack

Install pdfcrack on Ubuntu:

sudo apt update
sudo apt install pdfcrack wget

Replace locked.pdf with your PDF filename:

pdfcrack -f locked.pdf -w small.txt

The -f option selects the PDF and -w selects the dictionary. User-password recovery is the default. If the first list fails, repeat with common-passwords.txt. See the pdfcrack manual for other options.

The project documents support for standard security-handler revisions 2, 3 and 4. Unsupported encryption requires another tool. Installing NVIDIA drivers will not add GPU support to pdfcrack.

Use Hashcat for NVIDIA acceleration

Install Hashcat and the supporting tools:

sudo apt install hashcat git python3
nvidia-smi
hashcat -I

You need a working NVIDIA driver and a compatible CUDA installation. The Hashcat requirements page lists the NVIDIA CUDA Toolkit requirement. Confirm that hashcat -I detects your NVIDIA GPU before continuing. A working nvidia-smi alone does not confirm that Hashcat can use it.

Hashcat needs an extracted password-verification record, rather than the PDF itself. The third-party pdf2hashcat script can prepare it locally:

git clone https://github.com/sighook/pdf2hashcat.git
python3 pdf2hashcat/pdf2hashcat.py locked.pdf > locked.hash
hashcat --identify locked.hash

Select the matching PDF mode using the identification output and Hashcat’s example hashes. The encryption settings determine the mode. The PDF filename or version alone is insufficient.

For example, only if mode 10500 matches your extracted record:

hashcat -m 10500 -a 0 locked.hash common-passwords.txt
hashcat -m 10500 locked.hash --show

Here, -a 0 selects a dictionary attack, while --show displays recovered results. Check the startup output to confirm that the NVIDIA device is being used. Mode 10500 is not suitable for every PDF.

Exhausted means the selected candidates were tried without a match. It does not mean the PDF has no password. GPU acceleration can increase guessing speed, but recovery time depends on the encryption and password. A long random password may remain impractical to recover.

Revisiting Midnight Commander: A Classic Linux File Manager

Some Linux tools bring back memories as soon as you open them. Midnight Commander is one of those tools. Its familiar blue panels, text menus, and function keys recall the days when managing files in a terminal was an ordinary part of using a computer.

Known simply as mc, GNU Midnight Commander is a terminal file manager with two directory panels. Open your source folder on one side and the destination on the other, then browse and copy files using the keyboard.

Midnight Commander showing two directory panels and a function key menu in the terminal
Midnight Commander’s familiar two-panel interface. Screenshot from the official Midnight Commander project website.

The appeal of those blue panels

For anyone who remembers DOS-era file managers, this layout feels familiar. The available actions appear along the bottom of the screen, and the keyboard does most of the work. There is something satisfying about seeing both folders at once and moving through them without repeatedly typing ls and cd.

Midnight Commander also remains useful when working on a Linux server through SSH. It runs inside the terminal, so you can browse directories, inspect files, and organise folders without opening a graphical desktop. It includes a file viewer and an editor, too.

How to install Midnight Commander on Ubuntu

Install it using Ubuntu’s package manager:

sudo apt update
sudo apt install mc

Then launch it:

mc

Start with these shortcuts, documented in the official manual:

Key Action
Tab Switch between panels
F1 Open help
F3 View a file
F4 Edit a file
F5 Copy files
F6 Move or rename files
F7 Create a directory
F8 Delete files
F10 Quit

Modern desktops have changed how we manage files, but this old style still has its appeal. Two panels, clear actions, and a keyboard within reach are enough to make routine file management comfortable. If you have not used Midnight Commander for years, try typing mc again.

References

Remembering WGAfakap.exe, a Windows XP Genuine Advantage removal tool – It’s already 20 years!

Twenty years ago I wrote WGAfakap.exe, a simple windows application that removes the Windows XP Genuine Advantage Tattoo.

WGAfakap was widely used around the world to help individuals or companies who has purchased a legitimate Windows XP from being nagged by the notorious “You May Be A Victim Of Software Counterfeiting, Solve It Now! ” screen.

I used Microsoft Visual Studio 6 and libctiny and wcrt library to keep WGAfakap small. And the result was a very small (less than 8kb of executable!) https://blog.mypapit.net/2006/05/solution-to-libctiny-and-wcrt-lnk2001-unresolved-external-symbol-__chkstk.html

I was obsessed with optimization and efficiency because I was poor back then. Couldn’t afford a decent computer with a lot of storage space and speed. Thus, efficiency was everything to me.

Although there are attempts to supress it, WGAfakap was famous and it was distributed through message boards and was being used across the world.

With careful searching, archived message board threads explaining how to use WGAfakap can still be found. The most recent of these discussions date to 2010, four years after its initial development

Most WGAfakap users probably almost reached 40 years old now. Give a shout out if you’ve heard or ever used WGAfakap!