14 Commits
Author SHA1 Message Date
naturallaw777 70ccf1eba1 chore(release): prepare v1.1.7 2026-09-21 18:09:10 -05:00
naturallaw777 f6caa2ff32 updated nixpkgs 2026-09-21 18:07:21 -05:00
Sovran Contributor 8bc325b148 postgresql: drop per-database autovacuum ALTERs (rejected by Postgres)
Follow-up to the previous two commits: the ALTER DATABASE ... SET
autovacuum_* commands fail at boot with

  ERROR: parameter "autovacuum_vacuum_scale_factor" cannot be changed now

and take matrix-synapse-db-tune.service (and nextcloud-db-init.service)
down with them.

Root cause: ALTER DATABASE/ROLE ... SET validates through
set_config_option() with an interactive context, and guc.c rejects any
PGC_SIGHUP parameter set that way. All autovacuum_* GUCs are
SIGHUP-context, so per-database scoping is impossible for them — only
USERSET-level parameters (e.g. work_mem, statement_timeout) can be set
per-database.

Nothing is lost: the same values are already set cluster-wide in
configuration.nix, which covers both nextclouddb and matrix-synapse.
Remove the ALTERs from nextcloud-db-init and delete the now-purposeless
matrix-synapse-db-tune service.
2026-09-21 14:21:01 -05:00
Sovran Contributor e31094c194 synapse: performance tuning for 32 GB Server+Desktop hosts
Monolith Synapse spends most of its RAM on caches to avoid Postgres
round-trips, but Sovran ships stock cache settings (global_factor 0.5,
10K event cache, no autotuning) and a default 5-connection DB pool.

- caches.global_factor 4.0 + 100K event cache + autotuning capped at
  2G (target 1G), with boosts for the /sync and room-join hot paths.
- DB pool cp_min 5 / cp_max 15, txn_limit 10000 (fewer reconnects).
- gc_thresholds raised to cut GC pauses on a 32 GB box.
- cache-memory extra for cache-size statistics.
- Per-database autovacuum (ALTER DATABASE, scoped to matrix-synapse)
  matching the nextclouddb tuning.

Deliberately unchanged: presence and URL previews stay enabled
(disabling them is faster but user-visible), and no workers — monolith
is the right call under ~100 users. Workers would need Redis
replication, the redis extra, and Caddy reverse-proxy rework; revisit
if federation load ever justifies it.
2026-09-21 14:00:19 -05:00
Sovran Contributor 09d4cc9b83 nextcloud, postgresql: fix Nextcloud 35 DB warnings on 32 GB hosts
Nextcloud 35's Database checks flag three Performance issues out of the
box: buffer cache hit ratio ~96% (wants 99%+), 100k+ dead tuples, and
million-plus sequential scans on oc_mail_tags / oc_guests_users.

Root causes in Sovran: stock 128MB shared_buffers, stock 60s autovacuum
naptime, APCu file locking, and db:add-missing-indices running exactly
once at install time (never on upgrades or app installs).

Size Postgres for the README's Server + Desktop recommendation (32 GB
RAM, NVMe): 2GB shared_buffers, 12GB effective_cache_size, 512MB
maintenance_work_mem, 32MB work_mem, 4GB max_wal_size, 30s autovacuum
naptime with 4 workers. shared_buffers stays below the 25% rule because
Postgres shares the box with bitcoind, Electrs, LND, MariaDB and PHP-FPM.

Scope the aggressive autovacuum to nextclouddb via ALTER DATABASE so the
shared matrix-synapse DB keeps the milder cluster defaults.

Add a local Redis (127.0.0.1:6379, Nextcloud only) and move
memcache.distributed/locking to Redis; migrate existing installs with a
one-shot since nextcloud-init never re-runs.

Add a weekly nextcloud-db-maintenance timer (VACUUM ANALYZE +
db:add-missing-*) so upgrades and later app installs can't regress the
checks again.

Note: shared_buffers needs one 'systemctl restart postgresql', which
briefly takes down both Nextcloud and Matrix. Everything else is
reload-only or scoped to nextclouddb.
2026-09-21 13:59:52 -05:00
naturallaw777 3341659a0c updated to php85 and fixes 2026-09-19 16:24:57 -05:00
Sovran Systems 32e1119e33 Updated to proper syntax to prevent build errors. 2026-09-17 16:28:37 -05:00
Sovran Systems 0f7ef8422d Clean up flake.nix by removing comments and LiveKit override
Removed comments and overridden attributes for LiveKit version in flake.nix.
2026-09-17 16:19:37 -05:00
naturallaw777 dd6042928a updated flake lock which contains Bisq 1.10.8 and Bisq2 2.1.13 2026-09-17 15:37:28 -05:00
naturallaw777 74405b2ffc chore(release): prepare v1.1.6 2026-09-15 15:17:10 -05:00
naturallaw777 258da6a337 updated nix packages includes the new mempool version 2026-09-15 14:15:20 -05:00
Sovran Systems 73ab3f40c1 Rename 'The Sovran Hub' to 'The Hub' in README 2026-09-09 11:19:50 -05:00
Sovran Systems 0768712bf7 Rename 'Sovran Hub' to 'The Hub' in README
Updated references from 'Sovran Hub' to 'The Hub' for consistency.
2026-09-09 11:19:03 -05:00
naturallaw777 2ac30dc10a docs: update Sovran Hub screenshot to the v1.1.5 redesign
Replace the pre-redesign Hub capture with the new welcome dashboard
introduced in v1.1.5 — the default view showing system status, Bitcoin
sync, and the update card at a glance.

The capture is rendered from the real Hub frontend (Server + Desktop
role, demo credentials/domains) at 1920x1080, and doubles as the hero
shot of the marketing kit.  Also drops the asset from 391 KB to 59 KB
with no visible loss.
2026-09-09 11:04:57 -05:00
10 changed files with 317 additions and 113 deletions
+30
View File
@@ -7,6 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
---
## [1.1.7] - 2026-09-21
### Added
- Postgresql: drop per-database autovacuum ALTERs (rejected by Postgres)
- Synapse: performance tuning for 32 GB Server+Desktop hosts
- Nextcloud, postgresql: fix Nextcloud 35 DB warnings on 32 GB hosts
- Clean up flake.nix by removing comments and LiveKit override
### Changed
- Updated nixpkgs
- Updated to php85 and fixes
- Updated to proper syntax to prevent build errors.
- Updated flake lock which contains Bisq 1.10.8 and Bisq2 2.1.13
[1.1.7]: https://git.sovransystems.com/Sovran_Systems/Sovran_SystemsOS/releases/tag/v1.1.7
## [1.1.6] - 2026-09-15
### Added
- Rename 'The Sovran Hub' to 'The Hub' in README
- Rename 'Sovran Hub' to 'The Hub' in README
### Changed
- Updated nix packages includes the new mempool version
### Documentation
- Update Sovran Hub screenshot to the v1.1.5 redesign
[1.1.6]: https://git.sovransystems.com/Sovran_Systems/Sovran_SystemsOS/releases/tag/v1.1.6
## [1.1.5] - 2026-09-09
### Added
+18 -18
View File
@@ -21,9 +21,9 @@ Lightning infrastructure, private cloud, and communications platform when you
are ready.
[Visit the Website](https://sovransystems.com) ·
[Download the ISO](https://downloads.sovransystems.com/Sovran_SystemsOS-1.1.5.iso) ·
[Download the ISO](https://downloads.sovransystems.com/Sovran_SystemsOS-1.1.7.iso) ·
[Try it safely in a VM](#try-it-first-in-a-virtual-machine) ·
[Verify the Download](https://downloads.sovransystems.com/Sovran_SystemsOS-1.1.5.iso.sha256) ·
[Verify the Download](https://downloads.sovransystems.com/Sovran_SystemsOS-1.1.7.iso.sha256) ·
[Build from Source](#build-from-source)
<img src="assets/desktop-screenshot.webp" alt="Sovran_SystemsOS private Bitcoin desktop" width="800" />
@@ -45,7 +45,7 @@ are ready.
- [What is included](#what-is-included)
- [Three modes](#three-modes)
- [Use it your way](#use-it-your-way)
- [The Sovran Hub](#the-sovran-hub)
- [The Hub](#the-hub)
- [Install Sovran_SystemsOS](#install-sovran_systemsos)
- [For developers](#for-developers)
- [Development workflow](#development-workflow)
@@ -264,11 +264,11 @@ infrastructure behind them.
---
## The Sovran Hub
## The Hub
### Your private infrastructure, controlled from any screen.
The Sovran Hub is the command center built into Sovran_SystemsOS. It is both a
The Hub is the command center built into Sovran_SystemsOS. It is both a
local desktop application and a private web interface served directly by your
Sovran_SystemsOS machine. Nothing needs to be installed on the device opening
the Hub: you only need a modern browser and access to the same local network.
@@ -281,9 +281,9 @@ From one place, the Hub helps you:
- Reach your Bitcoin tools, private cloud, and communications
- Perform supported system operations without everyday terminal commands
<img src="assets/sovran-hub-screenshot.webp" alt="The Sovran Hub dashboard" width="800" />
<img src="assets/sovran-hub-screenshot.webp" alt="The Sovran Hub welcome dashboard" width="800" />
*The Sovran Hub: manage your private infrastructure from one place.*
*The Hub: your whole system at a glance — Bitcoin, Lightning, and your private apps.*
### Example home setup
@@ -300,7 +300,7 @@ From one place, the Hub helps you:
┌──────────────────────────┐
│ Sovran_SystemsOS │
│ │
│ • Sovran Hub │
│ • The Hub │
│ • Bitcoin node │
│ • Sparrow Wallet │
│ • Bisq and Bisq 2 │
@@ -345,8 +345,8 @@ with an imaging application such as [Balena Etcher](https://etcher.balena.io).
### 1. Download the ISO and checksum
- [Download Sovran_SystemsOS-1.1.5.iso](https://downloads.sovransystems.com/Sovran_SystemsOS-1.1.5.iso)
- [Download Sovran_SystemsOS-1.1.5.iso.sha256](https://downloads.sovransystems.com/Sovran_SystemsOS-1.1.5.iso.sha256)
- [Download Sovran_SystemsOS-1.1.7.iso](https://downloads.sovransystems.com/Sovran_SystemsOS-1.1.7.iso)
- [Download Sovran_SystemsOS-1.1.7.iso.sha256](https://downloads.sovransystems.com/Sovran_SystemsOS-1.1.7.iso.sha256)
The download may take some time. Do not rename or modify the ISO before
verifying it, and keep both files in the same folder.
@@ -364,16 +364,16 @@ checksum exactly.
Open a terminal in the download folder and run:
```bash
sha256sum --check Sovran_SystemsOS-1.1.5.iso.sha256
sha256sum --check Sovran_SystemsOS-1.1.7.iso.sha256
```
A successful comparison reports:
```text
Sovran_SystemsOS-1.1.5.iso: OK
Sovran_SystemsOS-1.1.7.iso: OK
```
You can also run `sha256sum Sovran_SystemsOS-1.1.5.iso` and compare the output
You can also run `sha256sum Sovran_SystemsOS-1.1.7.iso` and compare the output
against the checksum file manually.
</details>
@@ -384,11 +384,11 @@ against the checksum file manually.
Open Terminal in the download folder and run:
```bash
shasum -a 256 Sovran_SystemsOS-1.1.5.iso
shasum -a 256 Sovran_SystemsOS-1.1.7.iso
```
Compare the value shown in Terminal with the value inside
`Sovran_SystemsOS-1.1.5.iso.sha256`.
`Sovran_SystemsOS-1.1.7.iso.sha256`.
</details>
@@ -398,7 +398,7 @@ Compare the value shown in Terminal with the value inside
Open PowerShell in the download folder and run:
```powershell
Get-FileHash .\Sovran_SystemsOS-1.1.5.iso -Algorithm SHA256
Get-FileHash .\Sovran_SystemsOS-1.1.7.iso -Algorithm SHA256
```
Compare the value under `Hash` with the published checksum.
@@ -413,7 +413,7 @@ match exactly.
1. Download and install [Balena Etcher](https://etcher.balena.io), then
connect the USB drive.
2. Choose **Flash from file** and select `Sovran_SystemsOS-1.1.5.iso`.
2. Choose **Flash from file** and select `Sovran_SystemsOS-1.1.7.iso`.
3. Choose **Select target**, select the USB drive, and review your selection
carefully.
4. Choose **Flash** and wait for the writing and verification process to
@@ -856,7 +856,7 @@ primary location for collaboration. Please read our
## Privacy. Sovereignty. Bitcoin.
[Visit Sovran Systems](https://sovransystems.com) ·
[Download Sovran_SystemsOS](https://downloads.sovransystems.com/Sovran_SystemsOS-1.1.5.iso) ·
[Download Sovran_SystemsOS](https://downloads.sovransystems.com/Sovran_SystemsOS-1.1.7.iso) ·
[View the License](LICENSE)
</div>
+1 -1
View File
@@ -1 +1 @@
1.1.5
1.1.7
Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 KiB

After

Width:  |  Height:  |  Size: 59 KiB

+36
View File
@@ -165,6 +165,14 @@
programs.fish = { enable = true; promptInit = "fastfetch"; };
# ── PostgreSQL base ────────────────────────────────────────
# Shared cluster for Nextcloud (nextclouddb) + Matrix Synapse.
# Sized for the README's Server + Desktop recommendation (32 GB RAM,
# 500 GB NVMe OS + 2 TB NVMe timechain). Postgres shares the box with
# Bitcoin Core, Electrs, LND, MariaDB, PHP-FPM and GNOME, so
# shared_buffers stays below the 25%-of-RAM dedicated-server rule.
# Fixes Nextcloud 35 Database checks (pg.cache_hit_ratio,
# pg.dead_tuples). Override in custom.nix for other hosts, e.g.:
# services.postgresql.settings.shared_buffers = lib.mkForce "512MB";
services.postgresql = {
enable = true;
authentication = lib.mkForce ''
@@ -172,6 +180,34 @@
host all all 127.0.0.1/32 trust
host all all ::1/128 trust
'';
settings = {
# Memory — fixes low buffer cache hit ratio (stock default is
# 128MB shared_buffers). effective_cache_size is only a planner
# hint, not an allocation, so it can be generous.
# NOTE: changing shared_buffers requires a Postgres restart.
shared_buffers = "2GB";
effective_cache_size = "12GB";
maintenance_work_mem = "512MB";
work_mem = "32MB";
wal_buffers = "64MB";
# Checkpoints — spread write bursts out on NVMe. Reload-only.
min_wal_size = "1GB";
max_wal_size = "4GB";
checkpoint_completion_target = 0.9;
# Autovacuum — the stock 60s naptime can't keep up with
# Nextcloud's and Synapse's write-heavy tables (filecache,
# activity, jobs, state). Reload-only.
autovacuum_naptime = "30s";
autovacuum_vacuum_scale_factor = 0.05;
autovacuum_analyze_scale_factor = 0.025;
autovacuum_max_workers = 4;
# NVMe planner assumptions (README: NVMe OS + data disks).
random_page_cost = "1.1";
effective_io_concurrency = 200;
};
};
# ── Backups ────────────────────────────────────────────────
Generated
+28 -45
View File
@@ -5,11 +5,11 @@
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1788871704,
"narHash": "sha256-Vtc2SqCB7NOO028+K5JHbpWQ3XVpLyoC75MZQ12l13o=",
"lastModified": 1789651044,
"narHash": "sha256-4VAbiqMJXW/fgdMqDN4+03PkCa3xRnWi4zEX9J6/QRk=",
"owner": "emmanuelrosa",
"repo": "btc-clients-nix",
"rev": "e14502cba22806341f8c54c6f0c349094830c58b",
"rev": "bc71039666a17100c49e67a93e1d7a15f31dee47",
"type": "github"
},
"original": {
@@ -26,11 +26,11 @@
]
},
"locked": {
"lastModified": 1787559586,
"narHash": "sha256-onL0VLf9vPllmT0H/OlURIU5r5t5WIEl7t4tVNKT0Nw=",
"lastModified": 1788450739,
"narHash": "sha256-glZLQlzIn1fXH6PazR2iUmTo7kzzyYSshrWhLS9TqCU=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "9d0d87172c374f89da73c1cfe6d81ae62feac1f1",
"rev": "31729ca8cbdb4fa927b34e5f4353e6a83f39e993",
"type": "github"
},
"original": {
@@ -41,11 +41,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1788179970,
"narHash": "sha256-r5LmxzIhsu5+oDybatN/HJ8roYOKjb2Apa5xI6v46VU=",
"lastModified": 1789563672,
"narHash": "sha256-05W7P4/pqgpliOA/HyZM6IkKd6ojI8L5X/x9tgthckI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1db62ab7d2ccf1916bbf7deb61fc9d16f1c4ab49",
"rev": "88142f2dc8f2727eec89047694ec8000f92ce542",
"type": "github"
},
"original": {
@@ -56,27 +56,11 @@
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1788921488,
"narHash": "sha256-8+xWRxEkD6l217cIUdRxfeUGS9lQX0hVtUuNVsBaDzk=",
"lastModified": 1789885152,
"narHash": "sha256-mDNo95riUw8k0MA2Btzj/OuiMcfLKofqIliLYsLbrSY=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "6aefcda9401be8acc2b74244fb3b37520ea1f0a8",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-26.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable_2": {
"locked": {
"lastModified": 1788807765,
"narHash": "sha256-J9oC0bKnkXUrMegqRTXVkyDFJ0gn2U/Qpoo9HgGMQmA=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "93108a538f079596c9a16c72cf03e9322782b6dd",
"rev": "6d663c0533ff269008fb84e45930151e37c99db9",
"type": "github"
},
"original": {
@@ -88,11 +72,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1788881743,
"narHash": "sha256-2V9GZGvPfrNzxFozhI9dcqV+c3QdA8YZrvAAzqEB+dI=",
"lastModified": 1789921291,
"narHash": "sha256-Ft/BRnIqw1MywFoXydKobjjWmDFgDdYtSpJliE8+yUw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d6524aaca2ff07876657ae2b323f24be4874944b",
"rev": "44a91898084f46797b5fac650c7e8c9ac38c43d4",
"type": "github"
},
"original": {
@@ -104,11 +88,11 @@
},
"nixpkgs_3": {
"locked": {
"lastModified": 1787631388,
"narHash": "sha256-vMiXptXarfSdJb1Gkc+FYVOAibuBRj7qxGa8z68q1Uw=",
"lastModified": 1789724158,
"narHash": "sha256-nlKgrm0dsVhOSopKheVBCcOpiIticufPPVLdVOI0euA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ac6b2166e7a9375683b8e98f860f273222337b16",
"rev": "0a3468a402c449992505b6a9fc5b06580141b750",
"type": "github"
},
"original": {
@@ -120,11 +104,11 @@
},
"nixpkgs_4": {
"locked": {
"lastModified": 1788881743,
"narHash": "sha256-2V9GZGvPfrNzxFozhI9dcqV+c3QdA8YZrvAAzqEB+dI=",
"lastModified": 1789921291,
"narHash": "sha256-Ft/BRnIqw1MywFoXydKobjjWmDFgDdYtSpJliE8+yUw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d6524aaca2ff07876657ae2b323f24be4874944b",
"rev": "44a91898084f46797b5fac650c7e8c9ac38c43d4",
"type": "github"
},
"original": {
@@ -141,11 +125,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1788190018,
"narHash": "sha256-59BAfH0txPAZrPBF4QJqwvUWppD+ICrcjA1LZAmPnrQ=",
"lastModified": 1789961561,
"narHash": "sha256-2lRgE8XsmXIVmiujmHVaCy5TrBUSblILNT5vYOj/Ed0=",
"owner": "nix-community",
"repo": "nixvim",
"rev": "41844750e55f17b1385d5b09ca7ade5f11f49506",
"rev": "bcb5f577a36565bda07d7b81346b73cad8618d16",
"type": "github"
},
"original": {
@@ -165,15 +149,14 @@
},
"sovran-bitcoin": {
"inputs": {
"nixpkgs": "nixpkgs_4",
"nixpkgs-stable": "nixpkgs-stable_2"
"nixpkgs": "nixpkgs_4"
},
"locked": {
"lastModified": 1788921077,
"narHash": "sha256-k2i55M0lK3xzjsJKS/kOhQHSf8479r6RYEllnICxggg=",
"lastModified": 1790031910,
"narHash": "sha256-aqwWD6FfKxhF7edo/ryn2Um8yMCr/MN5HXNIot4KB2k=",
"owner": "naturallaw777",
"repo": "Sovran_Bitcoin",
"rev": "7c4d5b509c0533ea48192146f987182668bf42dc",
"rev": "4acd272bec53cb88300535d6238e72ad20bd90f1",
"type": "github"
},
"original": {
-29
View File
@@ -6,8 +6,6 @@
nixvim.url = "github:nix-community/nixvim";
btc-clients.url = "github:emmanuelrosa/btc-clients-nix";
nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-26.05";
# Bitcoin / Lightning stack — standalone flake, consumed as a module.
sovran-bitcoin.url = "github:naturallaw777/Sovran_Bitcoin";
};
@@ -19,24 +17,6 @@
system = prev.stdenv.hostPlatform.system;
config.allowUnfree = true;
};
# Pin LiveKit to 1.13.6: element-calling.nix sets
# rtc.advertise_internal_ip, which gives LAN callers a host candidate
# so calls work on Wi-Fi without the router needing NAT-hairpin. That
# flag is only honoured when node_ip is set manually from LiveKit
# v1.13.6 (mediatransportutil f234b53); nixpkgs-unstable currently
# ships 1.13.5. Remove this override once nixpkgs-unstable reaches
# >= 1.13.6.
livekit = prev.livekit.overrideAttrs (old: {
version = "1.13.6";
src = prev.fetchFromGitHub {
owner = "livekit";
repo = "livekit";
rev = "v1.13.6";
hash = "sha256-sUAx6ooeEUUqot5xuZv7xiQa3DdRFVULteTwYgFUzCI=";
};
vendorHash = "sha256-nOGSmoNuQQm/sIVI1HojsiS4GkbhA68uYMQ6X7d4a5Q=";
});
};
in
{
@@ -77,14 +57,5 @@
];
};
};
checks.x86_64-linux = let
pkgs = import nixpkgs {
system = "x86_64-linux";
};
in {
# Bitcoin hardening and package checks now live in the Sovran_Bitcoin flake.
# Run them with: nix build github:naturallaw777/Sovran_Bitcoin#checks.x86_64-linux
};
};
}
+112 -3
View File
@@ -3,10 +3,22 @@
lib.mkIf config.sovran_systemsOS.services.nextcloud {
# ── PostgreSQL database ───────────────────────────────────
# Cluster-wide tuning (shared_buffers, autovacuum) lives in
# configuration.nix so it is shared with Matrix Synapse.
services.postgresql = {
enable = true;
};
# ── Redis for Nextcloud distributed cache + file locking ───
# Nextcloud does not recommend APCu for memcache.locking in production.
# TCP on localhost avoids unix-socket permission juggling with the caddy user.
# Scoped to Nextcloud only — Synapse / MariaDB / Bitcoin are unaffected.
services.redis.servers.nextcloud = {
enable = true;
bind = "127.0.0.1";
port = 6379;
};
# ── Auto-generate DB password and initialize ──────────────
systemd.services.nextcloud-db-init = {
description = "Initialize Nextcloud PostgreSQL database with auto-generated password";
@@ -47,14 +59,20 @@ lib.mkIf config.sovran_systemsOS.services.nextcloud {
if ! psql -U postgres -lqt | cut -d \| -f 1 | grep -qw "nextclouddb"; then
psql -U postgres -c "CREATE DATABASE nextclouddb WITH OWNER ncusr TEMPLATE template0 LC_COLLATE = 'C' LC_CTYPE = 'C';"
fi
# NOTE: autovacuum GUCs are SIGHUP-context, so they cannot be set
# per-database ALTER DATABASE ... SET rejects them with
# 'parameter "..." cannot be changed now'. They are set
# cluster-wide in configuration.nix instead, which already covers
# both nextclouddb and matrix-synapse.
'';
};
# ── Fully automated Nextcloud setup ───────────────────────
systemd.services.nextcloud-init = {
description = "Download, extract, and fully configure Nextcloud";
after = [ "network-online.target" "postgresql.service" "phpfpm-nextcloud.service" "nextcloud-db-init.service" ];
wants = [ "network-online.target" ];
after = [ "network-online.target" "postgresql.service" "phpfpm-nextcloud.service" "nextcloud-db-init.service" "redis-nextcloud.service" ];
wants = [ "network-online.target" "redis-nextcloud.service" ];
requires = [ "postgresql.service" "nextcloud-db-init.service" ];
wantedBy = [ "multi-user.target" ];
@@ -150,7 +168,11 @@ lib.mkIf config.sovran_systemsOS.services.nextcloud {
php $INSTALL_DIR/occ config:system:set default_phone_region --value='US'
php $INSTALL_DIR/occ config:system:set maintenance_window_start --type=integer --value=1
php $INSTALL_DIR/occ config:system:set memcache.local --value='\OC\Memcache\APCu'
php $INSTALL_DIR/occ config:system:set memcache.locking --value='\OC\Memcache\APCu'
php $INSTALL_DIR/occ config:system:set memcache.distributed --value='\OC\Memcache\Redis'
php $INSTALL_DIR/occ config:system:set memcache.locking --value='\OC\Memcache\Redis'
php $INSTALL_DIR/occ config:system:set redis host --value='127.0.0.1'
php $INSTALL_DIR/occ config:system:set redis port --type=integer --value=6379
php $INSTALL_DIR/occ config:system:set redis timeout --value='1.5'
php $INSTALL_DIR/occ config:system:set server_id --value='$SERVER_ID'
php $INSTALL_DIR/occ background:cron
"
@@ -247,6 +269,93 @@ CREDS
'';
};
# ── Migrate existing installs to Redis locking ────────────
# nextcloud-init only runs on fresh installs (ConditionPathExists
# !config.php), so pre-existing / pre-Sovran installs would keep
# APCu locking forever. This one-shot is idempotent and safe to
# re-run on every boot — occ just overwrites the same values.
systemd.services.nextcloud-redis-migrate = {
description = "Point existing Nextcloud installs at Redis locking";
after = [ "postgresql.service" "redis-nextcloud.service" "phpfpm-nextcloud.service" ];
wants = [ "redis-nextcloud.service" ];
wantedBy = [ "multi-user.target" ];
unitConfig = {
ConditionPathExists = [
"/var/lib/www/nextcloud/occ"
"/var/lib/www/nextcloud/config/config.php"
];
};
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
path = with pkgs; [ coreutils shadow ];
script = ''
set -euo pipefail
INSTALL_DIR="/var/lib/www/nextcloud"
# Wait briefly for Redis (TCP localhost:6379).
for i in $(seq 1 15); do
if (echo > /dev/tcp/127.0.0.1/6379) >/dev/null 2>&1; then
break
fi
sleep 2
done
/run/wrappers/bin/su -s /bin/sh caddy -c "
php $INSTALL_DIR/occ config:system:set memcache.local --value='\OC\Memcache\APCu'
php $INSTALL_DIR/occ config:system:set memcache.distributed --value='\OC\Memcache\Redis'
php $INSTALL_DIR/occ config:system:set memcache.locking --value='\OC\Memcache\Redis'
php $INSTALL_DIR/occ config:system:set redis host --value='127.0.0.1'
php $INSTALL_DIR/occ config:system:set redis port --type=integer --value=6379
php $INSTALL_DIR/occ config:system:set redis timeout --value='1.5'
"
'';
};
# ── Recurring DB maintenance (Nextcloud 35 checks) ───────────
# nextcloud-init runs db:add-missing-indices exactly once. Upgrades
# (e.g. to NC35) and later app installs (Mail, Guests) add tables
# like oc_mail_tags / oc_guests_users that then seq-scan forever.
# Weekly: VACUUM ANALYZE (dead tuples) + backfill missing indices.
# Scoped to nextclouddb only — matrix-synapse is untouched.
systemd.services.nextcloud-db-maintenance = {
description = "Nextcloud DB maintenance: VACUUM + missing indices";
after = [ "postgresql.service" "redis-nextcloud.service" "phpfpm-nextcloud.service" ];
wants = [ "postgresql.service" ];
unitConfig = {
ConditionPathExists = [
"/var/lib/www/nextcloud/occ"
"/var/lib/www/nextcloud/config/config.php"
];
};
serviceConfig = {
Type = "oneshot";
};
path = [ config.services.postgresql.package pkgs.coreutils pkgs.shadow ];
script = ''
set -euo pipefail
INSTALL_DIR="/var/lib/www/nextcloud"
echo "Vacuuming nextclouddb..."
psql -U postgres -d nextclouddb -c "VACUUM (ANALYZE);"
echo "Backfilling Nextcloud indices..."
/run/wrappers/bin/su -s /bin/sh caddy -c "
php $INSTALL_DIR/occ db:add-missing-indices
php $INSTALL_DIR/occ db:add-missing-columns
php $INSTALL_DIR/occ db:add-missing-primary-keys
"
echo "Nextcloud DB maintenance complete."
'';
};
systemd.timers.nextcloud-db-maintenance = {
description = "Weekly Nextcloud DB maintenance";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "Sun 03:30";
Persistent = true;
RandomizedDelaySec = "30m";
};
};
services.cron.systemCronJobs = [
"*/5 * * * * caddy /run/current-system/sw/bin/php -f /var/lib/www/nextcloud/cron.php"
];
+59 -17
View File
@@ -1,29 +1,70 @@
{ config, pkgs, lib, ... }:
# ── Shared PHP for Nextcloud + WordPress ──────────────────────────────────────
#
# One interpreter (with one extension set and one php.ini) is shared by the
# phpfpm-nextcloud and phpfpm-wordpress pools, the Nextcloud cron job and the
# occ / wp-cli helper scripts. Every consumer must reference
# config.sovran_systemsOS.phpPackage (or /run/current-system/sw/bin/php) so
# that the CLI and the FPM pools always run the *same* PHP.
#
# Version policy (September 2026):
# • Nextcloud 35 supports PHP 8.3 / 8.4 / 8.5 and recommends 8.5. Its setup
# check flags 8.3 as "deprecated since Nextcloud 35" and warns that
# Nextcloud 36 may require at least 8.4.
# • WordPress 6.9 / 7.0 fully support PHP 8.4 and 8.5.
# • PHP 8.3 has been security-only since 2025-12-31; PHP 8.4 leaves active
# support on 2026-12-31; PHP 8.5 is actively supported until 2027-12-31.
#
# To fall back to PHP 8.4 (nixpkgs' current default `pkgs.php`) change only
# the `phpBase` line below.
let
phpBase = pkgs.php85;
custom-php = phpBase.buildEnv {
# `enabled` is nixpkgs' default extension set. It already contains every
# module Nextcloud lists as required or recommended (ctype, curl, dom,
# fileinfo, gd, intl, mbstring, openssl, posix, session, simplexml,
# xmlreader, xmlwriter, zip, zlib, pdo_pgsql, pdo_mysql, bcmath, gmp,
# exif, sodium, sysvsem, pcntl, ...). OPcache is compiled into PHP >= 8.5
# and no longer appears as a separate extension.
extensions = { enabled, all }: enabled ++ (with all; [
bz2 # Nextcloud: bz2 archive support
apcu # Nextcloud: memcache.local (apc.enable_cli=1 below is mandatory for occ + cron)
redis # Nextcloud: memcache.distributed / file locking once a Redis server is configured
imagick # Nextcloud: previews + theming (nixpkgs ImageMagick is built with SVG support)
memcached # WordPress object-cache plugins (legacy option for Nextcloud)
]);
custom-php = pkgs.php83.buildEnv {
extensions = { enabled, all }: enabled ++ (with all; [ bz2 apcu redis imagick memcached ]);
extraConfig = ''
display_errors = On
display_startup_errors = On
; Error handling (production)
display_errors = Off
display_startup_errors = Off
log_errors = On
; Limits
max_execution_time = 10000
max_input_time = 3000
memory_limit = 1G;
opcache.enable=1;
opcache.memory_consumption=512;
opcache_revalidate_freq = 240;
opcache.max_accelerated_files=20000;
memory_limit = 1G
post_max_size = 3G
upload_max_filesize = 3G
apc.enable_cli=1
; OPcache (Nextcloud "Server tuning" recommendations)
opcache.enable = 1
opcache.memory_consumption = 512
opcache.interned_strings_buffer = 192
redis.session.locking_enabled=1
redis.session.lock_retries=-1
redis.session.lock_wait_time=10000
opcache.max_accelerated_files = 20000
opcache.revalidate_freq = 240
opcache.save_comments = 1
; APCu
apc.enable_cli = 1
; phpredis session locking (only used with session.save_handler = redis)
redis.session.locking_enabled = 1
redis.session.lock_retries = -1
redis.session.lock_wait_time = 10000
'';
};
in
@@ -46,12 +87,13 @@ in
};
users.users.php.group = "php";
users.groups.php = {};
environment.systemPackages = with pkgs; [
custom-php
];
};
}
+33
View File
@@ -94,16 +94,23 @@ EOF
# ── Synapse service ─────────────────────────────────────────
services.matrix-synapse = {
enable = true;
# cache-memory provides cache-size statistics for the autotuning below
# (in addition to the NixOS defaults).
extras = [ "systemd" "postgres" "url-preview" "cache-memory" ];
extraConfigFiles = [
"/run/matrix-synapse/runtime-config.yaml"
];
settings = {
database = {
name = "psycopg2";
# Recycle pooled connections less often (fewer reconnects).
txn_limit = 10000;
args = {
host = "localhost";
database = "matrix-synapse";
user = "matrix-synapse";
cp_min = 5;
cp_max = 15;
};
};
push.include_content = false;
@@ -120,6 +127,32 @@ EOF
];
presence.enabled = true;
enable_registration = false;
# ── Performance (32 GB Server + Desktop) ─────────────────
# Synapse trades RAM for fewer Postgres round-trips; most RAM goes
# to caches. Stock is global_factor 0.5 + 10K event cache, which
# leaves syncs hitting the database on every request.
# Deliberately unchanged: presence and URL previews stay enabled —
# disabling them is faster but changes user-visible behavior.
event_cache_size = "100K";
caches = {
global_factor = 4.0;
expire_caches = true;
cache_entry_ttl = "30m";
sync_response_cache_duration = "2m";
cache_autotuning = {
max_cache_memory_usage = "2G";
target_cache_memory_usage = "1G";
min_cache_ttl = "30s";
};
per_cache_factors = {
# Hot paths for /sync and room joins.
get_users_in_room = 3.0;
get_current_state_ids = 3.0;
get_unread_event_push_actions_by_room_for_user = 5.0;
};
};
# Fewer GC pauses at the cost of a little more memory.
gc_thresholds = [ 1500 20 10 ];
listeners = [
{
port = 8008;