poatmyp ("point at my pdf") is a simple, one-file server that lets people share a display of a pdf (and not more) in a web browser. With javascript and websockets on in a user's browser, they will have a shared pointer. Without javascript, people will need to manually reload when a new slide should be shown, and they won't have a shared pointer. Running it for fun:: python3 poatmyp.py -a Then point a browser to http://localhost:8900 or http://your-ip:8900, upload a pdf and share the link you're being redirected to (this may fail if the browsers are configured to deny websockets to http pages). Dependencies: python3-pil, python3-pdfrw, mupdf-tools Proper installation: You'll need a reverse proxy to do the https termination, and you'll have to come up with a start script. Here's an nginx snippet that lets you run poatmyp within another service at the location /p ("pdf" or "presentation"): rewrite ^/p$ /p/ permanent; location /p { rewrite ^/p(.*)$ $1 break; proxy_pass http://localhost:8900; } location ~ ^/p/[^/]*/websocket$ { rewrite ^/p(.*)$ $1 break; proxy_pass http://localhost:8900; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; } As to a start script... you'll want to run poatmyp as a minimally privileged user, as rendering PDFs is something likely to be exploitable now and then (though mupdf appears to be a lot less stinky than poppler). If you can sandbox it, even better. Here's a baseline initscript (a systemd unit is quite a bit simpler); of course, you'll have to adapt the script location:: ### BEGIN INIT INFO # Provides: poatmyp # Required-Start: $local_fs $network # Required-Stop: $local_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: poatmyp shared pdf daemon # Description: A piece of twisted listening on 8900. ### END INIT INFO SCRIPT_LOCATION=/home/msdemlei/gavo/poatmyp/poatmyp.py DAEMONOPTS="--pidfile /run/poatmyp.pid --oknodo --exec /usr/bin/python3" do_start() { start-stop-daemon --start $DAEMONOPTS \ --make-pidfile --background --chuid nobody \ -- $SCRIPT_LOCATION } do_stop() { start-stop-daemon --stop $DAEMONOPTS \ --remove-pidfile \ -- $SCRIPT_LOCATION } case "$1" in start) do_start ;; stop) do_stop ;; restart) do_stop do_start ;; *) echo "USAGE: $0 start|stop|restart" ;; esac exit 0