Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ The shared secret is read through a throwaway container that mounts only Coturn'

Two interfaces, both on the same binding and port. WebDAV is the same server under a different path, offered separately so the desktop and mobile sync clients have an address to copy.

| Interface | Id | Type | Port | Path | Description |
| --------- | -------- | ---- | ---- | ------------------ | ------------------------------ |
| Web UI | `ui` | ui | 80 | `/` | The web interface of Nextcloud |
| WebDAV | `webdav` | api | 80 | `/remote.php/dav/` | Addresses for WebDAV syncing |
| Interface | Id | Type | Port | Path | Description |
| --------- | -- | ---- | ---- | ---- | ----------- |
| Web UI | `ui` | ui | 80 | `/` | The web interface of Nextcloud |
| WebDAV | `webdav` | api | 80 | `/remote.php/dav/` | Addresses for WebDAV syncing |

Neither is masked. The addresses published for `ui` are what init writes into `trusted_domains`, so an address Nextcloud does not know about is rejected by Nextcloud itself, not by StartOS.

Expand Down Expand Up @@ -182,13 +182,15 @@ Selects the document server that opens office files — Collabora Online, ONLYOF

**Switching first deletes the settings written for the previous backend**, so a connector is never left pointed at a service that has since been uninstalled. That teardown is also what keeps the choice unambiguous: an unconfigured connector registers no file actions of its own, so exactly one handler is live in the Files UI.

**It waits on the connector app.** The setting does nothing until **Nextcloud Office** (for Collabora) or **ONLYOFFICE** (for ONLYOFFICE Docs) is installed from the Nextcloud app store and enabled. Until then the oneshot logs that it is waiting and applies the settings on a later start.
**It installs the connector app, once, on a change of selection.** The `office-suite` oneshot runs `occ app:install` for **Nextcloud Office (Collabora)** or **ONLYOFFICE** when that app is absent. Because it sits behind the signature check it fires only when the selection changes, never on an ordinary start — so an app the user later removes stays removed, and the health check reports it rather than the package silently putting it back.

**It never re-enables a disabled connector.** An app that is present but switched off is either the user's decision or a major Nextcloud upgrade disabling one with no compatible release; re-enabling it is how that protection gets undone, and it is what `Disable Non-default Apps` exists to recover from. That state falls through to the health check instead.

**The `trusted_domains` entry is load-bearing.** A document server fetches and saves files over the host bridge, and without that entry Nextcloud answers every one of those requests with `Trusted domain error` — the editor opens and then fails to load the document. Nextcloud matches on the host alone, so the bare IP covers whatever port the binding was assigned.

### Maintenance — Reset Admin Password, Disable Maintenance Mode, Disable Non-default Apps, Scan Files, Repair

- **Reset Admin Password** generates a new password for a chosen admin account and shows it once. Only while running; the account list is read live.
- **Reset Admin Password** generates a new password for a chosen admin account and shows it once. Only while running; the account list is read live. It carries a warning, so StartOS asks for confirmation first — it replaces on invocation rather than revealing the current password, and signs that user out.
- **Disable Maintenance Mode** clears a stuck maintenance flag. Only while running. **Wait first** — brief maintenance mode after an update or a restart is normal, and this is for when it has lasted more than about fifteen minutes.
- **Disable Non-default Apps** turns off every enabled app that Nextcloud does not ship, preserving the bundled set plus Calendar and Contacts. It is the recovery for an app that has made the UI return an Internal Server Error. Apps are disabled one at a time, and the result lists any that could not be — a fataling app is exactly what this action targets, so its own failure must not hide what did get disabled. Only while running, and **stable apps must be re-enabled individually afterwards.**
- **Scan Files** rebuilds the file-cache index, which is what makes files added outside Nextcloud — over WebDAV's back door, rsync, or an external-storage mount — appear with correct sizes and turn up in search.
Expand Down Expand Up @@ -243,9 +245,13 @@ A web-interface failure after the grace period is Nextcloud itself: an app that

The transient checks — Recognize Model Download, Memories Indexing, Memories Map Setup, File Scan, Repair — exist only while their task is pending, and report `loading` with a progress message throughout.

**Office Connector** (`office-connectors`) — present only while an office suite is selected. It reads Nextcloud's enabled-app list and fails while more than one office connector app is enabled.
**Office Connector** (`office-connectors`) — present only while an office suite is selected. It reads Nextcloud's enabled-app list and fails in two distinct cases, each with its own instruction.

**The selected suite's connector is not enabled.** Either it was never installed, or it has been removed or switched off since. The message says *Install* or *Enable* accordingly — telling someone to install what they already have is how a message stops being read — and names the other way out: selecting `None` in the Office Suite action. Without this the failure is silent: the reconcile simply waits, the document server runs, and nothing in Nextcloud opens in it.

**More than one office connector is enabled.** Everything is running and OpenDocument files still open; what breaks is Word, Excel and PowerPoint, silently. `richdocuments` demotes those formats the moment it sees a rival connector enabled, and the rival does not claim them unless it is configured too. The message names the app to disable.

A failure here is not a fault in any service: everything is running, and OpenDocument files still open. What breaks is Word, Excel and PowerPoint, silently — `richdocuments` demotes those formats the moment it sees a rival connector enabled, and the rival does not claim them unless it is configured. The message names the app to disable; disabling it in Nextcloud's Apps page clears the check on the next poll. It is a check rather than a task because a task can be dismissed while the breakage remains.
Both clear on the next poll once the condition is resolved. It is a check rather than a task because a task can be dismissed while the breakage remains.

## Backups and Restore

Expand Down
5 changes: 3 additions & 2 deletions instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ Nextcloud is what tells Talk where the relay is, so there is nothing to enter in
Nextcloud on its own shows your documents but cannot edit them. To edit in the browser, install one of the two office services from the Marketplace and connect it:

1. Install **Collabora Online**, unless you have a specific reason for the other one — see below. ONLYOFFICE Docs is in the Community Registry, so you would need that registry added to your server to find it.
2. In Nextcloud's web interface, open **Apps** and install the matching app — **Nextcloud Office** for Collabora, **ONLYOFFICE** for ONLYOFFICE Docs. Enable only that one: with both enabled, Nextcloud stops opening Word, Excel and PowerPoint files in either, and this service's page will name the one to disable.
3. Run the **Office Suite** action here and pick the one you installed.
2. Run the **Office Suite** action here and pick the one you installed. Nextcloud installs the app it needs for it — **Nextcloud Office (Collabora)** or **ONLYOFFICE** — and points itself at the service.

Keep only one of those apps enabled. With both on, Nextcloud stops opening Word, Excel and PowerPoint files in either, and this service's page will name the one to disable. It will also tell you if the app is ever removed or switched off while a document server is still selected.

Documents, spreadsheets and presentations then open in the browser from Files, and several people can edit the same file at once. The editor is served from your Nextcloud address, so it works the same on your local network, a public domain, or Tor.

Expand Down
4 changes: 3 additions & 1 deletion startos/actions/maintenance/resetAdmin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ export const resetAdmin = sdk.Action.withInput(
async ({ effects }) => ({
name: i18n('Reset Admin Password'),
description: i18n('Generate a new password for an admin user'),
warning: null,
warning: i18n(
'This replaces the password on the chosen account immediately. The current one stops working, and anyone signed in as that user is signed out.',
),
allowedStatuses: 'only-running',
group: 'Maintenance',
visibility: 'enabled',
Expand Down
9 changes: 8 additions & 1 deletion startos/i18n/dictionaries/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,14 @@ const dict = {
None: 144,
'Choose the document server that opens office files in your browser.': 145,
'Office Connector': 146,
'Disable or uninstall the Nextcloud app named below. More than one office app is enabled, and Nextcloud then refuses to open Word, Excel and PowerPoint files in any of them: ': 147,

'This replaces the password on the chosen account immediately. The current one stops working, and anyone signed in as that user is signed out.': 150,
'Install ': 152,
' is ready': 154,
'Disable ': 155,
' on Nextcloud’s Apps page. With two office apps enabled, Word, Excel and PowerPoint files open in neither.': 156,
'Enable ': 157,
' in Nextcloud, or select “None” using the “Office Suite” action.': 158,
} as const

/**
Expand Down
32 changes: 28 additions & 4 deletions startos/i18n/dictionaries/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,13 @@ export default {
144: 'Ninguna',
145: 'Elija el servidor de documentos que abre los archivos ofimáticos en su navegador.',
146: 'Conector ofimático',
147: 'Desactive o desinstale la aplicación de Nextcloud indicada abajo. Hay más de una aplicación ofimática activada, y entonces Nextcloud se niega a abrir archivos de Word, Excel y PowerPoint en cualquiera de ellas: ',
150: 'Esto reemplaza de inmediato la contraseña de la cuenta elegida. La actual deja de funcionar y se cierra la sesión de quien la esté usando.',
152: 'Instale ',
154: ' está listo',
155: 'Desactive ',
156: ' en la página Aplicaciones de Nextcloud. Con dos aplicaciones ofimáticas activadas, los archivos de Word, Excel y PowerPoint no se abren en ninguna.',
157: 'Active ',
158: ' en Nextcloud, o seleccione «Ninguna» con la acción «Suite ofimática».',
},
de_DE: {
0: 'Starte Nextcloud...',
Expand Down Expand Up @@ -299,7 +305,13 @@ export default {
144: 'Keine',
145: 'Wählen Sie den Dokumentenserver, der Office-Dateien in Ihrem Browser öffnet.',
146: 'Office-Connector',
147: 'Deaktivieren oder entfernen Sie die unten genannte Nextcloud-App. Es ist mehr als eine Office-App aktiviert, und Nextcloud öffnet Word-, Excel- und PowerPoint-Dateien dann in keiner von ihnen: ',
150: 'Dies ersetzt das Passwort des gewählten Kontos sofort. Das aktuelle funktioniert dann nicht mehr, und wer als dieser Benutzer angemeldet ist, wird abgemeldet.',
152: 'Installieren Sie ',
154: ' ist bereit',
155: 'Deaktivieren Sie ',
156: ' auf der Apps-Seite von Nextcloud. Sind zwei Office-Apps aktiviert, öffnen sich Word-, Excel- und PowerPoint-Dateien in keiner von beiden.',
157: 'Aktivieren Sie ',
158: ' in Nextcloud, oder wählen Sie „Keine“ über die Aktion „Office-Suite“.',
},
pl_PL: {
0: 'Uruchamianie Nextcloud...',
Expand Down Expand Up @@ -449,7 +461,13 @@ export default {
144: 'Brak',
145: 'Wybierz serwer dokumentów, który otwiera pliki biurowe w przeglądarce.',
146: 'Łącznik biurowy',
147: 'Wyłącz lub odinstaluj wskazaną poniżej aplikację Nextcloud. Włączona jest więcej niż jedna aplikacja biurowa, a wtedy Nextcloud nie otworzy plików Word, Excel ani PowerPoint w żadnej z nich: ',
150: 'To natychmiast zastąpi hasło wybranego konta. Dotychczasowe przestanie działać, a osoba zalogowana jako ten użytkownik zostanie wylogowana.',
152: 'Zainstaluj ',
154: ' jest gotowy',
155: 'Wyłącz ',
156: ' na stronie Aplikacje w Nextcloud. Przy dwóch włączonych aplikacjach biurowych pliki Word, Excel i PowerPoint nie otworzą się w żadnej z nich.',
157: 'Włącz ',
158: ' w Nextcloud albo wybierz „Brak” w akcji „Pakiet biurowy”.',
},
fr_FR: {
0: 'Démarrage de Nextcloud...',
Expand Down Expand Up @@ -599,6 +617,12 @@ export default {
144: 'Aucune',
145: 'Choisissez le serveur de documents qui ouvre les fichiers bureautiques dans votre navigateur.',
146: 'Connecteur bureautique',
147: 'Désactivez ou désinstallez l\'application Nextcloud indiquée ci-dessous. Plusieurs applications bureautiques sont activées, et Nextcloud refuse alors d\'ouvrir les fichiers Word, Excel et PowerPoint dans l\'une ou l\'autre : ',
150: 'Cela remplace immédiatement le mot de passe du compte choisi. L\'actuel cesse de fonctionner et toute personne connectée sous cet utilisateur est déconnectée.',
152: 'Installez ',
154: ' est prêt',
155: 'Désactivez ',
156: ' sur la page Applications de Nextcloud. Avec deux applications bureautiques activées, les fichiers Word, Excel et PowerPoint ne s\'ouvrent dans aucune.',
157: 'Activez ',
158: ' dans Nextcloud, ou sélectionnez « Aucune » avec l\'action « Suite bureautique ».',
},
} satisfies Record<string, LangDict>
68 changes: 59 additions & 9 deletions startos/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { createHash } from 'node:crypto'
import { writeFile } from 'node:fs/promises'
import {
APACHE_MODULES,
CONNECTOR_APP_TITLES,
DS_VPATH,
isOfficeSuite,
moduleLoadLine,
Expand All @@ -41,6 +42,7 @@ import {
getPostgresEnv,
getPostgresSub,
getValkeySub,
hasNextcloudApp,
readEnabledApps,
nextcloudMount,
TALK_APP,
Expand Down Expand Up @@ -708,17 +710,47 @@ export const main = sdk.setupMain(async ({ effects }) => {
result: 'starting' as const,
message: null,
}
const keep = officeSuiteMeta[officeSuite].connectorApp
const { connectorApp: keep, title } =
officeSuiteMeta[officeSuite]
// Selected a document server but Nextcloud has nothing to
// reach it with. Silent otherwise: the reconcile just waits.
if (!(keep in enabled)) {
// Present but disabled is a different instruction from
// absent, and telling someone to install what they already
// have is how a message stops being followed.
const present = await hasNextcloudApp(keep)
return {
result: 'failure' as const,
message: (present ? i18n('Enable ') : i18n('Install '))
.concat(CONNECTOR_APP_TITLES[keep] ?? keep)
.concat(
i18n(
' in Nextcloud, or select “None” using the “Office Suite” action.',
),
),
}
}
const rivals = OFFICE_CONNECTOR_APPS.filter(
(a) => a !== keep && a in enabled,
)
if (rivals.length === 0)
return { result: 'success' as const, message: null }
return {
result: 'success' as const,
message: title.concat(i18n(' is ready')),
}
return {
result: 'failure' as const,
message: i18n(
'Disable or uninstall the Nextcloud app named below. More than one office app is enabled, and Nextcloud then refuses to open Word, Excel and PowerPoint files in any of them: ',
).concat(rivals.join(', ')),
message: i18n('Disable ')
.concat(
rivals
.map((a) => CONNECTOR_APP_TITLES[a] ?? a)
.join(', '),
)
.concat(
i18n(
' on Nextcloud’s Apps page. With two office apps enabled, Word, Excel and PowerPoint files open in neither.',
),
),
}
},
},
Expand Down Expand Up @@ -1364,10 +1396,28 @@ async function reconcileOffice(
})
const app = officeSuiteMeta[suite].connectorApp
if (!(app in enabled)) {
console.warn(
`office-suite: the ${app} app is not enabled in Nextcloud; leaving its settings alone until it is`,
)
return
// Install it, but only when it is absent entirely, and only here — this
// runs on a change of selection, never on an ordinary start, so an app the
// user later removes stays removed and the health check reports it.
//
// A present-but-disabled app is left alone on purpose. That state is either
// the user's decision or a major Nextcloud upgrade disabling an app with no
// compatible release, and re-enabling it is exactly how that protection
// gets undone — the failure `Disable Non-default Apps` exists to recover.
if (await hasNextcloudApp(app)) {
console.warn(
`office-suite: the ${app} app is present but disabled; not re-enabling it`,
)
return
}
const res = await occ(['app:install', app])
if (res.exitCode !== 0) {
console.warn(
`office-suite: could not install ${app}: ${res.stdout.toString()} ${res.stderr.toString()}`,
)
return
}
console.info(`office-suite: installed the ${app} app`)
}

// Collabora's two URLs are set through `activate-config` rather than
Expand Down
11 changes: 10 additions & 1 deletion startos/officeSuite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ export const OFFICE_CONNECTOR_APPS = [
'officeonline',
] as const

/** Exactly what each connector is called in Nextcloud's own Apps list. */
export const CONNECTOR_APP_TITLES: Record<string, string> = {
richdocuments: 'Nextcloud Office (Collabora)',
onlyoffice: 'ONLYOFFICE',
officeonline: 'Office Online',
}

export const officeMountpoint = '/mnt/onlyoffice'
export const officeSecretPath = `${officeMountpoint}/jwt-secret`

Expand All @@ -35,7 +42,7 @@ export const officeSuiteMeta = {
internalPort: 9980,
// The daemon's id, which is what its `ready` check is named.
healthCheckId: 'cool',
// Installed by the user from the Nextcloud app store, like Talk.
title: 'Collabora Online',
connectorApp: 'richdocuments',
},
onlyoffice: {
Expand All @@ -44,6 +51,7 @@ export const officeSuiteMeta = {
hostId: 'main',
internalPort: 80,
healthCheckId: 'documentserver',
title: 'ONLYOFFICE Docs',
connectorApp: 'onlyoffice',
},
} as const satisfies Record<
Expand All @@ -54,6 +62,7 @@ export const officeSuiteMeta = {
hostId: string
internalPort: number
healthCheckId: string
title: string
connectorApp: string
}
>
Expand Down