How-to: Nextcloud Full Text Search with the Cloudron Elasticsearch community package
-
This guide configures Nextcloud Full Text Search (FTS) to use Elasticsearch over the Cloudron-internal app network.
The Elasticsearch REST API is not public. The public app URL exposes only a minimal health endpoint; Nextcloud connects directly to Elasticsearch on internal port
9200.1. Install Elasticsearch from the community catalog
In Cloudron, open:
App Store → Settings → Community AppsAdd this catalog URL:
https://git.due.ren/andreas/elasticsearch-cloudron/-/raw/main/CloudronVersions.jsonOr install through the Cloudron CLI:
cloudron install \ --versions-url https://git.due.ren/andreas/elasticsearch-cloudron/-/raw/main/CloudronVersions.json \ --location elasticsearch.example.comInstalling from this catalog makes the app community-tracked, allowing Cloudron to discover later package releases through its normal update mechanism.
Allocate at least 4 GB RAM where possible. The package sizes Elasticsearch's JVM heap from the app memory limit.
2. Obtain the internal Elasticsearch address and credential
Open the Elasticsearch app's Web Terminal and run:
hostname cat /app/data/credentials.txthostnameprints the Cloudron app ID. This is the internal hostname that other Cloudron apps can resolve for the lifetime of this installed app.Use the app-ID hostname, not the container IP. Container IP addresses are not a supported configuration value and can change.
The internal Elasticsearch endpoint is:
http://<APP_ID_HOSTNAME>:9200For example:
http://210f8b84-f417-4697-80b7-efefd18e7329:9200The generated password is also available at:
/app/data/secrets/elastic_passwordTreat it as a secret. A Cloudron app that has both this password and the internal hostname can query Elasticsearch.
Important: If the Elasticsearch app is removed and installed again, it receives a new app ID. Update the Nextcloud
elastic_hostconfiguration after such a migration.3. Enable the Nextcloud FTS apps
Open the Nextcloud app's Web Terminal and run:
sudo -u www-data php /app/code/occ app:enable fulltextsearch sudo -u www-data php /app/code/occ app:enable fulltextsearch_elasticsearch sudo -u www-data php /app/code/occ app:enable files_fulltextsearch4. Configure Nextcloud
Set the FTS platform and the index name:
sudo -u www-data php /app/code/occ config:app:set \ fulltextsearch app_navigation --value "1" sudo -u www-data php /app/code/occ config:app:set \ fulltextsearch search_platform \ --value "OCA\\FullTextSearch_Elasticsearch\\Platform\\ElasticSearchPlatform" sudo -u www-data php /app/code/occ config:app:set \ fulltextsearch_elasticsearch elastic_index --value "nextcloud"Set the Elasticsearch connection. The password must be URL-encoded if it contains URL-reserved characters such as
@,:,/,?,#, or%.sudo -u www-data php /app/code/occ config:app:set \ fulltextsearch_elasticsearch elastic_host \ --value "http://elastic:URL_ENCODED_PASSWORD@APP_ID_HOSTNAME:9200"Replace:
URL_ENCODED_PASSWORDwith the generated Elasticsearch password, URL-encoded where necessary.APP_ID_HOSTNAMEwith the value returned byhostnamein the Elasticsearch app.
Example shape:
http://elastic:REDACTED@210f8b84-f417-4697-80b7-efefd18e7329:92005. Test and build the index
sudo -u www-data php /app/code/occ fulltextsearch:test sudo -u www-data php /app/code/occ fulltextsearch:indexThe first indexing run can take time, depending on the number and size of files.
Elasticsearch's built-in
germananalyzer is available. No separate ICU plugin is required for the standard German analyzer.6. Verify Elasticsearch and the public boundary
Inside the Elasticsearch app:
curl -u elastic:$(cat /app/data/secrets/elastic_password) \ http://localhost:9200/_cat/indices?vYou should see the
nextcloudindex after indexing.From outside the Cloudron, verify that Elasticsearch API routes are not public:
curl -i https://elasticsearch.example.com/_cat/indicesExpected result:
HTTP 404 {"status":"not_found"}The harmless public health endpoint should remain available:
curl -i https://elasticsearch.example.com/healthExpected result:
HTTP 200 {"status":"green","service":"elasticsearch-cloudron"}Security and operational notes
- Elasticsearch REST runs on internal port
9200; it is not routed through the public Cloudron reverse proxy. - The public Cloudron
httpPortserves only/health. - The Elasticsearch transport port
9300has no external Cloudron port mapping. - HTTP CORS is disabled by default.
- Elasticsearch data persists in
/app/data; routine package updates do not normally require a re-index. - Do not use container IP addresses in Nextcloud configuration.
-
Thanks for the write up.
@andreasdueren do you think the elasticsearch package can make use of https://docs.cloudron.io/packaging/manifest#backupcommand ? Since filesystem backup is not atomic on Cloudron, this might bring more consistency to the elasticsearch backups (since elastic is a "database").
-
Thanks for the write up.
@andreasdueren do you think the elasticsearch package can make use of https://docs.cloudron.io/packaging/manifest#backupcommand ? Since filesystem backup is not atomic on Cloudron, this might bring more consistency to the elasticsearch backups (since elastic is a "database").
@girish Thanks, didn't know about this feature and implemented what I understood to be best practice in the latest version:
The package now uses Cloudron’s
backupCommandto create an Elasticsearch filesystem snapshot before Cloudron copies/app/data.That snapshot is created by Elasticsearch, waits for
SUCCESS, and is included in the normal Cloudron app backup under:/app/data/snapshotsSo the current situation is:
Cloudron backup ├── normal /app/data filesystem copy └── completed Elasticsearch snapshotIf the restored raw Elasticsearch data starts normally, nothing else is required. If it does not, the Elasticsearch snapshot is the supported recovery source.
I considered stopping Elasticsearch for the entire Cloudron filesystem-copy phase to make the raw copy consistent, but that would add backup downtime and probably be less robust than Elasticsearch’s own snapshot mechanism.
-
@andreasdueren there is a companion command called
restoreCommandwhich will restore from the snapshot into the filesystem . You also don't need to back up the raw elastic files, you can use persistentDirs -
@andreasdueren there is a companion command called
restoreCommandwhich will restore from the snapshot into the filesystem . You also don't need to back up the raw elastic files, you can use persistentDirs@girish That was the missing piece, thank you. I mistakenly had concluded from the
backupCommanddocs alone that there was no restore-side hook.restoreCommandis documented, it just isn't cross-linked frombackupCommand.One thing I hit that may be a bug in
9.2.0: the docs state thebackupCommandcontainer shares the app container's network namespace, so services onlocalhostare reachable. On my install that did not work.curlto127.0.0.1:9200failed with exit code 7 (connection refused / could not connect) duringbackupCommand, on two separate package releases, including one with--retry 30 --retry-delay 2 --retry-connrefusedretrying for roughly a minute. The identical command run inside the live app container viacloudron execsucceeded immediately, and the app was healthy throughout.I worked around it for now by having
backupCommandtalk to the live container over a Unix socket in/app/data/runinstead of TCP. Happy to provide logs or a minimal reproducer if that's unexpected.restoreCommandshouldn't care since the app isn't running at that point, butbackupCommanddoes depend on it.
Hello! It looks like you're interested in this conversation, but you don't have an account yet.
Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.
With your input, this post could be even better 💗
Register Login
