I’ve been running owncloud, then nextcloud for years. While it worked I was never very happy with it. Performance was always lackluster even for 1-2 users, features added was never something I cared about (groupware, AI assistant, talk features – don’t use, need or care).
All I want is a reliable lean google drive or onedrive alternative, clean files-only minimal interface, some apps on ios and android, ability to share and edit files. I’ve been on the lookout for alternatives for years but there was nothing really good out there until now. Already has android and apple apps.
Enter opencloud. I’ve been running it for 2 months now and can recommend switching. Here’s how I run it using docker compose. Note that this is unofficial docker-compose.yml. Official docker-compose.yml is over here, but myself and many other people find it too complicated. Examples also focus on traefik while people might be using other reverse proxies.
Note: This is tutorial is only to illustrate how I personally run my personal opencloud service. This post is provided for informational and educational purposes only. It does not constitute security advice, and no statement is made regarding the suitability or fitness of these configurations for production or secure deployment.
- Opencloud screenshots
- How I run opencloud in docker compose with nginx proxy manager as a reverse proxy
- Opencloud – docker-compose.yml
- Opencloud – docker compose .env file
- Opencloud – csp.yaml. yes this is needed
- Opencloud reverse proxy – Nginx proxy manager on a public VPS
- Join opencloud chat (matrix)
- What I would say to Nextcloud
- In conclusion
Opencloud screenshots
Sharing screenshots so people can see how it looks like. People that are looking to switch are probably interested in this the most.
What I love about it – interface is clean, uncluttered, and to the point.









Various settings pages:



How I run opencloud in docker compose with nginx proxy manager as a reverse proxy
Opencloud docker setup could be a bit convoluted if you want collabora (collabora is a selfhosted service for editing documents) or calendar (you need to add radicale container). If you don’t use collabora for editing microsoft word or open documents – you can just run opencloud as a single container (fine for people that dont care about docs) – you can still do text and markdown file editing with a single container opencloud setup.
If you want collabora – you need 3 containers: collabora, wopi and opencloud. I’m running with collabora and these examples are for 3 container setup with collabora.
I run opencloud containers straight on my NAS server running ubuntu LTS, I then expose container ports on tailscale only, and then I route it via nginx proxy manager through my public VPS via tailscale.
This avoids cloudflare as I dont like using cloudflare, I’m sure you can set this up with cloudflare as well.
You don’t necessarily need tailscale and nginx proxy manager unless you want to expose opencloud via public VPS server just like I do, or just want to use private openlcoud on tailscale VPN (good idea).
I use these 3 domains (Using example.com is just an example). Why? Because I own example.com, I then have a VPS that i identify as toolski17.example.com, I then run 3 services on that VPS.
These are just example urls, my setup uses different DNS names:
- https://fence-red5-opencloud.toolski17.example.com
- https://fence-red5-wopi.toolski17.example.com
- https://fence-red5-collabora.toolski17.example.com
Why such complex dns names? That’s just for additional security – nginx proxy manager is configured to 444 if user does not have domain. This literally eliminates bots and probes entirely for me (No, this is not security by obscurity, this is defence in depth). “obscurity is not a security” types are going to love this paragraph – look guys – Just use tailscale without exposing services to the internet if you don’t like this. This is how I do it and it works great.
Edit: To clarify to my dear frieds from “obscurity is not a security” crowd that immediately attacked me. I should have clarified – I use wildcard ssl and wildcard dns: *.toolski17.example.com. *.toolski17.example.com is the only thing letsencrypt and registrar sees. For attacker to even begin trying to exploit your application they would have to guess a subdomain first, everything else get’s a 444 from nginx. And after that – you still have regular opencloud authentication and authorization to deal with.
Edit 2: added bolder disclaimer as I dont have time to go back and fourth on secure subdomain topic. Works great for me. Ymmv

Opencloud – docker-compose.yml
networks:
default:
external: true
name: infranet
# Example from here: https://www.reddit.com/r/selfhosted/comments/1n5kgvi/looking_for_a_reliable_nextcloud_alternative/
services:
opencloud-app:
restart: always
image: opencloudeu/opencloud-rolling:latest
hostname: opencloud-app
container_name: opencloud-app
user: "1000:1000"
logging:
driver: "json-file"
options:
max-file: "5"
max-size: "10m"
environment:
# enable services that are not started automatically
OC_ADD_RUN_SERVICES: "notifications"
OC_URL: "https://fence-red5-opencloud.toolski17.example.com"
OC_LOG_LEVEL: "info"
OC_LOG_COLOR: "false"
OC_LOG_PRETTY: "false"
PROXY_TLS: "false"
OC_INSECURE: "true"
### demo users ###
IDM_CREATE_DEMO_USERS: "false"
PROXY_HTTP_ADDR: 0.0.0.0:9200
FRONTEND_ARCHIVER_MAX_SIZE: 1099511627776 # 1 TiB
# (optional) if you also need more files per archive:
FRONTEND_ARCHIVER_MAX_NUM_FILES: 500000
### Notifications Settings ###
NOTIFICATIONS_SMTP_HOST: blah.mxrouting.net
NOTIFICATIONS_SMTP_PORT: 587
NOTIFICATIONS_SMTP_SENDER: "OpenCloud <donotreply@example.com>"
NOTIFICATIONS_SMTP_USERNAME: donotreply@example.com
NOTIFICATIONS_SMTP_PASSWORD: FILL_IN_YOUR_PASS
NOTIFICATIONS_SMTP_INSECURE: false
NOTIFICATIONS_SMTP_AUTHENTICATION: plain
NOTIFICATIONS_SMTP_ENCRYPTION: starttls
STORAGE_USERS_DRIVER: posix
STORAGE_USERS_ID_CACHE_STORE: nats-js-kv
### Wopi Server Settings ###
WOPISERVER_DOMAIN: "fence-red5-wopi.toolski17.example.com"
# Bullshit needed for collabora
PROXY_CSP_CONFIG_FILE_LOCATION: "/etc/opencloud/csp.yaml"
FRONTEND_APP_HANDLER_SECURE_VIEW_APP_ADDR: "eu.opencloud.api.collaboration.CollaboraOnline"
### NATS Settings - by default it listens on 127.0.0.1 ###
NATS_NATS_HOST: 0.0.0.0
NATS_NATS_PORT: 9233
### GRPC Settings ###
GATEWAY_GRPC_ADDR: "0.0.0.0:9142"
### Collabora Settings ###
COLLABORA_DOMAIN: "fence-red5-collabora.toolski17.example.com"
COLLABORA_ADMIN_USER: "admin"
COLLABORA_ADMIN_PASSWORD: "FILL_IN_YOUR_PASS"
COLLABORA_SSL_ENABLE: false
COLLABORA_SSL_VERIFICATION: false
volumes:
- ${FS_DIR}/data:/var/lib/opencloud
- ${FS_DIR}/config:/etc/opencloud
#exposing port to internal Tailscale network only
ports:
- ${TAILSCALE_IP}:${OPENCLOUD_PORT}:${OPENCLOUD_PORT}
opencloud-collaboration:
image: opencloudeu/opencloud-rolling:latest
container_name: opencloud-collaboration
depends_on:
opencloud-app:
condition: service_started
opencloud-collabora:
condition: service_healthy
restart: always
entrypoint:
- /bin/sh
command: ['-c', 'opencloud collaboration server']
environment:
OC_LOG_LEVEL: info
COLLABORATION_GRPC_ADDR: 0.0.0.0:9301
COLLABORATION_HTTP_ADDR: 0.0.0.0:9300
MICRO_REGISTRY: "nats-js-kv"
MICRO_REGISTRY_ADDRESS: "opencloud-app:9233"
COLLABORATION_WOPI_SRC: "https://fence-red5-wopi.toolski17.example.com"
COLLABORATION_APP_NAME: "CollaboraOnline"
COLLABORATION_APP_PRODUCT: "Collabora"
COLLABORATION_APP_ADDR: "https://fence-red5-collabora.toolski17.example.com"
COLLABORATION_APP_ICON: "https://fence-red5-collabora.toolski17.example.com/favicon.ico"
COLLABORATION_APP_INSECURE: true
COLLABORATION_CS3API_DATAGATEWAY_INSECURE: true
COLLABORATION_LOG_LEVEL: info
OC_URL: "https://fence-red5-opencloud.toolski17.example.com"
volumes:
- ${FS_DIR}/config:/etc/opencloud
ports:
#exposing port to internal Tailscale network only
# - 9300:9300
- ${TAILSCALE_IP}:${COLLABORATION_PORT}:${COLLABORATION_PORT}
opencloud-collabora:
image: collabora/code:latest
container_name: opencloud-collabora
cap_add:
- MKNOD
environment:
aliasgroup1: https://fence-red5-wopi.toolski17.example.com:443
DONT_GEN_SSL_CERT: "YES"
extra_params: |
--o:ssl.enable=false \
--o:ssl.ssl_verification=false \
--o:ssl.termination=true \
--o:welcome.enable=false \
--o:net.frame_ancestors=fence-red5-opencloud.toolski17.example.com
username: admin
password: 'FILL_IN_YOUR_PASS'
domain: "fence-red5-collabora\\.toolski17\\.aurora\\.dev|fence-red5-opencloud\\.toolski17\\.aurora\\.dev|fence-red5-wopi\\.toolski17\\.aurora\\.dev|opencloud-app|opencloud-collaboration"
restart: always
entrypoint: ['/bin/bash', '-c']
command: ['coolconfig generate-proof-key && /start-collabora-online.sh']
healthcheck:
test: ["CMD", "bash", "-c", "exec 3<>/dev/tcp/127.0.0.1/9980 && echo -e 'GET /hosting/discovery HTTP/1.1\r\nHost: localhost:9980\r\n\r\n' >&3 && head -n 1 <&3 | grep '200 OK'"]
ports:
#exposing port to internal Tailscale network only
- ${TAILSCALE_IP}:${WOPI_PORT}:${WOPI_PORT}
Opencloud – docker compose .env file
#General settings
COMPOSE_PROJECT_NAME=opencloud
# Where data is stored for opencloud on my nas
FS_DIR=/mnt/nas-pool-furyroad/dockervolumes/opencloud
#ports
OPENCLOUD_PORT=9200
COLLABORATION_PORT=9300
WOPI_PORT=9980
#Nas Host Tailscale network ip
TAILSCALE_IP=100.93.99.20
Opencloud – csp.yaml. yes this is needed
I had to set it up manually. Various UI operations will fail if you dont have it.
This file is used by main opencloud service:
# Bullshit needed for collabora
PROXY_CSP_CONFIG_FILE_LOCATION: "/etc/opencloud/csp.yaml"
directives:
child-src:
- "'self'"
connect-src:
- "'self'"
- 'blob:'
- 'https://ence-red5-wopi.shedsky1.example.com/'
- 'wss://ence-red5-wopi.shedsky1.example.com/'
- 'https://raw.githubusercontent.com/opencloud-eu/awesome-apps/'
- 'https://ence-red5-opencloud.shedsky1.example.com/'
default-src:
- "'none'"
font-src:
- "'self'"
frame-ancestors:
- "'self'"
frame-src:
- "'self'"
- 'blob:'
- 'https://embed.diagrams.net/'
- 'https://ence-red5-collabora.shedsky1.example.com/'
- 'https://docs.opencloud.eu'
img-src:
- "'self'"
- 'data:'
- 'blob:'
- 'https://raw.githubusercontent.com/opencloud-eu/awesome-apps/'
- 'https://ence-red5-collabora.shedsky1.example.com/'
manifest-src:
- "'self'"
media-src:
- "'self'"
object-src:
- "'self'"
- 'blob:'
script-src:
- "'self'"
- "'unsafe-inline'"
- "'unsafe-eval'" # <-- allow eval()/new Function()
style-src:
- "'self'"
- "'unsafe-inline'"
Opencloud reverse proxy – Nginx proxy manager on a public VPS
I prefer this route when exposing a service from my local network. Basically if I want service to be publicly available, – I route it from my home network via tailscale and expose via remote public VPS I own and some domain name I own using nginx proxy manager reverse proxy.
Here is an example: just point domains to the tailscale DNS names.
Again – I use tailscale purely to connect from public VPS server to my homenetwork.
a. I add 3 proxies in nginx proxy manager:

b. Nginx proxy config looks something like this – note how I point to my NAS tailscale dns:

c. Just make sure to increase nginx timeouts. (advanced tab in nginx proxy manager), otherwise transferring a lot of files could fail.
proxy_connect_timeout 60s;
proxy_send_timeout 4h; # or 14400s
proxy_read_timeout 4h; # or 14400s
send_timeout 4h; # or 14400s
# these help WebDAV COPY/MOVE and uploads
# disabled as im not sure this is needed
# proxy_request_buffering off;
# proxy_buffering off;
Join opencloud chat (matrix)
They have good active matrix channel (that’s a chat app): https://matrix.to/#/#opencloud:matrix.org
If you need help and support community seems active and growing.
What I would say to Nextcloud
You need to refactor your backend. No – you cannot build application like nextcloud on share-nothing per request PHP backend. What you have now is a buggy, unscalable mess of a product that can only survive on top of redis caching and being entirely free. You need to convert nextcloud to a long running in-memory always-on application with heavy use of async/coroutines.
@nextcloud team – If you want to refactor quickly – use swoole on top PHP, use hyperf framework. This way you can keep PHP, but shift entirely how it works under the hood.
Switch to long-running paradigm, parallelize database calls (improves performance), use coroutines, use swoole built-in side processes, use built-in cronjobs abilities, offload async tasks to nonblocking TaskExecutor using side nonblocking task workers.
Look at the benchmark I’ve done to illustrate the differene – it barely scratches the surface of what is possible with swoole.
Websockets, socket.io, tcp server, grpc server -> these are a killer features most PHP apps simply incapable of. You need them for nextcloud. – I dont have time to list it all. Just take a look at this list https://hyperf.wiki/3.1/#/en/ and if you’ve been in a PHP field for a while the difference of possibilities will be self-evident. it’s a night and day.
In conclusion
Switch to opencloud today, it’s fast, clean, lean and overall amazing. And maybe nextcloud will get their act together (it should better be soon).