Because the PinePhone is designed a lot like a Raspberry Pi, using it as a server is a perfectly reasonable thing to mess with.
Install Docker on the PinePhone, run Nextcloud, and set up a private cloud drive. Then use the phone app to upload photos to Nextcloud for backup.

No hardware mods to the PinePhone itself, such as soldering. No screws removed either. The PinePhone can also keep running without relying on the battery.
1. Install the System to an SD Card#
I chose to install the system to an SD card because if I later want to turn it back into a phone, I can just pull the card out. Worst case, I can dd the entire SD card to a computer for storage, and I do not have to configure the software again.
To let the PinePhone choose whether to boot from the SD card or eMMC, install Tow-Boot first.
Next, install Mobian, which is based on Debian. Download the image from the official site, then flash the system.
After flashing, hold the volume-down button after the first red LED lights up during boot, then boot from the SD card. After booting, update packages and set the time zone.
If you remove the PinePhone battery, the modem stops working, so networking has to go through a Type-C hub with an external network adapter or Ethernet. My Wi-Fi adapter needs the community 88x2bu driver, compiled and installed manually.
2. Install Docker#
I chose Docker because the manual setup ran straight into PHP dependency hell. No thanks.
- Install the Debian prerequisites for Docker.
sudo apt update
sudo apt-get install a-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null- After adding the GPG key, because Mobian is bookworm and has no release file here, change it to bullseye before installing Docker.
# Change "bookworm" in this file to "bullseye"
sudo vi /etc/apt/sources.list.d/docker.list- Install Docker.
sudo apt-get install docker-ce docker-ce-cli containerd.io- Check that Docker is running.
$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
7050e35b49f5: Pull complete
Digest: sha256:10d7d58d5ebd2a652f4d93fdd86da8f265f5318c6a73cc5b6a9798ff6d2b2e67
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.- Install docker-compose. The official instructions had a bug; GitHub says to install this version instead.
sudo curl -L "https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose- Check the docker-compose version.
$ docker-compose --version
Docker Compose version v2.2.23. Create the Nextcloud Container#
- Create the docker compose file.
vim docker-compose.yml- Add the following content. MySQL does not seem to have an ARM version, so I used MariaDB instead.
version: "3"
services:
nextcloud:
image: nextcloud:latest
restart: unless-stopped
ports:
- 80:80
environment:
- MYSQL_HOST=mysql
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_PASSWORD=nextcloud
volumes:
- nextcloud:/var/www/html
mysql:
image: MariaDB:10.5.8
restart: unless-stopped
environment:
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_PASSWORD=nextcloud
- MYSQL_ROOT_PASSWORD=nextcloud
volumes:
- mysql:/var/lib/mysql
volumes:
mysql:
nextcloud:- Deploy it and wait for the containers to finish downloading. These containers will also start automatically when the phone boots.
sudo docker-compose up -d4. Initialize Nextcloud#
- Open a browser on the PinePhone, enter
localhost, and go to Nextcloud. Create an admin account, click “Install”, and wait about 10 minutes for installation to finish.

- Next, install the other services, then wait another 5 minutes for installation to finish.

- Run the following command to send instructions to the Nextcloud container through
docker exec, adding the Android phone’s IP to the allowlist. Put the domain after"value". It still did nothing for me, so I changed it to allow login from any domain. Dangerous, do not try this at home.
sudo docker exec --user www-data mobian-nextcloud-1 php occ config:system:set trusted_domains 1 --value=*Since the PinePhone and Android phone are connected to the same Wi-Fi, open the official Nextcloud app on the Android phone, enter the PinePhone’s IP, and log in to Nextcloud.

After logging in with the phone app, the interface works like a normal cloud drive. You can upload and view files.

Photo upload speed is decent, but you need to wait about 10 seconds for it to refresh.

After that, you can keep configuring Nextcloud with external storage, external network access, and so on.
5. Summary#
Having the Nextcloud containers start automatically at boot is convenient, but a full PinePhone boot takes about 2 minutes. Especially with the system installed on an SD card, shutdown also takes longer.
Even so, the PinePhone really can work as a simple server. In an emergency, it even has a touchscreen. Fancy.
6. References#
- Install Docker Engine on Debian - docker docs
- How to Self-Host a Collaborative Cloud with Nextcloud and Docker - cloud savvy IT
- /usr/local/bin/docker-compose: line 1: Not: command not found #6268 - Github
- Docker (Apple Silicon/M1 Preview) MySQL “no matching manifest for linux/arm64/v8 in the manifest list entries” - stackoverflow
- Add a Trusted Domain to Nextcloud - Laur IVAN | PRO
