Firefox Sync Server and Apache as a proxy

Life sometimes is like ping pong.

  • Firefox sync is such a great feature. ping
  • But it’s worrisome to store all your passwords to someone’s else machine. pong
  • There is the syncserver. It’s opensource! You can run it in your premises. ping
  • But it is a python2 project. It may be a problem some day. pong (sort of)
  • Who cares about python3. It has this WSGI thingy and we can plug it to a public apache with a nice SSL and be done with it. ping (almost)

5 years later

  • Looks like distribution support for python2 is fading. There is still python2 but we cannot run it in the public apache because it runs a host of other things that require python 3 WSGI. pong
  • Told you so. double pong
  • Ok. Don’t panic. How difficult would be to port it to python3? ping?
  • From the looks of #179 and #165 that isn’t going to happen. Syncserver was not part of Mozilla infrastructure and there is a Rust port underway which of course is not ready for general consumption yet. pong

So what options do we have? If we run it with

make serve

it starts a server a localhost:5000. Maybe we could proxy from our public apache.

Unfortunately all guides I could find was about setting nginx as reverse proxy or with apache + mod_wsgi but nothing about apache as a reverse proxy for syncserver. Given the vast options of apache configuration that was a suprise. I mean: is it even possible to find something that cannot be done with apache configuration?

Indeed after extensive search and experimentation I found the combination of options that form the solution. The specific options are more or less mentioned at https://github.com/mozilla-services/syncserver/issues/131 but I will try to make them more clear and explicit. So here are the non obvious configuration settings.

syncserver.ini

Below is the diff of syncserver.ini that works for me.

diff --git a/syncserver.ini b/syncserver.ini
index ccf1ae0..edb1763 100644
--- a/syncserver.ini
+++ b/syncserver.ini
@@ -11,7 +11,7 @@ use = egg:syncserver
[syncserver]
# This must be edited to point to the public URL of your server,
# i.e. the URL as seen by Firefox.
-public_url = http://localhost:5000/
+public_url = https://www.my-public-address.org/

# By default, syncserver will accept identity assertions issued by
# any BrowserID issuer.  The line below restricts it to accept assertions
@@ -21,7 +21,7 @@ identity_provider = https://accounts.firefox.com/

# This defines the database in which to store all server data.
#sqluri = sqlite:////tmp/syncserver.db
-#sqluri = pymysql://sample_user:sample_password@127.0.0.1/syncstorage
+sqluri = pymysql://sync-user:sync-password@localhost:3306/syncserver

# This is a secret key used for signing authentication tokens.
# It should be long and randomly-generated.
@@ -30,7 +30,7 @@ identity_provider = https://accounts.firefox.com/
#    head -c 20 /dev/urandom | sha1sum
#
# If not specified then the server will generate a temporary one at startup.
-#secret = INSERT_SECRET_KEY_HERE
+secret = SECRET_KEY

# Set this to "false" to disable new-user signups on the server.
# Only requests by existing accounts will be honoured.
@@ -56,3 +56,4 @@ force_wsgi_environ = false

# "{node}/1.5/{uid}"
# sync-1.5 = "http://localhost:8000/1.5/{uid}"
+sync-1.5 = "https://www.my-public-address.org/storage/1.5/{uid}"   #<-----------This is the trick no 1

The first trick is to specify the storage server because it is not calculated properly from the public address. Probably the authors have provisions to host the storage server to a different machine but that just complicate things. If you open firefox’s about:sync-log you will notice that it tries to access localhost:5000 after the initial handshake and it fails if your firefox runs in a different machine from the sync server.

Here is the relevant bit from the apache configuration.

<VirtualHost *:80>
        ServerName www.my-public-address.org
        Redirect / https://www.my-public-address.org/
</VirtualHost>

<VirtualHost *:443>
        #SSLProxyEngine On
        ServerName www.my-public-address.org

        SSLEngine On
        SSLProtocol all -SSLv2
        SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM
        SSLCertificateFile /etc/letsencrypt/live/www.my-public-address.org/cert.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/www.my-public-address.org/privkey.pem
        SSLCertificateChainFile /etc/letsencrypt/live/www.my-public-address.org/chain.pem

        CustomLog /var/log/apache2/access_sync.log combined
        ErrorLog /var/log/apache2/error_sync.log
        LogLevel info

        ProxyPreserveHost On                          # <-- This is the trick no 2
        RequestHeader set X-Forwarded-Proto "https"   # <-- This is the trick no 3
        ProxyPass / http://localhost:5000/
        ProxyPassReverse / http://localhost:5000/
</VirtualHost>
  • The second trick is to preserve the public host name address in HTTP headers that go to the syncserver with the ProxyPreserveHost directive.
  • The third trick is to respect the https protocol when we proxy from https to http

Without the above two trick the proxying is not working and firefox cannot sync.

And after that what? Are we going to run make serve every time we reboot the apache machine?

Let’s wrap it in a systemd service. Here is the service file located at /etc/systemd/system/sync.service

[Unit]
Description=Start firefox syncserver
After=network.target

[Service]
Restart=always
RestartSec=1
User=www-data
WorkingDirectory=/var/www-ssl/syncserver
ExecStart=make serve

[Install]
WantedBy=multi-user.target

Run the command below in order to enable the service to run on boot.

systemctl enable sync

Run the command below to start the service immediately.

systemctl start sync

Hope that helps.

References