Nextcloud home deployment
1. Intro
I wanted to play with a home setup alternative to Cloud services like Dropbox or Google Drive with basically only one requirement: there should be working clients for all the systems I use: Linux, Android and Windows.
The first thing I wanted to play with is note synchronization among all my devices, for which nowadays I’m using mainly two tools:
- Joplin (joplin-cli) for Markdown based notes
- Emacs org-mode and Orgzly on Android
The biggest restrictions for the setup came from the Android clients, in particular Orgzly:
- Both Joplin and Orgzly work with Dropbox out of the box (Joplin also supports Nextcloud out of the box)
- Both support WebDAV for syncing, but Orgzly will only work with services over HTTPS
- Both support syncing to a local folder which could then be synced externally with whatever method you want to use
1.1. Nextcloud vs Owncloud
The two biggest solutions on the home cloud space seem to be Nextcloud and Owncloud. Nextcloud is actually a fork of Owncloud from the original developer.
A work we use a custom solution based in Owncloud and my experience with the android client is particularly bad. I tried to sync a local folder for some quick tests with Orgzly and the syncing kept breaking, with the client ending in an unresponsive state and needing a cold restart.
Just because of that I decided to try Nextcloud instead for this setup.
2. First execution
I launched a quick instance using docker following the recommended instructions in the Docker Hub Nextcloud guide to get a feel of the application.
After playing a bit and reading the rest of the sections in the link, I opted to override the default apache config to enable SSL, use an external database, and set a volume for the actual data.
I extracted the default apache config from the running container with
mkdir apache2 docker cp nextcloud_app_1:/etc/apache2 ./apache2
You can do the same with /var/www/html to get a copy of the application data, or you can run docker with a volume mapping to a local empty folder and the installation process will setup things there (You will want to do this to keep your data in some permanent storage solution anyway).
3. Customizing configuration
3.1. SSL Certificates
Because of the Orgzly requirement for HTTPS I needed to reconfigure apache to serve using TLS.
I use a dynamic DNS domain name provided by Duck Duck DNS to access my home network from the internet via Wireguard. With this setup, and Let’s encrypt support for DNS based certificate requests I obtained a wildcard certificate (so I can reuse it for other internal services) using Lego:
DUCKDNS_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXX \ lego --dns duckdns --domains "*.yourdomain.duckdns.org" --email your.email@whatever.place run
I placed a copy of the generated certificates to the local (working directory) ssl folder, which will be exposed to the container as a volume mounted on /etc/ssl/private.
3.2. apache configuration
With the certificates in place the following changes need to be applied to enable the apache listener on 443 and use the new let’s encrypt certificates:
- Modify apache2/sites-available/default-ssl.conf so the SSLCertificateFile and SSLCertificateKeyFile match your certificate file names:
SSLCertificateFile /etc/ssl/private/_.yourdomain.duckdns.org.crt SSLCertificateKeyFile /etc/ssl/private/_.yourdomain.duckdns.org.key
- Enable default-ssl site.
apache2/ $ ln -s sites-available/default-ssl.conf sites-enabled/default-ssl.conf
- Enable ssl module.
apache2/ $ ln -s mods-available/default-ssl.conf mods-enabled/ssl.conf apache2/ $ ln -s mods-available/default-ssl.load mods-enabled/ssl.load
3.2.1. Alternative method
An alternative for the enabling/configuration is to run the container and enable the module and the sites with the apache management tools a2enmod and a2ensite, then save the changes with docker cp.
Disclaimer: This is actually what I did, so the previous offline instructions might actually be missing something.
4. Nextcloud configuration
4.1. External Database
The Docker image already supports configuring an external database via the use of environment variables. In my case I have one PostgreSQL instance already running in my network, so I just created an account and database there and configured the values using environment variables in the docker-compose.yaml definition:
environment: POSTGRES_DB: nextcloud POSTGRES_USER: nextcloud POSTGRES_PASSWORD: XXXXXXXXX POSTGRES_HOST: A.B.C.D:5432
4.2. config/config.php trusteddomains
If you start now the container, the application will execute correctly but accesing it through the secure endpoint will fail because your particular domain is not in the list of trusteddomains. The config/config.php file needs to be modified to add your desired domain list to the list:
'trusted_domains' => array ( 0 => 'localhost:9080', 1 => 'localhost:9443', 2 => 'fqdn.your.domain.org:9080', 3 => 'fqdn.your.domain.org:9443', ),
5. Resulting Docker Compose file
After applying the configuration changes, the following docker-compose.yaml can be used to run the service with the customized configuration:
version: '3.7' volumes: nextcloud: driver: local driver_opts: o: bind type: none device: /path/to/nextcloud/local-storage ssl_private: driver: local driver_opts: o: bind type: none device: /path/to/nextcloud/ssl apache_conf: driver: local driver_opts: o: bind type: none device: /path/to/nextcloud/apache2/ services: app: image: nextcloud:apache restart: always environment: POSTGRES_DB: nextcloud POSTGRES_USER: nextcloud POSTGRES_PASSWORD: XXXXXXXXX POSTGRES_HOST: A.B.C.D:5432 ports: - 0.0.0.0:8080:80 - 0.0.0.0:8443:443 volumes: - nextcloud:/var/www/html - ssl_private:/etc/ssl/private - apache_conf:/etc/apache2