Skip to content

Article header

OpenCloud - Simple Self-Hosting with Tailscale

OpenCloud is great (search engines will often hit you with -> did you mean owncloud?). It is fast, has great native mobile apps and is much lighter than the giant in the self hosted space for file solutions, Nextcloud. The tipping point for me to use OpenCloud over Seafile, is that the underlying storage is just a normal file system. It is nice to know that my files are just that, normal ol' files and I can explore them with or without OpenCloud.

The one place OpenCloud is lacking, is its documentation and ease of setup. Taking a look at their docker compose docs, does not really help many from the self hosting crowd get up and running.

At this point Tailscale requires no introduction in the self hosting world, but the TLDR is: it is a great way to run services on your own hardware and access them securely wherever you go. Their generous free tier will cover even the most hardcore self-hoster's needs. Here is how you can setup Tailscale to securely access OpenCloud wherever you go.


Prerequisites

  • Docker installed and running on the machine you are going to be self hosting OpenCloud from.
  • A Tailscale account with MagicDNS enabled and HTTPS Certificates enabled.
  • Important: ensure that Tailscale is also installed on the host machine (and logged into the same tailnet you plan on using for this setup) that has Docker installed on it and that you are going to be hosting OpenCloud from. If you don't, you'll end up with weird DNS issues.
  • Tailscale installed on the machine(s) you plan on accessing OpenCloud from (laptop, phone, etc.).

The Docker Compose File

The simplicity of setting this up comes from this docker compose file ⬇️

compose.yaml
name: opencloud
configs:
  opencloud-ts-serve:
    content: |
      {"TCP":{"443":{"HTTPS":true}},
      "Web":{"$${TS_CERT_DOMAIN}:443":
       {"Handlers":{"/":
        {"Proxy":"http://127.0.0.1:9200"}}}},
      "AllowFunnel":{"$${TS_CERT_DOMAIN}:443":false}}
services:
  opencloud-chown:
    image: busybox
    container_name: opencloud-chown
    user: root
    volumes:
      - ./opencloud-config:/etc/opencloud
      - ./opencloud-data:/var/lib/opencloud
    command: chown -R 1000:10000 /etc/opencloud /var/lib/opencloud
    restart: "no"
  opencloud-init:
    image: opencloudeu/opencloud-rolling:latest
    container_name: opencloud-init
    entrypoint: /bin/sh
    command: -c "[ -f /etc/opencloud/opencloud.yaml ] || opencloud init"
    user: "1000:10000"
    volumes:
      - ./opencloud-config:/etc/opencloud
      - ./opencloud-data:/var/lib/opencloud
    environment:
      - OC_URL=${OC_URL}
      - PROXY_TLS=false
      - IDM_ADMIN_PASSWORD=admin
      - OC_INSECURE=false
    restart: "no"
    network_mode: service:opencloud-ts
    depends_on:
      opencloud-ts:
        condition: service_started
      opencloud-chown:
        condition: service_completed_successfully
  opencloud-ts:
    image: tailscale/tailscale:latest
    container_name: opencloud-ts
    hostname: opencloud
    environment:
      - TS_STATE_DIR=/var/lib/tailscale
      - TS_SERVE_CONFIG=/config/serve.json
      - TS_AUTHKEY=${TS_AUTHKEY}
    configs:
      - source: opencloud-ts-serve
        target: /config/serve.json
    volumes:
      - opencloud-ts-state:/var/lib/tailscale
    restart: unless-stopped
  opencloud:
    image: opencloudeu/opencloud-rolling:latest
    container_name: opencloud
    user: "1000:10000"
    network_mode: service:opencloud-ts
    depends_on:
      opencloud-ts:
        condition: service_started
      opencloud-init:
        condition: service_completed_successfully
    volumes:
      - ./opencloud-config:/etc/opencloud
      - ./opencloud-data:/var/lib/opencloud
    environment:
      - OC_URL=${OC_URL}
      - PROXY_TLS=false
    restart: unless-stopped
volumes:
  opencloud-ts-state:

Breaking It Down

If you're a docker pro, you got it from here, but let's break down what this does starting with configs.

name: opencloud
configs:
  opencloud-ts-serve:
    content: |
      {"TCP":{"443":{"HTTPS":true}},
      "Web":{"$${TS_CERT_DOMAIN}:443":
       {"Handlers":{"/":
        {"Proxy":"http://127.0.0.1:9200"}}}},
      "AllowFunnel":{"$${TS_CERT_DOMAIN}:443":false}}

This defines our Tailscale Serve config. This bit of JSON gibberish says ➡️ forward port 9200 from the opencloud-ts network to https://opencloud.your-tailnet.ts.net. This config is mounted into the Tailscale container as if it was a JSON file in the container's filesystem.

The opencloud-ts service defines our Tailscale container that acts as the sidecar for our application. Unless you have shell access to the host or are logged into your tailnet, you can't even access OpenCloud, which is awesome from a security perspective. Due to this, we can safely use PROXY_TLS=false in the opencloud service. We are letting Tailscale take care of our networking so we don't have to mess with a reverse proxy. Even if you were to access OpenCloud with MagicDNS via http://opencloud:9200, the connection is still secure since the underlying traffic is being routed through an encrypted WireGuard connection.

All of the persistent data lives in the opencloud-config and the opencloud-data folders. These are the folders that are essential to backup in case of any hardware failure.

Step by Step Setup

  1. Open up a shell session on the machine you are going to be hosting OpenCloud from.

  2. Create a folder named opencloud wherever you want to run your service on your machine.

    mkdir -p opencloud && cd opencloud
    

  3. Create the compose.yaml file with your text editor of choice.

    nano compose.yaml
    

    Paste the contents from the compose file above, hit ctrl + x, then y, and then enter.

  4. Go to Settings -> Keys in the Tailscale admin console and generate an auth key.

  5. Create a opencloud.env file.

    nano opencloud.env
    
    Paste in the contents below and fill it in with your own values.
    opencloud.env
    # Tailscale
    TS_AUTHKEY=tskey-auth-xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    
    # OpenCloud
    # Replace with your actual Tailscale machine name and tailnet domain
    # Format: https://<hostname>.<tailnet-name>.ts.net
    OC_URL=https://opencloud.your-tailnet.ts.net
    
    After pasting, hit ctrl + x, then y, and then enter to save the file

    Proper secrets management is out of scope for this article, but if the boot drive that you are running docker on is properly secured, using an env file is likely OK.

  6. Run docker compose up command.

    docker compose --env-file opencloud.env up -d
    

🎉 You should be able to go to https://opencloud.your-tailnet.ts.net and setup OpenCloud for use. The default username is admin and the default password admin. Be sure to change the password right away!