How a note typed on my iPhone ends up on my laptop, through my home server. No third-party cloud, just WebDAV, git and a systemd timer.
phone ── WebDAV ──> server ── git push ──> GitHub ── git pull ──> laptop
The server itself (hardware, firewall, SSH, Pi-hole) is in homeserver-barebasics.
- I use an org-mode app on my iPhone for quick notes. It saves them to
mobile-inbox.orgon the server over WebDAV - Every 5 minutes,
org-syncon the server moves anything new from that file into my notes repo, and empties the phone's copy - Then it commits, pulls and pushes
- My laptop runs the same script on the same timer, so it pulls the note down
A note typed on my phone shows up on my laptop in under 10 minutes.
If two machines edit the same lines at the same time, git can't merge them. The script then stops, logs an error, and waits for me to fix it by hand.
WebDAV is file sharing over HTTPS.
- Apache serves one folder,
~/webdav. The only file in it ismobile-inbox.org - Port 8443, because Pi-hole already uses 80 and 443
- Password protected, and only reachable over the tailnet
- HTTPS certificate comes from Tailscale (
tailscale cert). It lasts 90 days and I renew it by hand
| Port | Who can reach it | RAM used |
|---|---|---|
| 8443 | Tailnet only | 12 MB (Apache) |
RAM measured with systemd-cgtop -m.
Needs the base setup from homeserver-barebasics done first.
Apache, over HTTPS, tailnet only. Pi-hole already has ports 80 and 443, so Apache can't use them.
sudo apt install -y apache2 apache2-utils
sudo cp apache/ports.conf.example /etc/apache2/ports.conf
sudo a2dissite 000-default
sudo a2enmod dav dav_fs auth_basic ssl
sudo htpasswd -c /etc/apache2/webdav.htpasswd <user>
mkdir -p ~/webdav && chmod 775 ~/webdav
sudo usermod -aG <user> www-data
Get a real certificate from Tailscale. iPhones won't accept plain HTTP or a self-signed one:
sudo tailscale cert \
--cert-file /etc/ssl/<host>.<tailnet>.ts.net.crt \
--key-file /etc/ssl/<host>.<tailnet>.ts.net.key \
<host>.<tailnet>.ts.net
Copy apache/webdav.conf.example to
/etc/apache2/sites-available/webdav.conf, fill in the placeholders,
then:
sudo a2ensite webdav
sudo apache2ctl configtest
sudo systemctl restart apache2
sudo ss -tlnp | grep 8443
The certificate lasts 90 days. To renew, run the tailscale cert
command again and restart Apache.
The server needs its own SSH key for GitHub:
ssh-keygen -t ed25519 -C "<host>"
cat ~/.ssh/id_ed25519.pub # add this to GitHub, Settings > SSH keys
ssh -T git@github.com
Clone your notes repo and set who the commits come from:
git clone git@github.com:<you>/<notes-repo>.git ~/org
git config --global user.name "<n>"
git config --global user.email "<email>"
Then this repo, and install:
git clone git@github.com:<you>/org-sync.git ~/src/org-sync
~/src/org-sync/install.sh server
install.sh server links the script into ~/.local/bin, installs the
timer, opens 8443 on the tailnet, and turns on linger. Without linger
the timer stops when you log out.
Same notes repo in ~/org, then:
git clone git@github.com:<you>/org-sync.git ~/src/org-sync
~/src/org-sync/install.sh
The laptop has no ~/webdav, so the script skips the phone part and
just syncs.
Apache wouldn't start. sudo ss -tlnp showed Pi-hole already using port 80.
I turned off Apache's port 80 and moved it to 8443. Then turning on
HTTPS in Apache quietly added port 443 back, and it failed again on
that. I turned that off too.
The phone app wouldn't sync, and Apache's log was empty. The request never left the phone. iOS blocks apps from using plain HTTP, and it also rejected a self-signed certificate. A real certificate from Tailscale fixed it.
- The HTTPS certificate has to be renewed by hand every 90 days
- A conflict stops the sync on that machine until I fix it by hand
systemctl --user list-timers | grep org # is the sync timer running?
journalctl --user -u org-sync -n 20 # last sync runs and errors
sudo ss -tlnp | grep 8443 # is Apache listening?
sudo openssl x509 -in /etc/ssl/<host>.<tailnet>.ts.net.crt -noout -enddate # cert expiryorg-sync the sync script
org-sync.service runs it once
org-sync.timer every 5 minutes, starting 1 minute after boot
install.sh links the script, installs the timer
apache/ports.conf.example Apache with 80 and 443 turned off
apache/webdav.conf.example the WebDAV site on 8443