OpenCloud in a bare-metal installation in combination with Radicale

I switched from Nextcloud to Opencloud.
Nextcloud worked great for me, but to be honest, it is overpowered for just a single user like me.

Some words why I switched and a bit of comparison

So a few weeks ago I read about Opencloud: It comes with an integrated markdown editor and when integrating Radicale (CalDAV/ CardDAV server) I can also host my calendar and contacts with it, like I did with Nextcloud.

But right now some features are still missing: You can not see or edit your calendar and contacts in the opencloud webpanel (which I’m okay with) and it also does not send notifications, if you have reminders set for calendar events. You would need to manage this with external apps.
And right now there are not many apps for Opencloud itself, but it’s a quite young project, so it might change in the future.
Like there is no eMail integration like Nextcloud has. And there are dozens or so of apps you can install and use with Nextcloud, like 2FA, Talk, whiteboard etc. pp. But I don’t need this for my self-hosted cloud setup :slight_smile:
You can integrate collabora into Opencloud tho, and create workspaces. And there is also a roadmap for Openclouds future, the file-download-on-demand feature is right around the corner.

Opencloud is written in Golang, so it has a webserver integrated, It does not need PHP nor a database, everything is file-based. So you can just manipulate the files on your SBC without the need to refresh a database. Same goes for the calendar and contact data, everything in Radicale is stored as vcf or ics files.

Before we start a quick note:
You can not run Opencloud on a subpath, like example.org/opencloud, it will not work.
I tried to make it work, but somewhere in the code they trim the URL that you specify in the config file. So maybe you could change the code and try to run it on a subpath, but a lot of stuff is relying on that URL and will likely have unwanted side effects and break the app.
Now I think it’s a smart move to stay consistent through out the whole app with this canonical URL.

As it must run on the “root” of the domain, you can create just a subdomain, like cloud.example.org or just run it on the second-level-domain example.org if you like.
I use a DynDNS domain which has already a sub-domain in it (like domain.ddns.net, so I just created a new one for opencloud, which also points to my public IP.

How I installed opencloud & radicale bare-metal (including systemd services):

Install opencloud

useradd --system --no-create-home --shell /usr/sbin/nologin opencloud
mkdir /mnt/dietpi_userdata/opencloud
chown -R opencloud:opencloud /mnt/dietpi_userdata/opencloud
chmod 700 /mnt/dietpi_userdata/opencloud
  • Create the config and data directory and config file
cd /mnt/dietpi_userdata/opencloud
sudo -u opencloud mkdir ./config ./data
sudo -u opencloud touch ./config/config.env

content for config.env:

OC_CONFIG_DIR=/mnt/dietpi_userdata/opencloud/config/
OC_BASE_DATA_PATH=/mnt/dietpi_userdata/opencloud/data
OC_URL=http://<LAN_IP>:9200
PROXY_LOG_LEVEL=info

Replace <LAN_IP> with the IP of your device (like http://192.168.0.1:9200), we will test after the init if the service is running.
We will then later change it to the actual domain.
(I set PROXY_LOG_LEVEL to info to be able to create a filter for fail2ban)

Opencloud will create a yaml file inside ./config on first start, it contains keys, tokens and passworts, for example the admin passwort you need for the logging into the web panel.

  • Then we create a systemd service:
    nano/etc/systemd/system/opencloud.service
    with the contents:
[Unit]
Description=OpenCloud Service
After=network.target

[Service]
Type=simple
User=opencloud
Group=opencloud
WorkingDirectory=/opt/opencloud
EnvironmentFile=/mnt/dietpi_userdata/opencloud/config/config.env
ExecStart=/opt/opencloud/opencloud server
Restart=on-failure
RestartSec=5
Environment=PATH=/usr/bin:/usr/local/bin
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Don’t start the service yet!

First we need to initialize opencloud, it also needs to use our .env file for the init to create the files in the correct places.

sudo -u opencloud env $(cat /mnt/dietpi_userdata/opencloud/config/config.env | xargs) /opt/opencloud/opencloud init

A prompt should appear:

Do you want to configure OpenCloud with certificate checking disabled?

If you use a self-signed certificate (if you use DynDNS and certbot / letsencrypt), choose yes.
If you know what you are doing, choose no.
We’ll config SSL within the reverse proxy and Opencloud (running on port 9200) will not be accessible directly from public internet, so this is fine.

It will also show you the admin passwort you need for login into the web panel. There should be now also a new file in /mnt/dietpi_userdata/opencloud/config called opencloud.yaml, it cointains also the password.

Now enable and start the service

systemctl daemon-reload
systemctl enable --now opencloud.service

You should now be able to reach it on port 9200 via http.


Proxy config

Is use nginx for the proxy, you can use this as a blueprint for lighty or apache I guess

  • create the file: nano /etc/nginx/sites-available/opencloud
    (Replace cloud.example.org with your domain. It also contains already the proxy config for Radicale / CalDAV)
    If you don’t want to use radicale, please delete the corresponding blocks from the nginx config!
/etc/nginx/sites-available/opencloud
server {
    server_name cloud.example.org
    listen 443 ssl;
    http2 on;

    ssl_certificate /etc/letsencrypt/live/cloud.example.org/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/cloud.example.org/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    http2_max_concurrent_streams 512;

    location / {
        proxy_pass https://127.0.0.1:9200;

        proxy_http_version 1.1;
        proxy_set_header Connection "";

        proxy_ssl_verify off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_set_header Accept-Encoding "";

        proxy_buffering off;
        proxy_request_buffering off;

        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        keepalive_timeout 3600s;
        keepalive_requests 100000;

        proxy_next_upstream off;

        client_max_body_size 10M;
    }

    # ----------------------------
    # RADICALE CalDAV
    # ----------------------------
    location /caldav/ {
        proxy_pass http://127.0.0.1:5232/;
        proxy_set_header X-Script-Name /caldav;
        proxy_set_header X-Remote-User $http_x_remote_user;
        proxy_set_header Host $host;
        proxy_http_version 1.1;
        proxy_buffering off;
    }

    location = /.well-known/caldav {
        return 301 /caldav/;
    }

    # ----------------------------
    # RADICALE CardDAV
    # ----------------------------
    location /carddav/ {
        proxy_pass http://127.0.0.1:5232/;
        proxy_set_header X-Script-Name /carddav;
        proxy_set_header X-Remote-User $http_x_remote_user;
        proxy_set_header Host $host;
        proxy_http_version 1.1;
        proxy_buffering off;
    }

    location = /.well-known/carddav {
        return 301 /carddav/;
    }
}

I guess you can also use QUIC/HTTP3, but in NGINX only one directive is allowed for QUIC for the whole config!
QUIC runs on UDP and is stateless, so it makes no sense to define it in multiple server blocks. If you already have QUIC set up in your default config it should be fine.

  • link the config and reload nginx
ln -s /etc/nginx/sites-available/opencloud /etc/nginx/sites-enabled
  • Now it’s also time to change OC_URL inside /mnt/dietpi_userdata/opencloud/config/config.env to you actual domain, it should look like
OC_URL=https://cloud.example.org
  • Now restart nginx and opencloud
systemctl daemon-reload
systemctl reload nginx.service
systemctl restart opencloud.service

You are now able to reach opencloud via your domain.


Install Radicale

(If you don’t want to use radicale, please delete the corresponding blocks from the nginx config)

Radicale is availble in the Debian repo, so we can just install it via apt

apt install radicale

It creates a systemd service file we can overwrite with

systemctl edit radicale.service

At the top of the file is an area marked, where we can insert our overwrites.
We add:

[Service]
User=radicale
Group=radicale

ExecStart=
ExecStart=/usr/bin/radicale --config /mnt/dietpi_userdata/radicale/radicale.conf

ReadWritePaths=
ReadWritePaths=/mnt/dietpi_userdata/radicale/

Before we restart we need to create the corresponding paths and the config file:

mkdir -p /mnt/dietpi_userdata/radicale/collections
chown -R radicale:radicale /mnt/dietpi_userdata/radicale
chmod 700 /mnt/dietpi_userdata/radicale
sudo -u radicale nano /mnt/dietpi_userdata/radicale/radicale.conf
content of the radicale.conf
[server]
hosts = 127.0.0.1:5232

max_connections = 20
timeout = 30

[auth]
type = http_x_remote_user

[rights]
type = owner_only

[storage]
filesystem_folder = /mnt/dietpi_userdata/radicale/collections
predefined_collections = {
  "def-addressbook": {
    "D:displayname": "Personal Address Book",
    "tag": "VADDRESSBOOK"
  },
  "def-calendar": {
    "C:supported-calendar-component-set": "VEVENT,VJOURNAL,VTODO",
    "D:displayname": "Personal Calendar",
    "tag": "VCALENDAR"
  }
}

[web]
type = none

[logging]
level = warning
  • Now restart everything
systemctl daemon-reload
systemctl restart radicale.service
systemctl restart opencloud.service

If you browse now the /caldav or /carddav endpoint you should see the message Radicale works!.
Also in the opencloud webpanel, click in the top right corner on the user icon, then on settings.
In the menu on the left side choose Calendar, you should see now some info about your radicale integration on this page.
To access it externally, you can use the username “admin” and as passwort you need to create an app token. You can do this from the menu on the left as well.

I hope I did not forget something, I wrote all of this from memory. The 1000 lines of history in bash were not enough to save everything I did when I was testing :smiley:


References:

Radicale:

https://radicale.org/v3.html#documentation-1

Opencloud:

https://docs.opencloud.eu/docs/next/dev/server/configuration/config-system
https://docs.opencloud.eu/docs/next/admin/configuration/radicale-integration
https://github.com/opencloud-eu/opencloud
https://github.com/opencloud-eu/opencloud-compose/blob/3bddb65c8bf357285b8b47246351936aae3b75dc/config/radicale/config

1 Like

Yes, this is exactly what my post describes.
Also radicale is enough for me, I just want a way to host my calendar and contacts data to use it e.g. on Android.
On my phone I sync it with DAVx5 app.

As an alternative to Radikal, you can also use Baikal, which is available as an option in DietPi. Although I don’t know if Baikal can be integrated with OpenCloud. At least the web server Nginx is already available and can be used by Baikal.