Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
PHP_VERSION=7.4

include $(FAB_PATH)/common/mk/turnkey/lamp.mk
include $(FAB_PATH)/common/mk/turnkey.mk
20 changes: 13 additions & 7 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,22 @@ wherever you are, when you need it.
This appliance includes all the standard features in `TurnKey Core`_,
and on top of that:

- ownCloud Server:
- ownCloud Server 11:

- Installed from official zip file to /var/www/owncloud.
- Data directory (/var/www/owncloud-data) outside the webroot (security).
- Runs from the official ownCloud container image, pinned to a verified
amd64 manifest digest.
- Stores persistent configuration and user files under
/var/lib/owncloud.
- Uses Debian MariaDB and Redis services on a dedicated local Docker
network.
- Includes occ_ script for command line administration and configuration.
Also includes turnkey-occ_ wrapper script (runs occ as www-data user).

**Security note**: Updates to ownCloud may require supervision so
they **ARE NOT** configured to install automatically. See `ownCloud
documentation`_ for upgrading.
**Security note**: ownCloud updates require supervision and are not
installed automatically. Use ``owncloud-update --check VERSION`` to
inspect the official amd64 image digest, then run
``owncloud-update VERSION DIGEST`` after reviewing the release and
backing up the appliance. See `ownCloud documentation`_ for upgrading.

- SSL support out of the box.
- `Adminer`_ administration frontend for MySQL (listening on port
Expand All @@ -39,5 +45,5 @@ Credentials *(passwords set at first boot)*
.. _TurnKey Core: https://www.turnkeylinux.org/core
.. _occ: https://doc.owncloud.com/server/admin_manual/configuration/server/occ_command.html
.. _turnkey-occ: https://github.com/turnkeylinux-apps/owncloud/blob/master/overlay/usr/local/bin/turnkey-occ
.. _ownCloud documentation: https://doc.owncloud.org/server/admin_manual/maintenance/upgrade.html
.. _ownCloud documentation: https://doc.owncloud.com/server/11.0/admin_manual/maintenance/upgrading/manual_upgrade.html
.. _Adminer: https://www.adminer.org
12 changes: 11 additions & 1 deletion changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
turnkey-owncloud-19.0 (1) turnkey; urgency=low

* Run ownCloud Server 11.0.0 from the official container image pinned to
its amd64 manifest digest.

* Use Debian 13 Trixie for Docker, Apache, MariaDB, Redis and Adminer.

* Add a supervised ownCloud container update command.

-- TurnKey Linux Developers <admin@turnkeylinux.org> Mon, 24 Aug 2026 13:00:00 +0000

turnkey-owncloud-18.0 (1) turnkey; urgency=low

* Includes latest stable ownCloud - v10.13.1.
Expand Down Expand Up @@ -293,4 +304,3 @@ turnkey-owncloud-12.0 (1) turnkey; urgency=low
appliances. Here we only describe changes specific to this appliance.

-- Alon Swartz <alon@turnkeylinux.org> Wed, 01 Aug 2012 08:00:00 +0200

25 changes: 18 additions & 7 deletions conf.d/downloads
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
#!/bin/bash -ex
#!/bin/bash
set -Eeuo pipefail

dl() {
[ "$FAB_HTTP_PROXY" ] && PROXY="--proxy $FAB_HTTP_PROXY"
cd $2; curl -L -f $PROXY $1 > $3; cd -
}
image=owncloud/server@sha256:dbebc24fe77a35c5de621d38a3f7264ffb43e3ee321928cde9a563a72b8ff366
archive=/usr/local/src/owncloud-server.tar
local_tag=owncloud/server:11.0.0-turnkey-dbebc24fe77a

URL="https://download.owncloud.com/server/stable/owncloud-complete-20230906.zip"
if [[ -n ${FAB_HTTP_PROXY:-} ]]; then
export HTTP_PROXY=$FAB_HTTP_PROXY
export HTTPS_PROXY=$FAB_HTTP_PROXY
fi

dl $URL /usr/local/src owncloud.zip
skopeo copy --override-os linux --override-arch amd64 \
"docker://docker.io/$image" "docker-archive:$archive:$local_tag"

cat > /usr/local/src/owncloud-image-source <<EOF
source=docker.io/owncloud/server
version=11.0.0
digest=sha256:dbebc24fe77a35c5de621d38a3f7264ffb43e3ee321928cde9a563a72b8ff366
local_tag=$local_tag
EOF
92 changes: 44 additions & 48 deletions conf.d/main
Original file line number Diff line number Diff line change
@@ -1,75 +1,71 @@
#!/bin/bash -ex
#!/bin/bash -e

DB_NAME=owncloud
DB_USER=owncloud
DB_PASS=$(mcookie)

ADMIN_NAME=admin
ADMIN_PASS=turnkey

WEBROOT=/var/www/owncloud
DATAROOT=${WEBROOT}-data
CONF=$WEBROOT/config/config.php

# unpack tarball to webroot and set permissions
unzip /usr/local/src/owncloud*.zip -d $(dirname $WEBROOT)
[[ ! -d "$WEBROOT" ]] && exit 1
rm -rf /usr/local/src/owncloud*
mkdir -p $DATAROOT

# tweak footer
TEMPLATE=$WEBROOT/core/templates/layout.guest.php
sed -i "s|.*getLongFooter.*|<a href='https://www.turnkeylinux.org/owncloud'>ownCloud Appliance</a> \&ndash; Powered by <a href='https://www.turnkeylinux.org'>TurnKey Linux</a>|" $TEMPLATE
REDIS_PASS=$(mcookie)

# configure apache
a2dissite 000-default
a2ensite owncloud.conf
a2enmod rewrite
a2enmod headers
a2enmod env
a2enmod dir
a2enmod mime
a2enmod proxy
a2enmod proxy_http

# start services
service mysql start
service apache2 start

# setup the database
mysqladmin create $DB_NAME
mysql --batch --execute "grant all privileges on $DB_NAME.* to $DB_USER@localhost identified by '$DB_PASS'; flush privileges;"
mysql --batch --execute "CREATE USER '$DB_USER'@'172.28.0.%' IDENTIFIED BY '$DB_PASS'; GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'172.28.0.%'; FLUSH PRIVILEGES;"

# command-line install
chown -R www-data:www-data $WEBROOT
cd $WEBROOT
php occ maintenance:install --database "mysql" \
--database-name "$DB_NAME" --database-user "$DB_USER" --database-pass "$DB_PASS" \
--admin-user "$ADMIN_NAME" --admin-pass "$ADMIN_PASS" \
--data-dir "$DATAROOT"
install -d -m 700 /etc/owncloud
install -d -m 700 /var/lib/owncloud
install -m 600 /usr/local/src/owncloud-image-source /etc/owncloud/image-source

# enable notify owncloud that we are using cron
mysql --batch --database=$DB_NAME --execute "INSERT INTO oc_appconfig (appid, configkey, configvalue) VALUES ('core', 'backgroundjobs_mode', 'cron');"

# adjust owncloud config for redis
sed -i '/^);/d' $CONF
cat >> $CONF <<EOF
'memcache.local' => '\OC\Memcache\Redis',
'redis' => [
'host' => '/var/run/redis/redis.sock',
'port' => 0,
],
'memcache.locking' => '\OC\Memcache\Redis',
);
cat > /etc/owncloud/image.conf <<EOF
OWNCLOUD_IMAGE=owncloud/server:11.0.0-turnkey-dbebc24fe77a
OWNCLOUD_VERSION=11.0.0
OWNCLOUD_DIGEST=sha256:dbebc24fe77a35c5de621d38a3f7264ffb43e3ee321928cde9a563a72b8ff366
EOF

# add www-data user to redis group
usermod -a -G redis www-data
cat > /etc/owncloud/owncloud.env <<EOF
OWNCLOUD_DOMAIN=localhost
OWNCLOUD_TRUSTED_DOMAINS=localhost,127.0.0.1
OWNCLOUD_OVERWRITE_CLI_URL=https://localhost
OWNCLOUD_OVERWRITE_PROTOCOL=https
OWNCLOUD_DB_TYPE=mysql
OWNCLOUD_DB_NAME=$DB_NAME
OWNCLOUD_DB_USERNAME=$DB_USER
OWNCLOUD_DB_PASSWORD=$DB_PASS
OWNCLOUD_DB_HOST=172.28.0.1
OWNCLOUD_MYSQL_UTF8MB4=true
OWNCLOUD_REDIS_ENABLED=true
OWNCLOUD_REDIS_HOST=172.28.0.1
OWNCLOUD_REDIS_PORT=6379
OWNCLOUD_REDIS_PASSWORD=$REDIS_PASS
OWNCLOUD_ADMIN_USERNAME=admin
OWNCLOUD_ADMIN_PASSWORD=turnkey
EOF
chmod 600 /etc/owncloud/image.conf /etc/owncloud/owncloud.env

# adjust redis config
sed -i 's|# unixsocket .*|unixsocket /var/run/redis/redis.sock|g' /etc/redis/redis.conf
sed -i 's|# unixsocketperm .*|unixsocketperm 770|g' /etc/redis/redis.conf
cat > /etc/mysql/mariadb.conf.d/60-owncloud.cnf <<'EOF'
[mariadbd]
bind-address = 172.28.0.1
EOF

chown -R www-data:www-data $WEBROOT $DATAROOT
sed -i 's/^bind .*/bind 172.28.0.1/' /etc/redis/redis.conf
sed -i "s/^# requirepass .*/requirepass $REDIS_PASS/" /etc/redis/redis.conf

# stop services
service mysql stop
service apache2 stop

systemctl enable docker.service
install -d /etc/systemd/system/multi-user.target.wants
ln -s ../owncloud-network.service \
/etc/systemd/system/multi-user.target.wants/owncloud-network.service
ln -s ../owncloud.service \
/etc/systemd/system/multi-user.target.wants/owncloud.service
125 changes: 125 additions & 0 deletions docs/v19.0-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# ownCloud 19.0 testing

## Scope and source decision

ownCloud Server 11 supports PHP 8.3 or newer but supports deployment only
through the official ownCloud container image. Debian 13 Trixie provides PHP
8.4, so continuing the v18 manual archive installation would leave the
appliance outside ownCloud's maintained deployment contract. A disposable
Trixie probe confirmed that the 11.0.0 manual archive installs but fails when
it next opens its SQLite database on PHP 8.4.

The appliance therefore uses the official ownCloud Server 11.0.0 image for
amd64, pinned to manifest digest
`sha256:dbebc24fe77a35c5de621d38a3f7264ffb43e3ee321928cde9a563a72b8ff366`.
Skopeo retrieves and verifies that digest during the build. Docker, its
overlay-filesystem fallback, Skopeo, Apache, MariaDB, Redis and Adminer come
from signed Debian Trixie repositories.

The ownCloud container joins a dedicated `172.28.0.0/24` bridge. Debian
MariaDB and Redis listen only on its gateway, `172.28.0.1`, and Redis requires
a generated password. The ownCloud HTTP port binds only to host loopback.
Apache provides the public HTTPS endpoint. Persistent ownCloud configuration
and user data are stored under `/var/lib/owncloud`.

## Acceptance command

```sh
TKLDEV_CONTAINER=tkldev19-wave2 \
TKL_HARNESS_STATE_DIR=/home/agent/.local/state/turnkey-v19-harness-wave2 \
TKL_HARNESS_LOCK_FILE=/home/agent/.local/state/turnkey-v19-harness-wave2/build.lock \
TKL_HARNESS_DOCKER_LIMIT_BYTES=42949672960 \
/sandboxed-git/turnkey/tools/test-v19-appliance owncloud \
--source /home/agent/.local/worktrees/turnkey-apps/owncloud/wish-owncloud-v19-trixie
```

The command builds the Trixie root filesystem, imports it into Docker, boots
the normal systemd and firstboot path, then runs `tests/v19.sh`. The accepted
run, tested source, harness commit, report path and exact installed versions
are recorded below after exact acceptance passes.

## README crosswalk

| README contract | Focused check | Required result | Evidence |
| --- | --- | --- | --- |
| ownCloud is available through the HTTPS web endpoint | Request `/` and `/status.php` through Apache | The login page and installed ownCloud 11 status are returned over HTTPS; HTTP redirects to HTTPS | `tests/v19.sh` |
| The firstboot `admin` credential controls ownCloud | Request the authenticated OCS user endpoint | The response identifies the `admin` account | `tests/v19.sh` |
| Users can store and retrieve files | Create, read, update and delete a file through WebDAV, with MariaDB readback | Each content comparison passes, the database records the file and the deleted path returns HTTP 404 | `tests/v19.sh` |
| The opening description names contacts, photo galleries and calendars | Classify these product-level examples against focused appliance coverage | Deferred; v19 acceptance covers the WebDAV file lifecycle, not CardDAV, CalDAV or the gallery interface | Deferred |
| `turnkey-occ` provides command-line administration as `www-data` | Create, list and delete a temporary user through the wrapper | The user appears in both `occ` and MariaDB before deletion | `tests/v19.sh` |
| Persistent data is outside the application image | Inspect the running container and its `/mnt/data` mount | The official image runs with `/var/lib/owncloud` mounted at `/mnt/data` | `tests/v19.sh` |
| MariaDB and Redis are private application backends | Inspect listeners, Docker network addressing and Redis authentication | Both services listen only on the private bridge gateway; Redis rejects unauthenticated requests | `tests/v19.sh` |
| Background jobs run through cron | Inspect the installed schedule and OwnCloud background-job mode, then execute the scheduled command | The cron service and schedule are enabled, the mode is `cron` and `turnkey-occ system:cron` succeeds | `tests/v19.sh` |
| Adminer manages MariaDB over HTTPS on port 12322 | Submit the firstboot `adminer` login to the ownCloud database | Adminer accepts the credentials and exposes the ownCloud database | `tests/v19.sh` |
| ownCloud and Debian components have maintained update channels | Query `owncloud-update --check` and refresh APT metadata without installing changes | The official image digest and eligible signed Trixie candidates are returned; installed versions and the running image remain unchanged | `tests/v19.sh` |
| Webmin, SSH, Postfix, backup and other base services come from the inherited appliance layers | Exercise app-specific services and cite the unchanged Core and LAMP boundaries | Application services pass; inherited services retain their existing contracts | Core 19 and LAMP 19 acceptance reports |

## Update channel

`owncloud-update --check VERSION` resolves the current official amd64 digest
for an explicit ownCloud version tag without changing the appliance. After an
administrator reviews the release and takes a backup,
`owncloud-update VERSION sha256:DIGEST` requires the reviewed digest to match
the official tag, pulls that exact image, assigns a digest-derived local tag,
updates `/etc/owncloud/image.conf` and restarts the service. ownCloud performs
its supported database migration when the new container starts.

Debian and TurnKey components continue through their signed Trixie APT
repositories. The focused updater check refreshes metadata, verifies eligible
candidates and proves that the check itself leaves installed packages and the
running ownCloud image unchanged.

## Probe evidence

The official 11.0.0 image was exercised in a disposable bridge setup before
implementation. It connected to Trixie MariaDB and Redis on the bridge
gateway, initialized the administrator, reported version 11.0.0, created a
second user and persisted both users in MariaDB. The failed manual archive and
Unix-socket connection probes are recorded as disproved assumptions rather
than supported deployment paths.

## Accepted evidence

Exact acceptance passed on 26 August 2026.

- Run: `20260826t051749z-4089-14788`
- Tested source: `15e205df0a866da126ce1c9a54fdb1ce8422da51`
- Harness: `54ca2cff6b98a034089d186b249835b58fc467da`
- Report: `/home/agent/.local/state/turnkey-v19-harness-wave2/runs/owncloud/20260826t051749z-4089-14788/report.txt`
- Report SHA-256: `5f3f3c7e0b02071ee2e0b2551cadd2f9379f6591f65ac78abc3d9de9395a11ab`
- Retained evidence: all 8 checksums verified; credential-disclosure scan found 0 matches
- Verdict: `PASS`
- Installed versions: ownCloud 11.0.0, Apache 2.4.68,
MariaDB 11.8.6, Redis 8.0.2, Docker 26.1.5,
fuse-overlayfs 1.14 and Skopeo 1.18.0

The run completed normal initialization and firstboot, authenticated the
administrator, exercised WebDAV create, read, update and delete with MariaDB
readback, created and deleted a user through `turnkey-occ`, ran the cron
background command, verified authenticated Redis access and unauthenticated
denial, logged in to Adminer and checked both update channels without changing
the running image or installed packages. The report records the persistent
data mount, private network, signed Trixie package metadata and pinned official
amd64 image digest.

## Known limitations

The Docker acceptance path does not exercise the installer, kernel,
bootloader or physical hardware. It does exercise the appliance's nested
Docker daemon in the privileged systemd runtime, the same services and
network layout used on a normal installed appliance. The nested runtime uses
`fuse-overlayfs` because its root is already overlay-backed; a normal appliance
installed on a supported filesystem can use Docker's `overlay2` driver.

ownCloud Server 11 supports only container deployment. Administrators who add
applications requiring extra operating-system binaries must derive and pin a
custom image as described by ownCloud. This appliance intentionally keeps the
official image unchanged.

## Deferred issues

The acceptance flow covers the administrator endpoint, WebDAV file lifecycle,
MariaDB persistence, Redis authentication and command-line user management.
Desktop and mobile synchronization clients are not exercised because their
network behavior uses the same WebDAV endpoint and requires external client
systems.
11 changes: 4 additions & 7 deletions overlay/etc/apache2/sites-available/owncloud.conf
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,12 @@ ServerName localhost
<VirtualHost *:443>
SSLEngine on
ServerAdmin webmaster@localhost
DocumentRoot /var/www/owncloud/
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
RequestHeader set X-Forwarded-Proto "https"

<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains"
</IfModule>
</VirtualHost>

<Directory /usr/share/owncloud/>
Options +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
2 changes: 1 addition & 1 deletion overlay/etc/cron.d/owncloud
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# run cron.php for owncloud
*/15 * * * * www-data /usr/bin/php -f /var/www/owncloud/occ system:cron /dev/null 2>&1
*/15 * * * * root /usr/local/bin/turnkey-occ system:cron >/dev/null 2>&1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[Unit]
Requires=owncloud-network.service
After=owncloud-network.service
13 changes: 13 additions & 0 deletions overlay/etc/systemd/system/owncloud-network.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Unit]
Description=Prepare the private ownCloud container network
Requires=docker.service
After=docker.service
Before=mariadb.service redis-server.service owncloud.service

[Service]
Type=oneshot
ExecStart=/usr/local/lib/owncloud/network-ready
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
15 changes: 15 additions & 0 deletions overlay/etc/systemd/system/owncloud.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[Unit]
Description=ownCloud Server container
Requires=docker.service owncloud-network.service mariadb.service redis-server.service
After=docker.service owncloud-network.service mariadb.service redis-server.service

[Service]
Type=simple
ExecStartPre=/usr/local/lib/owncloud/wait-firstboot
ExecStart=/usr/local/lib/owncloud/run
ExecStop=-/usr/bin/docker stop --time 30 owncloud_server
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[Unit]
Requires=owncloud-network.service
After=owncloud-network.service
Loading