The error svn: E000030: Can't open file '.../db/txn-current-lock': Read-only file system is not caused by Subversion, Apache configuration, or your repository permissions. It happens because the apache2.service systemd unit on recent Ubuntu releases runs the web server inside a hardened sandbox in which /home is mounted read-only. If your SVN repository lives under /home/svn, the Apache worker that handles the commit physically cannot create the transaction files it needs, and the kernel reports the filesystem as read-only — even though it is perfectly writable for every other process on the machine.
Why commits fail only on newer Ubuntu releases
Subversion's repository format has not changed, and neither has mod_dav_svn's behavior. During a commit, the server must write into the repository's db/ directory, including creating and locking txn-current-lock and the corresponding transaction directories. If that write is blocked, the client sees E000030.
What changed is the default security hardening of the packaged Apache unit. The unit now includes a directive such as:
ProtectHome=read-only
This systemd sandboxing option makes every path under /home visible to the service but mounted read-only. Older LTS releases (20.04, 22.04, 24.04) shipped a unit without this restriction, which is why identical provisioning scripts that worked for years suddenly break after an OS upgrade. Nothing is wrong with your chown www-data, your 775 permissions, or your DBM authentication — the denial happens below the filesystem permission layer, at the mount-namespace level.
You can confirm this quickly:
sudo -u www-data touch /home/svn/myrepository/db/testfilesucceeds, because a plain shell is not sandboxed.- The Apache error log may show nothing beyond the failed commit, since the kernel rejection is transparent to the module.
- Checking the effective unit with
systemctl cat apache2.servicereveals theProtectHome(and related) settings.
The fix: a systemd drop-in, not editing the unit file
Do not edit /lib/systemd/system/apache2.service directly — package updates will overwrite it. Instead, create a drop-in override:
sudo systemctl edit apache2.service
This opens an editor on an override file. There are two approaches, and the trade-off between them matters:
Option 1 — whitelist only the repository path (recommended)
[Service]
ReadWritePaths=/home/svn
The ReadWritePaths directive carves a writable exception out of the read-only /home mount, leaving the rest of the sandbox intact. Your repository stays protected by all the other hardening options, and only the directory that genuinely needs writes is exposed. This is the minimal-privilege choice and the one to prefer.
Option 2 — disable home sandboxing entirely
[Service]
ProtectHome=no
This removes the read-only /home mount altogether. It is simpler and works if you also need Apache to read or write elsewhere under /home, but it weakens the sandbox more than necessary. If your repository lives somewhere else entirely — say /srv/svn — you may find that a different sandbox directive (such as one covering /srv) is the culprit, and the same technique applies with the appropriate path.
After saving the drop-in, reload and restart:
sudo systemctl daemon-reload
sudo systemctl restart apache2.service
Then retry the commit from the client. The txn-current-lock error should disappear immediately.
Verifying the change took effect
To confirm the service is running with your override, inspect the effective configuration:
systemctl show apache2.service -p ReadWritePaths -p ProtectHome
You can also verify from inside the running service's namespace:
sudo cat /proc/$(systemctl show -p MainPID --value apache2.service)/mounts | grep home
With Option 1 in place, /home appears read-only but /home/svn (or whatever path you whitelisted) appears writable.
Prevention and generalization
This class of failure is easy to misdiagnose because the error message points at the filesystem rather than at the sandbox. Whenever a daemon reports "read-only file system" on a path that is demonstrably writable from a shell, suspect systemd sandboxing directives: ProtectHome, ProtectSystem, ReadOnlyPaths, ReadWritePaths, and PrivateTmp. Upgrading an LTS release is the most common trigger, because unit files shipped by the distribution get stricter over time while your directory layout stays the same.
To avoid surprises in future upgrades:
- Keep any drop-in overrides in
/etc/systemd/system/apache2.service.d/under version control so they survive reinstallation and are easy to reapply on new servers. - Consider placing service-writable data outside
/home(for example/srv/svn) to reduce reliance onProtectHomeexceptions — though note that other directives may still apply to those paths. - After any OS upgrade that hosts Apache-backed services, smoke-test write operations (an SVN commit, a WordPress upload, etc.), not just read access.
Frequently Asked Questions
Why does the error say "read-only file system" when permissions are 775 and the owner is www-data?
Because the denial comes from a read-only bind mount inside Apache's systemd sandbox, not from Unix file permissions. The kernel rejects writes at the mount level before permissions are ever consulted, and the resulting error message is generic.
Is ReadWritePaths better than setting ProtectHome=no?
Generally yes. ReadWritePaths opens a single directory for writing while keeping the rest of the /home sandbox intact, which follows the principle of least privilege. ProtectHome=no is a blunt fix that removes the protection entirely; use it only if the service legitimately needs broad access to /home.
Do I need to reinstall or recreate the repository?
No. The repository itself is fine — nothing was corrupted, because the writes never happened. Once the sandbox permits writes, commits succeed against the existing repository with no migration or repair.
Does this affect browsing or checking out over HTTP(S), or only commits?
Read operations (checkout, export, log, update) usually continue to work, since the sandbox still allows reading /home. Only operations that write to the repository — commit, lock, property changes — hit the read-only wall.
I placed my repository in /var or /srv and get the same error. Is the fix the same?
The mechanism is the same but the responsible directive may differ. Newer units also restrict parts of the filesystem via options like ProtectSystem=full or ReadOnlyPaths. Check systemctl cat apache2.service, identify which directive covers your path, and add a matching ReadWritePaths entry for it.
Will a package upgrade of Apache erase my drop-in override?
No. Drop-ins live in /etc/systemd/system/apache2.service.d/, which is not owned by the package, so they survive upgrades. Only edits made directly to the unit file under /lib/systemd/system/ would be overwritten — which is exactly why drop-ins are the recommended approach.