I was reading some discussion on Hacker News and the fine folks there mentioned Dawarich, a self-hostable server for managing your location data. I got interested in this sort of thing. I've never really used stuff like this before for myself, even from the big names. I use Google Maps for navigation, but not for showing myself my location history. I'm sure the setting for "do not record my location" merely turns off my ability to look it up; I'm sure Google still knows exactly where my mobile device has been (that is not the same as where I have been) across all of time.
But F-Droid didn't have the Dawarich app, but it had the app for owntracks, a similar tool.
Stackrpms installation of owntracks
This application is for tracking my location history on my own infrastructure.
Goals
I want to be able to view my location history. In the past, I used Google Maps location history to find where I had stayed on a particular vacation. I want to be able to do this sort of auditing without depending on external vendors.
Setup
This application is installed in docker on server4.
sudo useradd owntracks
sudo usermod -a -G docker owntracks
sudo su - owntracks
mkdir -p compose ; cd compose
I established file docker-compose.yml and config.js. I just picked random ports available, including server4:8083 for recorder, and server4:8085 for frontend.
On server3, set up custom apache httpd config owntracks.cnf which is an adaptation of [Reference #5][5]. Adapt local_mirror.conf to include this for VirtualHosts 443 (internal https) and 444 (external https).
Establish new password repository. Use password scheme 3j.
# as root@server3
htpasswd -c .owntracks device5
htpasswd -c .owntracks device4
Added a port in the firewall on server4.
sudo firewall-cmd --add-port=8083/tcp
sudo firewall-cmd --add-port=8085/tcp
sudo firewall-cmd --add-port=1883/tcp
sudo firewall-cmd --add-port=8883/tcp
I established the container mosquitto, which uses its own TLS cert. The openssl req needed to be run on a newer system where parameter -addext can be used. I ran the ipa cert-request from server4 which owns the service we add here.
openssl genpkey -algorithm RSA -out https-server4.ipa.internal.com.key
openssl req -new -key https-server4.ipa.internal.com.key -subj "/O=IPA.INTERNAL.COM/CN=server4.ipa.internal.com" -addext "subjectAltName = DNS:server4.ipa.internal.com,DNS:www.example.com" -out https-server4.ipa.internal.com.csr
ipa service-add --force HTTP/server4.ipa.internal.com
ipa cert-request --principal=HTTP/server4.ipa.internal.com https-server4.ipa.internal.com.csr --certificate-out=https-server4.ipa.internal.com.pem
I configured the main router to forward port 8883/tcp to server4:8883. There might be a way to use an apache httpd reverse proxy for websockets to mqtt, but I have not investigated that.
To establish the mosquitto password database, use -c in the command, inside the container.
mosquitto_passwd -c /mosquitto/config/password_file recorder
The rest of the commands will omit -c.
The mosquitto config is in file mosquitto-conf/mosquitto.conf, and uses TLS.
Establishing useful contact info with cards
I want to be able to see pretty names/faces for "friends". https://owntracks.org/booklet/features/card/
I Used https://github.com/owntracks/recorder/raw/refs/heads/master/contrib/faces/image2card.sh from https://github.com/owntracks/recorder/blob/master/contrib/faces/image2card.sh to do this:
sh image2card.sh user1.jpg "user1" "na" > device5-device5.json
sh image2card.sh user2.png "user2" "nn" > device4-device4.json
sh image2card.sh user3.png "user3" "eo" > device2-device2.json
I prepared these so they are accessible for container mosquitto in /mosquitto/config/cards/, and then entered the container and ran these commands.
docker-compose exec mosquitto /bin/sh
mosquitto_pub -L 'mqtt://recorder:KEEPASS@localhost:1883/owntracks/device5/device5/info' -f /mosquitto/config/cards/device5-device5.json -r -q 2 -d
To remove/delete a card:
mosquitto_pub -L 'mqtt://recorder:KEEPASS@localhost:1883/owntracks/device5/device5/info' -n -r -d
Associated files
On server server4.
- /home/owntracks/compose
- config.js, taken from official example https://github.com/owntracks/frontend/blob/main/public/config/config.example.js for frontend.
- docker-compose.yml, very simple combination of official compose example files for recorder (backend) and frontend.
- mosquitto-conf/password_file
- mosquitto-conf/mosquitto.conf
- mosquitto-conf/https-server4.ipa.internal.com.key
- mosquitto-conf/https-server4.ipa.internal.com.pem
- mosquitto-conf/ca-ipa.internal.com.pem
-
mosquitto-conf/cards directory of custom .json files for "cards" that describe the various devices, and the script that loads them
!/bin/sh
cd "${1}"
for word in *.json ; do echo "${word%%.json}" | while IFS='-' read a b ; do mosquitto_pub -L "mqtt://recorder:KEEPASS@localhost:1883/owntracks/${a}/${b}/info" -f "${word}" -r -q 2 -d ; done ; done
On server server3, the main web server.
- /etc/httpd/conf.d/owntracks.cnf
- /etc/httpd/conf.d/local_mirror.conf includes owntracks.cnf in virtualhosts 443 and 444.
- /etc/httpd/.owntracks (or similar) for the credential.
Associated urls
Operations
Restarting the containers
Connect to owntracks@server4.
docker-compose pull ; docker-compose down ; docker-compose up -d
Adding a new device
Adding a device for MQTT auth
Connect to the mosquitto container and then modify the existing password file. The username will probably be the device name.
docker-compose exec mosquitto /bin/sh
mosquitto_passwd /mosquitto/config/password_file <username>
<password>
I am not sure if container mosquitto needs to be restarted to take effect.
Configure the client settings Connection.
Mode=MQTT
Host=www.example.com
Port=8883
Client ID=<device name>
Use Websockets=True
Device ID=<device name>
Tracker ID=?????
Username=<from password_file>
Password=<from password_file>
TLS=True
Make sure the android device trusts the CA cert, which is available at https://server3/internal/certs/ca-ipa.internal.com.crt
Adding a device for http auth
WARNING I think this might work, but it also might not work anymore now with MQTT usage.
I have decided to use a separate http credential for each device. Visit server3 and set up a new credential in the password file. This example shows adding device4.
sudo htpasswd -c /etc/httpd/.owntracks device4
<enter a password, probably "KEEPASS">
It is not necessary to reload the web server. Then configure OwnTracks on the new device to use this http endpoint.
URL=https://www.example.com/owntracks/pub
Device ID=device4
Tracker ID=<anything will do fine>
Username=device4
Password=<same as from htpasswd command>
Removing data about an old user/device combo.
To remove user "user" device "device5", run this command:
# on server4
sudo rm -rf /home/owntracks/compose/owntracks-recorder/store/last/user/device5
I am not sure if this removes info in the frontend for this user+device.
Viewing server app logs
docker-compose logs -f otrecorder mosquitto
Viewing location history
Visit http://server4:8085/ which is container frontend.
Re-adding the cards
A card is the pretty info about a device, such as user name and picture. These are hand-curated with a useful script (search image2card.sh in the install section), and after a container restart, you need to reload these.
docker-compose exec mosquitto /mosquitto/config/cards/import-cards /mosquitto/config/cards
References
- Self-Hosted device tracking with OwnTracks | Brian Douglass
- owntracks/recorder - Docker Image | Docker Hub
- owntracks/frontend: 🌍 Web interface for OwnTracks built with Vue.js
- owntracks/frontend - Docker Image | Docker Hub
- owntracks/reverse-proxy.conf at main · l33tn00b/owntracks
- mqtt - How to configure two Mosquitto listeners with different protocols? - Stack Overflow
- Latest way to get certificate in FreeIPA | Knowledge Base
- How to setup selfhosted owntracks server
- Card - OwnTracks Booklet
- Friends - OwnTracks Booklet
- mosquitto_pub delete topic at DuckDuckGo
Alternate reading
In case I want to experiment with using httpd to reverse-proxy MQTT or websockets.
- https://www.rushworth.us/lisa/?p=358
-
proxy - Mosquitto + Apache - Super User
<VirtualHost *:1883>
ProxyRequests Off
ProxyPreserveHost On
ProxyPass /mqtt ws://$Broker-IP:$Broker-Port
ProxyPassReverse /mqtt ws://$Broker-IP:$Broker-Port
</VirtualHost>
-
n8n apache2 reverse proxy fix websockets – 🔐 Karlo Luiten
<IfModule mod_ssl.c>
<VirtualHost *:443>
SSLEngine off
ServerAdmin webmaster@karloluiten.nl
ServerName n8n.karloluiten.nl
DocumentRoot "/var/www/html/"
ErrorLog "${APACHE_LOG_DIR}/error_n8n.servar_nl.log"
CustomLog ${APACHE_LOG_DIR}/access_n8n.servar_nl.log combined
RequestHeader set X-Forwarded-Proto https
RemoteIPHeader X-Forwarded-For
RequestHeader set X-Forwarded-Host "%{SERVER_NAME}e"
ProxyPreserveHost Off
ProxyPass / http://10.0.40.54:5678/
ProxyPassReverse / http://10.0.40.54:5678/
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://10.0.40.54:5678/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*) http://10.0.40.54:5678/$1 [P,L]
ProxyPassReverse / https://n8n.karloluiten.nl
SSLCertificateFile /etc/letsencrypt/live/n8n.karloluiten.nl/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/n8n.karloluiten.nl/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
Obviously fill in your own details/domains/ip.
Also for env vars:
N8N_BASIC_AUTH_ACTIVE=true
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=xxx
N8N_SECURE_COOKIE=false
WEBHOOK_URL=https://n8n.karloluiten.nl/
N8N_PROXY_HOPS=1
-
Reverse Proxying WebSockets through mod_proxy — HTTP Failback – Lisa's Home Page
I’ve been successfully reverse proxying MQTT over WebSockets via Apache HTTPD for quite some time now. The last few weeks, my phone isn’t able to connect. There’s no good rational presented (and manually clicking the “send data” button on my client successfully connects). It was time to upgrade the server anyway. Once I got the latest Linux distro on the server, I couldn’t connect at all to my MQTT server. The error log showed AH00898: Error reading from remote server returned by /mqtt
Evidently, httpd 2.4.47 added functionality to upgrade and tunnel in accordance with RFC 7230. And that doesn’t work at all in my scenario. Haven’t dug in to the why of it yet, but adding ProxyWebsocketFallbackToProxyHttp Off to the reverse proxy config allowed me to successfully communicate with the MQTT server through the reverse proxy.