PWA manifest does not work with custom subdirectory, manifest.json

  • I have searched for duplicates (including closed issues)
  • I have read the docs
  • I have cleared the browser cache

Bug Summary

PWA manifest does not work with custom subdirectory, manifest.json

Steps to reproduce

  1. Hosting fmd-server on a custom domain AND in a custom subdirectory (https://fmd.example.com/secpath1234567890/).
  2. Configure reverse-proxy (HAproxy in my case, but should not matter) to strip the subdirectory as documented before passing requests on to the fmd-server
  3. works in the browser. The browser does not need the manifest.json
  4. When installing the WebApp on Android (GrapheneOS with Vanadium), the Webapp is installed on the homescreen, the icon is there.
  5. When opening it, it tries to access https://fmd.example.com/ and not my custom https://fmd.exmaple.com/secpath1234567890/

Actual behaviour

Using the Webapp fails when using it with the existing manifest.json. Overriding it with a custom manifest.json works.

Expected behaviour

The manifest.json should respect the configured/deployed base path.

Metadata

  • FMD Android version: 0.16.2 (44)
  • Device: Google Pixel 10
  • Android version: 17
  • ROM name: GrapheneOS
  • FMD Server version: 0.16.0
  • Browser: Librewolf 153.0.3-1

Other information

Motivation to host in subpath is to not be visible to random bots/scraper what is actually running here and reduce number of times the actual backend is used. Initially I wanted to use Basic-Auth or a custom HTTP header, but this seems to be not possible. This relates to fmd-android#208

relates to !182 (merged), but I think manifest.json still needs a refinement.

HAproxy config derived from actual config, I shortened to the essential info, but it looks very similar to this:

########################################################################
#
# Minimal HAProxy configuration for FMD Server
#
# FMD is exposed at:
# https://fmd.example.com/secpath1234567890/
#
########################################################################

global
	maxconn 1000
	user nobody
	group nogroup
	daemon
	nosplice

defaults
	mode http
	timeout connect 1s
	timeout client 60s
	timeout http-request 10s
	timeout http-keep-alive 10s
	timeout server 60s
	timeout server-fin 10s
	timeout tunnel 1h
	timeout client-fin 10s
	timeout tarpit 5s
	retries 2


########################################################################
# HTTP frontend
#
# Only serve certbot requests here.
########################################################################

frontend main_frontend_plain
	bind [::]:80,:80

	acl is_host_fmd hdr(host) -i fmd.example.com
	acl is_acme_challenge path_beg /.well-known/acme-challenge/

	use_backend backend_certbot if is_acme_challenge is_host_fmd

	default_backend backend_default


backend backend_certbot
	server certbot 127.0.0.1:9999


########################################################################
# HTTPS frontend
########################################################################

frontend main_frontend_tls
	bind [::]:443,:443 ssl crt /etc/haproxy/ssl/fmd-example-com.pem ssl-min-ver TLSv1.3 alpn h2,http/1.1

	# Preserve client IP
	option forwardfor
	http-request set-header X-Real-IP %[src]

	# HTTPS only
	http-request redirect scheme https unless { ssl_fc }
	http-request deny unless { ssl_fc }

	acl is_host_fmd hdr(host) -i fmd.example.com


	########################################################################
	# FMD subpath
	#
	# FMD is externally available at:
	# https://fmd.example.com/secpath1234567890/
	#
	# The subpath itself is handled correctly by FMD since !182.
	########################################################################

	acl is_fmd_prefix path_beg /secpath1234567890/

	# Redirect /secpath1234567890 to /secpath1234567890/
	acl is_fmd_no_slash path /secpath1234567890
	http-request redirect code 301 location https://%[hdr(host)]%[path]/ if is_host_fmd is_fmd_no_slash


	########################################################################
	# Workaround for manifest.json
	#
	# The current manifest uses:
	#     "start_url": "/"
	#
	# When FMD is installed as a PWA, the browser therefore opens
	# https://fmd.example.com/ instead of the FMD subpath.
	#
	# Override the manifest so that the installed PWA opens:
	# https://fmd.example.com/secpath1234567890/
	########################################################################

	acl is_fmd_manifest path /secpath1234567890/manifest.json
	http-request return status 200 content-type application/manifest+json string '{"name":"FMD Server","short_name":"FMD","description":"Locate and control your devices.","start_url":"/secpath1234567890/","display":"standalone","theme_color":"#4cb050","background_color":"#232323","icons":[{"src":"icon.svg","type":"image/svg+xml","sizes":"any"},{"src":"apple-touch-icon.png","type":"image/png","sizes":"180x180"}]}' if is_host_fmd is_fmd_manifest


	########################################################################
	# Remove the external subpath before forwarding to FMD
	########################################################################

	http-request set-path %[path,regsub(^/secpath1234567890,)] if is_host_fmd is_fmd_prefix


	########################################################################
	# Only expose FMD below the configured subpath
	########################################################################

	http-request tarpit deny_status 404 if is_host_fmd !is_fmd_prefix

	use_backend backend_fmd_http if is_host_fmd

	default_backend backend_default


########################################################################
# FMD backend
########################################################################

backend backend_fmd_http
	server FMD_SERVER_HTTP 127.0.0.1:8888


########################################################################
# Default backend
########################################################################

backend backend_default
	http-request redirect code 301 location https://%[hdr(host)]%[capture.req.uri] unless { ssl_fc }
	http-request deny deny_status 404
Edited by TS