Homelab Part 8: Nextcloud Personal Cloud Storage
Deploying Nextcloud on Kubernetes with a MariaDB database and Longhorn storage - giving myself a self-hosted Google Drive accessible from any device on the network.
What Nextcloud Is
Nextcloud is a self-hosted cloud storage platform - like Google Drive or iCloud, but running entirely on my hardware. I can:
- Sync files between devices automatically (phone, laptop, iPad)
- Access files via a browser or the Nextcloud mobile app
- Store photos, documents, notes - anything
- Share files with links (within my network, or via Cloudflare Tunnel later)
- Add apps inside Nextcloud: calendar, contacts, tasks, notes
The data never leaves my home network. No cloud company has a copy.
What Nextcloud Needs
Nextcloud requires more than just a container - it needs a database. Nextcloud stores all its metadata (file names, user accounts, sharing permissions, settings) in a relational database. I’m using MariaDB.
So I’m deploying two pods:
- MariaDB - the database backend
- Nextcloud - the application itself
Both get Longhorn volumes for their data.
The Storage Plan
| Resource | Size | What It Stores |
|---|---|---|
| MariaDB PVC | 10Gi | The database (file metadata, users, sharing) |
| Nextcloud Data PVC | 50Gi | The actual files uploaded to Nextcloud |
50GB is my starting point. Longhorn volumes can be expanded later without downtime.
Deploying MariaDB
I create the database first, then Nextcloud connects to it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# mariadb.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mariadb-data
namespace: cloud
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Secret
metadata:
name: mariadb-secret
namespace: cloud
type: Opaque
stringData:
MYSQL_ROOT_PASSWORD: "your-root-password-here"
MYSQL_DATABASE: nextcloud
MYSQL_USER: nextcloud
MYSQL_PASSWORD: "your-nextcloud-db-password-here"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mariadb
namespace: cloud
spec:
replicas: 1
selector:
matchLabels:
app: mariadb
template:
metadata:
labels:
app: mariadb
spec:
containers:
- name: mariadb
image: mariadb:10.11
envFrom:
- secretRef:
name: mariadb-secret
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumes:
- name: data
persistentVolumeClaim:
claimName: mariadb-data
---
apiVersion: v1
kind: Service
metadata:
name: mariadb
namespace: cloud
spec:
selector:
app: mariadb
ports:
- port: 3306
targetPort: 3306
Replace your-root-password-here and your-nextcloud-db-password-here with actual strong passwords before applying.
1
2
3
kubectl apply -f mariadb.yaml
kubectl get pods -n cloud
# mariadb-xxx 1/1 Running
Deploying Nextcloud
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# nextcloud.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nextcloud-data
namespace: cloud
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nextcloud
namespace: cloud
spec:
replicas: 1
selector:
matchLabels:
app: nextcloud
template:
metadata:
labels:
app: nextcloud
spec:
containers:
- name: nextcloud
image: nextcloud:28-apache
ports:
- containerPort: 80
env:
- name: NEXTCLOUD_ADMIN_USER
value: admin
- name: NEXTCLOUD_ADMIN_PASSWORD
value: "your-admin-password-here"
- name: NEXTCLOUD_TRUSTED_DOMAINS
value: nextcloud.home.lab
- name: MYSQL_HOST
value: mariadb
- name: MYSQL_DATABASE
value: nextcloud
- name: MYSQL_USER
value: nextcloud
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mariadb-secret
key: MYSQL_PASSWORD
volumeMounts:
- name: data
mountPath: /var/www/html
volumes:
- name: data
persistentVolumeClaim:
claimName: nextcloud-data
---
apiVersion: v1
kind: Service
metadata:
name: nextcloud
namespace: cloud
spec:
selector:
app: nextcloud
ports:
- port: 80
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nextcloud
namespace: cloud
annotations:
cert-manager.io/cluster-issuer: homelab-ca-issuer
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
nginx.ingress.kubernetes.io/proxy-buffering: "off"
spec:
ingressClassName: nginx
tls:
- hosts:
- nextcloud.home.lab
secretName: nextcloud-tls
rules:
- host: nextcloud.home.lab
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nextcloud
port:
number: 80
1
kubectl apply -f nextcloud.yaml
Watch the pod start - Nextcloud takes 1–2 minutes on first boot because it initialises the database:
1
2
3
kubectl get pods -n cloud -w
# nextcloud-xxx 0/1 ContainerCreating ...
# nextcloud-xxx 1/1 Running ...
First Login
Open https://nextcloud.home.lab in a browser.
Log in with:
- Username:
admin - Password: whatever you set in
NEXTCLOUD_ADMIN_PASSWORD
Nextcloud shows a welcome screen and offers to install recommended apps. I install:
- Files (always on)
- Photos
- Calendar
- Contacts
Creating User Accounts
The admin account is for administration. I create a regular user for daily use:
Top-right menu → Administration → Users → New user:
- Username:
muhammed - Password: set a strong one
- Quota:
unlimited(or set a limit if you share with family)
Setting Up File Sync on Devices
Windows/Mac: Nextcloud Desktop Client
Download from nextcloud.com/install/#install-clients and install.
Set up:
- Server address:
https://nextcloud.home.lab - Login with the user account (not admin)
- Choose which folders to sync
Files in the sync folder appear in Windows Explorer automatically.
iPhone/iPad: Nextcloud Mobile App
Download from the App Store.
Setup:
- Add account → Server:
https://nextcloud.home.lab - Log in
The app syncs photos automatically if you enable camera upload. All files are accessible offline if you mark them as favorites.
Fixing the Nextcloud Warnings
After the first login, Nextcloud’s admin panel often shows warnings. Common ones and how to fix them:
Warning: Trusted Domain Not Set
If Nextcloud shows “You are accessing the server from an untrusted domain”:
1
2
3
# Run occ command inside the pod
kubectl exec -n cloud deployment/nextcloud -- \
php occ config:system:set trusted_domains 0 --value="nextcloud.home.lab"
This is already handled by the NEXTCLOUD_TRUSTED_DOMAINS env var, but if it still appears, the occ command above fixes it permanently.
Warning: Security & Setup Warnings
In the admin panel (Administration → Overview), Nextcloud checks for configuration issues. Most can be resolved:
1
2
3
# Fix missing background jobs (use system cron instead of AJAX)
kubectl exec -n cloud deployment/nextcloud -- \
php occ background:cron
For the memory cache warning, add to Nextcloud’s config:
1
2
kubectl exec -n cloud deployment/nextcloud -- \
php occ config:system:set memcache.local --value="\\OC\\Memcache\\APCu"
Uploading and Accessing Files
The Nextcloud web interface is straightforward - drag and drop files in the browser, create folders, and share links.
The real power is the desktop sync client. Once configured, any file I put in the Nextcloud folder on my laptop is available instantly on my phone and iPad. Documents, PDFs, photos - all synced automatically, no manual steps.
Nextcloud vs Google Drive: Key Differences
| Feature | Google Drive | Nextcloud |
|---|---|---|
| Storage cost | 15GB free, then paid | Limited by your disk |
| Privacy | Google sees your files | Only you see your files |
| Offline access | Limited | Full (with sync) |
| Custom apps | No | Calendar, Contacts, Notes, etc. |
| External access | Always on | Needs Cloudflare Tunnel (Part 9) |
| Setup complexity | Zero | What we just did |
The trade-off is real - Google Drive just works everywhere from the start. Nextcloud takes setup, but what I build here I own completely.
Where I Am Now
At the end of Part 8 I have:
- ✅ MariaDB running in the
cloudnamespace with a Longhorn PVC - ✅ Nextcloud running and connected to MariaDB
- ✅ File storage with 50GB Longhorn volume (expandable)
- ✅ HTTPS access at
https://nextcloud.home.lab - ✅ Desktop sync client configured on Windows
- ✅ Mobile app connected on iPhone/iPad
Both Jellyfin and Nextcloud are now running. The homelab is functional on the home network.
Next: Cloudflare Tunnel - the optional last piece, for accessing Jellyfin and Nextcloud securely from anywhere outside the home network.
