Skip to content

Opening remote files in LibreOffice on Windows

This guide walks through giving your users a one-click "Open in LibreOffice" button that hands off any remote URL — WebDAV, plain HTTPS, whatever LibreOffice can read — from the browser to LibreOffice on Windows. The recipe is generic; this page lives in the webdav module's docs because that's where the question usually arises, but nothing below is WebDAV-specific until you reach the troubleshooting notes at the very end.

Why a custom URL scheme is needed

LibreOffice on Windows declares a handful of URL schemes via its installer (vnd.libreoffice.command:, ms-word:, etc.), but those schemes invoke UNO commands inside an already-running LibreOffice — they aren't suitable for the "open this remote document URL" use case. To hand an arbitrary https://… URL to soffice.exe, the simplest path is to register your own URL scheme (e.g. libreoffice:) pointing at a small PowerShell helper that strips the scheme prefix and shells out.

The flow

flowchart LR
    B["Browser<br/>user clicks<br/>libreoffice:https://..."]
    R["Windows Registry<br/>HKCU\Software\Classes\libreoffice<br/>shell\open\command"]
    H["PowerShell helper<br/>1. strip libreoffice: prefix<br/>2. Start-Process soffice.exe"]
    O["LibreOffice<br/>opens the document"]
    B --> R --> H -->|soffice.exe &lt;url&gt;| O

Step 1 — Write the PowerShell helper

Pick a permanent home for the script, e.g. C:\Tools\LibreOfficeUrlHandler\open.ps1. Save the following:

param([Parameter(Mandatory)][string]$Url)

# Strip the custom-scheme prefix. The URL arrives as
# "libreoffice:https://host/path"; we want "https://host/path".
$clean = $Url -replace '^libreoffice:', ''

# Spawn soffice.exe with the cleaned URL. Start-Process foregrounds
# the new window by default, so an already-running LibreOffice is
# brought to front and the new document becomes the active one.
Start-Process `
    -FilePath 'C:\Program Files\LibreOffice\program\soffice.exe' `
    -ArgumentList $clean

Notes:

  • If LibreOffice is installed as 32-bit on a 64-bit Windows, the path is C:\Program Files (x86)\LibreOffice\program\soffice.exe instead. Adjust -FilePath to match.
  • Start-Process handles process focus correctly out of the box — no polling / delay dance is needed (unlike the macOS recipe).

Step 2 — Write the registry-import file

Create register.reg somewhere temporary (e.g. on the desktop):

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Classes\libreoffice]
@="URL:LibreOffice URL Handler"
"URL Protocol"=""

[HKEY_CURRENT_USER\Software\Classes\libreoffice\DefaultIcon]
@="C:\\Program Files\\LibreOffice\\program\\soffice.exe,0"

[HKEY_CURRENT_USER\Software\Classes\libreoffice\shell\open\command]
@="powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File \"C:\\Tools\\LibreOfficeUrlHandler\\open.ps1\" \"%1\""

Two registry keys are the bare minimum:

  • The URL Protocol value (an empty string, but the value must exist) — this tells Windows the key represents a URL handler rather than a file association.
  • shell\open\command\(Default) — the command line Windows runs when something dispatches the scheme. %1 is substituted with the full URL the browser handed off (so it arrives in the helper as libreoffice:https://host/path).

Optional but recommended:

  • DefaultIcon — gives the scheme a visible icon in Windows surfaces that render it (rare but cheap to add).
  • HKEY_CURRENT_USER is a per-user scope; no admin needed. If you want the handler available system-wide, write HKEY_LOCAL_MACHINE\Software\Classes\libreoffice instead — requires elevation.

A few escaping details that bite if missed:

  • Backslashes in registry string values must be doubled: C:\\Tools\\…\\open.ps1.
  • Double quotes inside the value must be escaped with a backslash: \"%1\".
  • Wrap %1 in \"…\" — without it, URLs containing whitespace (rare but possible) get split into multiple arguments.

Step 3 — Install the scheme

Double-click register.reg. Windows prompts:

Are you sure you want to continue?

Click Yes. The keys are merged into the registry instantly — no reboot, no logout. The scheme is now live for the current user.

To verify the registration:

Get-ItemProperty 'HKCU:\Software\Classes\libreoffice\shell\open\command'

Should return the PowerShell command line you set in Step 2.

To uninstall later, run from PowerShell:

Remove-Item -Path 'HKCU:\Software\Classes\libreoffice' -Recurse

Wrap the actual remote URL with your custom scheme prefix when rendering the "Open in LibreOffice" button:

$remote_url = 'https://example.test/path/to/file.odt';
$lo_url = 'libreoffice:' . $remote_url;

$build['button'] = [
    '#type' => 'link',
    '#title' => $this->t('Open in LibreOffice'),
    '#url' => \Drupal\Core\Url::fromUri($lo_url),
];

When the user clicks the link, the browser hands libreoffice:… off to Windows, which looks up the registry entry, runs the PowerShell helper, which shells out to soffice.exe with the unwrapped https://… URL.

Step 5 — Test

  1. Visit a page that renders the "Open in LibreOffice" button.
  2. Click it. The first time, the browser prompts "Open libreoffice?" or "Allow this site to open libreoffice links?" — tick Always allow if you want to skip the prompt on subsequent clicks, then click Open.
  3. LibreOffice should foreground (or launch if not running) with the remote document open.

Troubleshooting

  • Re-verify the registration with the Get-ItemProperty command above. If the key doesn't exist, the .reg import didn't apply — re-run as the right user.
  • Some browsers cache a denied permission for unknown schemes. Reset the site's notification / external-app permission via the browser's site-settings panel and try again.

PowerShell complains about execution policy

The default Windows execution policy can block ad-hoc .ps1 files. The -ExecutionPolicy Bypass flag in the registry command line covers most cases, but if your environment forces AllSigned, you have two options:

  • Replace the PowerShell helper with a .cmd batch file (no execution policy applies) and update the registry to point at it:
@echo off
set url=%~1
set url=%url:libreoffice:=%
start "" "C:\Program Files\LibreOffice\program\soffice.exe" "%url%"

Registry line becomes:

@="\"C:\\Tools\\LibreOfficeUrlHandler\\open.cmd\" \"%1\""
  • Or sign the PowerShell script with an internal code-signing certificate and switch the registry back to -ExecutionPolicy AllSigned.

A blank PowerShell window flashes briefly

The -WindowStyle Hidden flag in the registry command line suppresses the PowerShell window. If you skipped that flag, re-import the .reg with it added.

soffice.exe runs but doesn't pick up credentials in the URL

LibreOffice does not parse https://user:pw@host/file.odt from the CLI on Windows either — same limitation as macOS.

Embed credentials in the URL path instead, e.g. /<uid>-<hmac>/file.odt, and have your server unpack them server-side. The browser → PowerShell → soffice.exe chain passes the path verbatim, so the auth segment survives.

LO complains about an untrusted certificate

LibreOffice has its own NSS trust store on Windows too, a copy of Mozilla's NSS bundled with LO and not the Windows certificate store. Importing your CA into "Trusted Root Certification Authorities" via certmgr.msc does not reach LibreOffice's trust list.

To trust your local CA from LO:

  1. Tools → Options → LibreOffice → Security → Certificate, click Certificate Path….
  2. Point LO at a Mozilla NSS folder that already trusts your CA (typically a Firefox profile directory under %APPDATA%\Mozilla\Firefox\Profiles\<random>.default-release\).
  3. Or set the MOZILLA_CERTIFICATE_FOLDER environment variable in soffice.exe's startup environment.

soffice.exe runs but the file save fails with 403 (WebDAV-specific)

If you're serving the file over WebDAV, two failure modes are worth checking on the server side:

  • Query-string auth tokens are stripped by LO before PUT — this is RFC-compliant (query strings aren't part of the resource identifier). Put any auth token in the URL path instead. The auth survives every verb that way.
  • Lock tokens are URL-keyed. If your server rewrites the URL between LOCK and PUT, the lock token from the LOCK response won't match the resource path on PUT and the server returns 423/412/409. Keep the URL identical across the WebDAV session.