Get Rewarded! We will reward you with up to €50 credit on your account for every tutorial that you write and we publish!

Nextcloud with fully encrypted storage

profile picture
Author
Justin Scholz
Published
2025-08-20
Time to read
14 minutes reading time

About the author- Always striving to hit the right balance.

Introduction

In light of current events — waves around — putting your own private data into a US based cloud, regardless of whether you are a US citizen or a EU citizen or somewhere else, might not be the most advisable option anymore. Especially if it's not encrypted as it can then be scanned, AI trained on it and many more things. Tools like boxcryptor exist, but I specifically wanted something where I control more of the stack.

So I set out to run my own Nextcloud — pretty much a European open-source cloudware that is a bit akin to Google Workspace without email hosting.

What I wanted to achieve:

  • Low costs
  • Controllable costs (I want them predictable - not like an AWS bill)
  • European data center
  • Expandable
  • Fully encrypted (not necessarily end-to-end, but full disk encrypted)
  • Syncing of files, calendar, contacts and the ability to host my own video calls à la zoom

The setup that I built has now survived a stress test of 120000 files being synced to it, multiple reboots, and so far is running smoothly.

This tutorial will help you set up the system, but it will not guide you on running, maintaining and updating it. It is only concerning how to get it up and running and, aside from enabling encryption, it will not cover any Nextcloud usage patterns.

Nextcloud itself has the server side encryption feature activated and encrypts all files it stores. The data backend is the Storage Box, that encrypts the files' contents (it does not encrypt the file names, sizes or folder names).

ALL data is always encrypted as it either lands on disk (which is LUKS encrypted) or it lands in the Nextcloud data directory on the Storage Box, which is encrypted through the Nextcloud server side encryption.

I am fully aware that memory is not encrypted and if you are Hetzner and you poke through the RAM of my virtual machine you can probably extract out key material. This is not my threat model. If you want to defend against such a case, don't run your software on someone else's computer in a place you don't control.

Why I care about encryption

It might not be often but it does happen that law enforcement confiscates physical hardware in a data center for analysis or that people get unauthorised physical access. By making sure that I have to manually re-enter the encryption key when there is a power cut of some sorts, it gives me a chance to decide whether I want to do that or not. Storing the encryption key at boot is like taping it next to your door outside your house "just to have it handy all the time".


Prerequisites

  • VPS on Hetzner (in their parlance a cloud server) with 4GB of RAM, 2 CPU cores and 40GB of NVME storage
  • A Hetzner Storage Box - which is essentially a 1TB NAS in the cloud for an incredibly low price

On this setup, I run a Debian system on a fully encrypted disk that requires me to manually enter the encryption key at boot time.

The Nextcloud desktop client for Mac and Windows has support for virtual file systems. This means for me that I can have the best of both world. I can sync some files and folders (like my documents folder) fully and permanently to an arbitrary location on my MacBook. And I additionally also get to have all the other folders that I don't usually sync available on demand through the file provider cloud API so I can poke around through folders and download it on demand. Really useful for stuff that I don't need available all the time.

Step 1 - Creating the server

Create a new server with the architecture type x86 (!important!). With Hetzner, you can use CX22, for example. The 2 CPU version is sufficient. Even only 2 GB can work RAM wise — I will show you how.

After you created the server, follow this guide:

How to install Ubuntu 24.04 with full disk encryption

Beware of the special section for Debian 12 with the following caveats:

  • When booted into the rescue system, you can check the full name of the Debian image by running ls /root/images and copying the Debian 12 image name into your pasteboard.

  • In the setup.conf, specify the / filesystem to be btrfs instead of ext4. Your setup.conf should look like this:

    CRYPTPASSWORD secret
    DRIVE1 /dev/sda
    BOOTLOADER grub
    HOSTNAME host.example.com
    PART /boot ext4 1G
    PART /     ext4 all crypt
    IMAGE /root/images/Debian-1211-bookworm-amd64-base.tar.gz
    SSHKEYS_URL /tmp/authorized_keys
  • Additional notice: If you add private networking it might happen that your Dropbear unlock only picks up the IP from your local network first and is unreachable over ssh. In this case temporarily disable the private network or discuss this issue with your preferred coding AI — the issue is that the private network wins the race of "which network interface responds with an IP address first".

Once that is setup, you can create yourself a Storage Box in the same region via Hetzner Console. Choose your preferred size. Create a subaccount with limited access to a specific subfolder for your Nextcloud and enable SMB access. You DON'T need to enable "external access" though as this stays in the Hetzner network.

Step 2 - Booting into the server

Now you can proceed with setting up your VPS. You can follow this guide for a basic setup:

Initial Server Setup with Ubuntu

Let's open the relevant ports on UFW for all the stuff:

sudo ufw default deny incoming
sudo ufw default allow outgoing

# HTTP for ACME/Nextcloud challenge
sudo ufw allow 80/tcp comment 'ACME-HTTP-Nextcloud'

# HTTPS for Apache container (HTTP/1.1 & HTTP/2)
sudo ufw allow 443/tcp comment 'Apache-HTTPS'

# HTTP/3 (QUIC) for Apache container
sudo ufw allow 443/udp comment 'Apache-HTTP3-QUIC'

# Admin interface of master container
sudo ufw allow 8443/tcp comment 'Master-UI-HTTPS'

# TURN server (Talk container) – TCP & UDP
sudo ufw allow 3478/tcp comment 'TURN-TCP'
sudo ufw allow 3478/udp comment 'TURN-UDP'

Once that is done, you can check your IPv4 address (if you ordered one) and IPv6 by running this command on the server:

ip -6 addr show

Your interface is probably enp1s0.

Step 3 - Pointing DNS to your server

If you now go to the domain registrar of your own domain, you can adjust the (sub)domain's A and AAAA records for your IPv4 and IPv6 addresses respectively.

Once that is done, let's go back to your VPS.

Step 4 - Creating the SMB share to the Storage Box

Back on the Hetzner VPS, go to a root shell sudo su. Stay in the root shell during the rest of the guide.

Let's first install SMB support and create a mount point that makes sure it is mounted before Docker gets started.

sudo apt update
sudo apt install cifs-utils

Replace myshare with whatever you want to call the backing storage for your Nextcloud

sudo mkdir -p /mnt/myshare

Let's write the credentials in a file (our disk is encrypted - there might be more beautiful ways - this way works for me):

sudo mkdir -p /etc/cifs-creds
sudo nano /etc/cifs-creds/myshare

Add:

username=your_smb_username
password=your_smb_password

This username and password is the username and password from your sub account of your Hetzner Storage Box.

Then we create a systemd .mount unit by running:

sudo nano /etc/systemd/system/mnt-myshare.mount

Add the following content:

[Unit]
Description=Mount SMB Share myshare
After=network-online.target
Wants=network-online.target
Before=umount.target
Conflicts=umount.target

[Mount]
What=//YOURSTORAGEBOXUSER-subX.your-storagebox.de/YOURSTORAGEBOXUSER-subX
Where=/mnt/myshare
Type=cifs
Options=credentials=/etc/cifs-creds/myshare,iocharset=utf8,uid=33,gid=33,seal,vers=3.1.1,_netdev
TimeoutSec=30
TimeoutStopSec=30

[Install]
WantedBy=multi-user.target

And let's activate it:

sudo systemctl daemon-reload
sudo systemctl enable --now mnt-myshare.mount

Step 5 - Installing Docker

Now that this is done, you can follow the official guide to install Docker: https://docs.docker.com/engine/install/debian/

Now let's make Docker depend on the share mount:

sudo systemctl edit docker.service

Check the comments and now insert above the line that says ### Lines below this comment will be discarded:

[Unit]
Requires=mnt-myshare.mount
After=mnt-myshare.mount

Once that is done, enable IPv6 (we're living in the 21st century for heaven's sake): https://github.com/nextcloud/all-in-one/blob/main/docker-ipv6-support.md

You will not yet be able to check that it works — that will work later.

Step 6 - Preparing Nextcloud AIO

Once that is done, I recommend to run Nextcloud AIO through compose. This makes it easier to track changes and see what's the starting parameters. In my case, I run:

mkdir -p ~/containers/nextcloud
cd ~/containers/nextcloud
nano compose.yml

You can perfectly safely start with this compose file from AIO:

github.com/nextcloud/all-in-one/blob/main/compose.yaml

I made the following adjustments:

  • Uncomment environmen:
  • Uncomment NEXTCLOUD_DATADIR: and set it to (see README):
    NEXTCLOUD_DATADIR: /mnt/myshare
  • Uncomment NEXTCLOUD_MAX_TIME: and double the value
  • Uncomment NEXTCLOUD_MEMORY_LIMIT: and set the value to 2048

Step 7 - Setting up swap to help with memory pressure

Before we start running any containers, let's enable Swap on the server so that we don't run out of RAM:

fallocate -l 4G /swapfile
dd if=/dev/zero of=/swapfile bs=1M count=4096 status=progress
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

Let's add it to system boot up:

echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Encourage a bit more swapping:

echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf

You can verify it worked by checking:

htop

It should show memory and swap separately. Swap should show x/4.00G.

Especially if you are on the 2GB RAM box, 4G of Swap were a good idea when also running fulltext search

Step 8 - Starting it up

Make sure you're in the right directory:

If you haven't yet adjusted the DNS on your domain registrar to point to your Hetzner server, now is the time.

cd ~/containers/nextcloud
docker compose up -d

Now continuing the guide on nextcloud/all-in-one/blob/main/readme.md, let's open https://example.com:8443 and go to your AIO install interface. Use your own domain.

If https://example.com:8443 doesn't load for you, try https://example.com:8080 instead.

Follow the steps. At the end it will show a temporary password for the user admin that you can then use to login under https://example.com:443 with the data store in the back being on your Storage Box.

Step 9 - Enabling encryption

Once logged in to the Nextcloud, you should:

Description
Encrypt all files Head to your user icon on the top right => Admin settings => security settings => server side encryption => switch it on
Activate the encryption module Head to your user icon on the top right => apps => deactivated apps and activate the "default encryption module"
Encrypt user home folders Head back to admin settings => security settings => encryption
Check that the checkbox is ticked for "encrypt user home folders"

If you want, you can stop your containers, enable fulltextsearch and some other containers.

Step 10 - Enabling Nextcloud backup to the same Storage Box (Optional)

You can also hook up your backup to the same Storage Box for the backup by:

  • Creating a new sub account on the Storage Box with access restricted to a backup folder. This time, only SSH access is needed.

Once you have the new sub account, you can go to the AIO interface and enter your destination as

ssh://YOURBOXID-subX@YOURBOXID-subX.your-storagebox.de:23/./nextcloud-aio-borg

The . gets you to the backup sub folder but the additional sub folder is necessary. Don't ask me why.

Before it works, you'll have to add borg's public key to the authorized_keys, which is a bit of a pain because the Storage Box doesn't even have nano or vi.

To circumvent this, we create the key file by copying the key from the AIO interface and running:

nano authorized_keys

Paste in the key. You can exit nano by pressing ctrl+q and then confirming to save (look at the bottom of the screen).

Now let's copy it the Storage Box:

scp -P 23 authorized_keys     YOURBOXID-subX@YOURBOXID-subX.your-storagebox.de:.ssh/authorized_keys

Now it should be possible to connect borg.

Last but not least, to make sure that borg doesn't save the data twice, we should add exclusions for the SMB share:

touch /mnt/myshare/_data/.noaiobackup

Let's check if it worked:

ls -la /mnt/myshare/_data/

Now let's also add it to the custom_apps directory:

touch /mnt/myshare/_data/appdata_*/.noaiobackup

Now you should be good to go. For the extended desktop client, there is a dropdown next to the download button on https://nextcloud.com/install/#install-clients for "Nextcloud files" — choose the version MacOS Virtual files.

Step 11 - Final considerations

  • A word about Backups

    The borg backups are one thing, you can additionally configure the Storage Box to make automatic snapshots in a regular time interval. On top of that, you can have your Synology (if you have one) sync to a local (likely encrypted shared folder) all your data via the "Cloud Sync" app via WebDAV. You can find the webdav link in your Nextcloud in the "files" app on the bottom left by clicking on "settings" and then selecting "webdav".

    With this setup, if you want quick access to some large local files, you can work with them on the Synology and they will be synced back in your cloud. You can also drop them in the Synology to have large uploads work even when your laptop is off or not online. And with the virtual files, you can see everything on demand. With normal folder sync, you can get the basics always to be synced to your laptop.

    Last but not least, for good measure, I additionally make a regular backup via Hyperbackup on my Synology of the Cloudmirror — in case a ransomware encrypts my cloud and my backups fail at Hetzner. This way I can get back to my data nevertheless.


  • Expanding storage

    By increasing the Storage Box, you directly increase the size of data storage available. If you want to have more compute or internal storage, then you need to shut down your server, rescale it and figure out how to increase the LUKS container size on disk. Let me know if you figure this out - it probably works in the Hetzner rescue system.

Conclusion

Congratulations, you now have your own private Nextcloud with 1TB of storage, easily expandable, fully encrypted and under your control. As next steps you can start using it, set up emails, set up additional backup systems or activate them with Hetzner — enjoy!

License: MIT
Want to contribute?

Get Rewarded: Get up to €50 in credit! Be a part of the community and contribute. Do it for the money. Do it for the bragging rights. And do it to teach others!

Report Issue
Try Hetzner Cloud

Get €20/$20 free credit!

Valid until: 31 December 2025 Valid for: 3 months and only for new customers
Get started
Want to contribute?

Get Rewarded: Get up to €50 credit on your account for every tutorial you write and we publish!

Find out more