Intro
Today I had to setup a Nextcloud instance on a cloud server. A completely scripted approach (e.g. via Ansible or OpenTofu) felt a bit over-engineered in my particular case, so I went for a semi-manual installation.
By semi-manual I mean that I scripted parts of the process but not the entirety of it, back-to-back. What I did, though, was to document things in a human readable format and as granularly as possible, in case I need to get back to this and redo the installation again.
Once done with the documentation, I thought this could actually double as a blog post, so there it is. I hope you may find it interesting.
Shout out to jgart of WhereIsEveryone who pointed me to the Nextcloud Ubuntu snap and helped with a first version of this post.
Nextcloud instance setup
In the unlikely case that you've never heard of it, Nextcloud is a Free and Open Source software suite for creating and using a file hosting service.
Nextcloud-based hosting can be bought as a service from various providers. However, being an open source project, it can also be self-hosted either on a local or cloud server.
In this short guide we'll see how to set up a Nextcloud instance on a DigitalOcean cloud server. Things shouldn't be much different if you want to use a different cloud provider or if you want to use a local machine.
DigitalOcean account
You'll need a DigitalOcean account if you want to create an actual Nextcloud instance as you follow this guide. Note that you'll be charged for creating DigitalOcean machines (or droplets, in DigitalOcean jargon) and using other of their services. Spinning up a new DigitalOcean machine is very easy, make sure you cancel any unused instances to avoid extra costs.
Most DigitalOcean operations can be launched via a command-line tool called
doctl
. This guide assumes doctl
is installed and that the
DIGITALOCEAN_ACCESS_TOKEN
environment variable is set to a valid DigitalOcean
API token.
export DIGITALOCEAN_ACCESS_TOKEN=`pass show digitalocean.com/tokens/nextcloud`
In order to provision a new machine, first define the SSH key that you intend to use to connect to it. The list of the SSH keys available for a DigitalOcean account can be retrieved with the following command.
doctl compute ssh-key list
You also need to specify a system image. The list of available images can be
retrieved with doctl compute image list
or found at this page. Use a recent
Ubuntu, e.g. ubuntu-24-10-x64
.
Finally, you'll need a domain name to assign to Nextcloud once installed. Choose a domain and make sure you have access to its DNS settings.
Machine pre-configuration with cloud-init
We'll be using cloud-init to apply some initial configuration to the newly
created machine, like installing some packages and setting up a firewall.
Prepare a cloud-init configuration file like the one below, you'll need it when
provisioning the machine (see the --user-data-file
option). Note that the file
has to start with #cloud-config
to be interpreted properly.
#cloud-config package_update: true package_upgrade: true package_reboot_if_required: true write_files: - path: /etc/nftables.conf content: | flush ruleset table inet firewall { chain inbound { type filter hook input priority 0; policy drop; iif lo accept meta l4proto {icmp, ipv6-icmp} accept ct state vmap { established: accept, related: accept, invalid: drop } ct state new limit rate over 1/second burst 10 packets drop tcp dport 80 accept tcp dport 443 accept tcp dport ssh accept } chain forward { type filter hook forward priority 0; policy drop; } } runcmd: - [ systemctl, enable, nftables.service ] - [ systemctl, restart, nftables.service ] - [ snap, install, nextcloud ]
Provisioning
A new DigitalOcean machine can now be provisioned with this command.
export region=lon1 export size=s-2vcpu-4gb export image_id=ubuntu-24-10-x64 export ssh_key_id=26720555 doctl compute droplet create \ --enable-ipv6 \ --image "${image_id}" \ --region "${region}" \ --size "${size}" \ --ssh-keys "${ssh_key_id}" \ --user-data-file build/cloud-config \ --wait \ nextcloud
After a short while, the command should return a success message that includes some machine details, such as its IPv4 and IPv6 addresses.
Connect to the machine from the DigitalOcean web console and retrieve its SSH
public key fingerprint with ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key
.
From a terminal, SSH into the machine as root
, check that the SSH fingerprint
corresponds to what obtained from the web console.
Once logged in, verify that:
- The firewall has been activated correctly with
nft list ruleset
. The output should be similar to what was defined in ourcloud-config
file. - Nextcloud is running, for example by connecting to it locally with
curl localhost
.
You may now complete the Nextcloud installation - do this straightaway because Nextcloud is currently exposed to the internet and everybody can log in with the default credentials.
Nextcloud configuration
We mentioned that a domain name is required to complete the installation. Update the domain DNS with A and AAAA records pointing to the machine IPv4 and IPv6 addresses, respectively.
Run the following commands from the DigitalOcean machine.
nextcloud.enable-https lets-encrypt
This will ask you a few questions about the domain name that will be used to serve Nextcloud. Once done, continue with the following commands.
nextcloud.manual-install admin REPLACE-WITH-A-STRONG-PASSWORD
nextcloud.occ config:system:set trusted_domains 0 --value=YOUR-DOMAIN
nextcloud.occ config:system:set overwrite.cli.url --value="https://YOUR-DOMAIN"
snap set nextcloud php.memory-limit=1024M
snap set nextcloud http.compression=true
SMTP server configuration
Add the SMTP server configuration via the web interface at https://domain-name/index.php/settings/admin. Alternatively, use the occ command-line client:
cat << EOF | nextcloud.occ config:import { "mail_from_address": "nextcloud", "mail_smtpmode": "smtp", "mail_sendmailmode": "smtp", "mail_domain": "example.com", "mail_smtphost": "mail.example.com", "mail_smtpport": "587", "mail_smtpauth": 1, "mail_smtpname": "nextcloud@example.com", "mail_smtppassword": "SMTP-PASSWORD" } EOF
Parameters can also be set individually with nextcloud.occ config:system:set
KEY --value="VALUE"
, and inspected with nextcloud.occ config:system:get KEY
.
For instance:
nextcloud.occ config:system:set mail_from_address --value="nextcloud"
Security scan
At this point you may want to go to the Nextcloud Security Scan page and run a scan of your installation.
Nextcloud management
Congratulations, if you got to this point your Nextcloud instance is running and ready to use! Now let's have a look at a few more commands that will be needed in Nextcloud's day-to-day use and administration.
Users and groups
Nextcloud users can be added with this occ command:
nextcloud.occ user:add \ --display-name="Jane Doe" \ --email="jane@example.com" \ --generate-password \ --group="staff" \ jane@example.com
The --generate-password
enables a workflow where the user receives an email
notification with a link to set up their account. Note that this requires a
correctly configured SMTP server.
Use --group
to add a user to a group. Repeat the option multiple times to
specify more than one group. Any non-existing group will be created
automatically.
By default, users are created with unlimited disk quota. If you want to change that, run this command:
nextcloud.occ user:setting jane@example.com files quota 10GB
Or this one to set the quota back to unlimited:
nextcloud.occ user:setting jane@example.com files quota none
Batch import
It's possible to write a little script to import users in batch as opposed to individually. For example, let's assume our users are listed in a JSON file like this:
[ { "display-name": "Alice", "email": "alice@example.com", "groups": [ "staff", "director" ], "quota": "none", "username": "alice@example.com" }, { "display-name": "Bob", "email": "bob@example.com", "groups": [ "staff", "project-manager" ], "quota": "100GB", "username": "bob@example.com" }, { "display-name": "Charlie", "email": "charlie@example.com", "groups": [ "staff", "sales-manager" ], "quota": "20GB", "username": "charlie@example.com" } ]
Now use this script to batch-create the Nextcloud users. First install Guile and
the guile-json library with apt install guile guile-json
. The script can be
run as cat users.json | guile nextcloud-create-users.scm
.
(use-modules (json)) (use-modules (srfi srfi-1)) (define* (nextcloud-occ args) "Run a Nextcloud occ command and return its exit status." (let ((bin/occ "nextcloud.occ")) (zero? (status:exit-val (apply system* bin/occ args))))) (define (create-nextcloud-user user) "Create a Nextcloud user via Nextcloud's occ command." (let* ((display-name (assoc-ref user "display-name")) (email (assoc-ref user "email")) (groups (vector->list (assoc-ref user "groups"))) (quota (assoc-ref user "quota")) (username (assoc-ref user "username")) (args-add (append (list "user:add" "--display-name" display-name "--email" email "--generate-password") (append-map (lambda (x) (list "--group" x)) groups) (list username))) (args-quota (list "user:setting" username "files" "quota" quota))) (if (nextcloud-occ args-add) (begin (format #t "Created user ~s (~s)\n" display-name email) (when (nextcloud-occ args-quota) (format #t "User quota set to ~s\n" quota))) (format #t "Could not create user ~s (~s)\n" display-name email)))) (map create-nextcloud-user (vector->list (json->scm)))
Misc
Nextcloud maintenance
A new Nextcloud user can be added with nextcloud.occ user:add USERNAME
. A
Nextcloud password can be changed with nextcloud.occ user:resetpassword
USERNAME
.
See this website for further details.
Destroy a DigitalOcean machine
A list of currently active DigitalOcean machines can be obtained with doctl
compute droplet list
. A machine can be destroyed with doctl compute droplet
delete MACHINE-ID
.
Update 17 February 2025
Shortly after setting up the system, I ran into a problem when syncing a relatively large local folder with Nextcloud.
This is the command used (locally, from my client) for the syncing:
guix shell nextcloud-client -- nextcloudcmd \ --user user@example.com \ --password `pass show nextcloud.example.com/user@example.com` \ --non-interactive \ /home/user/nextcloud \ https://nextcloud.example.com
The syncing terminated halfway-through, with various errors and/or warnings
along the lines of "useless task found", "too many open files", "bulk upload" -
sorry, I don't have a full copy of the messages at my fingertip now. Searching
on the web, it turns out that this might be related to Nextcloud's bulkupload
setting, which can be changed with:
nextcloud.occ config:system:set bulkupload.enabled --value=false --type=boolean
Possibly unnecessary, but I restarted Nextcloud after the change, just in case. This did fix the upload issue and the sync terminates successfully now. I'm not sure what the full implications of the change are, to begin with the sync seems to be slower now but I guess that's expected. No time to investigate this further at the minute, so I'll just file it under "works for me" and leave it as it is.
Outro
This should prove that self-hosting a Nextcloud instance is pretty easy if you're at ease with basic system administration tasks. Should you go through the guide and see that something is wrong or missing, do let me know. Hope you found this useful, until next!