diff --git a/Makefile b/Makefile
index f867fcd3582628788bb6fe53c7bcf69b541a5b2d..88793bd7b0e319b9412d7edfbe2c8b80253c1851 100644
--- a/Makefile
+++ b/Makefile
@@ -29,6 +29,7 @@ SCRIPTS = branding/scripts
 all: icon locales helper build
 
 HAS_QTIFW := $(shell PATH=$(PATH) which binarycreator)
+OPENVPN_BIN = "$(HOME)/openvpn_build/sbin/$(shell grep OPENVPN branding/thirdparty/openvpn/build_openvpn.sh | head -n 1 | cut -d = -f 2 | tr -d '"')"
 
 
 #########################################################################
@@ -55,17 +56,22 @@ dependsDarwin:
 	@brew install python3 golang make pkg-config curl
 	@brew install --default-names gnu-sed
 
+ifeq ($(PLATFORM), darwin)
+ EXTRA_FLAGS = MACOSX_DEPLOYMENT_TARGET=10.10 GOOS=darwin CC=clang
+else
+ EXTRA_FLAGS =
+endif
 golib:
-	CGO_ENABLED=1 go build -buildmode=c-archive -o ${TARGET_GOLIB} ${SOURCE_GOLIB}
+	CGO_ENABLED=1 ${EXTRA_FLAGS} go build -buildmode=c-archive -o ${TARGET_GOLIB} ${SOURCE_GOLIB}
+
+build: build_helper build_openvpn
+	@XBUILD=no gui/build.sh
 
 build_helper:
 	@echo "PLATFORM: ${PLATFORM}"
 	@mkdir -p build/bin/${PLATFORM}
 	go build -o build/bin/${PLATFORM}/bitmask-helper -ldflags "-X main.AppName=${PROVIDER}VPN -X main.Version=${VERSION}" ./cmd/bitmask-helper/
 
-build: build_helper
-	@gui/build.sh
-
 build_old:
 ifeq (${XBUILD}, yes)
 	$(MAKE) build_cross_win
@@ -81,9 +87,16 @@ else
 	@gui/build.sh
 endif
 
+build_openvpn:
+	@[ -f $(OPENVPN_BIN) ] && echo "OpenVPN already built at" $(OPENVPN_BIN) || ./branding/thirdparty/openvpn/build_openvpn.sh
+
 build_installer: check_qtifw build
 	cp -r qtbuild/release/${PROVIDER}-vpn.app installer/packages/${PROVIDER}vpn/data/
 	cp build/bin/${PLATFORM}/bitmask-helper installer/packages/${PROVIDER}vpn/data/
+	cp $(OPENVPN_BIN) installer/packages/${PROVIDER}vpn/data/openvpn.leap
+	cp branding/templates/osx/bitmask.pf.conf installer/packages/${PROVIDER}vpn/data/helper/bitmask.pf.conf
+	cp branding/templates/osx/client.up.sh installer/packages/${PROVIDER}vpn/data/
+	cp branding/templates/osx/client.down.sh installer/packages/${PROVIDER}vpn/data/
 	cd installer && qmake && make
 
 check_qtifw: 
@@ -263,6 +276,7 @@ package_deb:
 	@make -C build/${PROVIDER} pkg_deb
 
 installer_win:
+	# XXX refactor with build_installer
 	cp helper.exe ${WININST_DATA}
 	cp qtbuild/release/${TARGET}.exe ${WININST_DATA}${PROVIDER}-vpn.exe
 	windeployqt --qmldir gui/qml ${WININST_DATA}${PROVIDER}-vpn.exe
diff --git a/bitmask.pro b/bitmask.pro
index 7f4b488a4a2ed81731332a27061cdfcd8f5cb256..7acf7a962cbb07f5a273a32eb1ae6b1e975fe088 100644
--- a/bitmask.pro
+++ b/bitmask.pro
@@ -5,7 +5,7 @@ CONFIG += qt staticlib
 windows:CONFIG += console
 unix:DEBUG:CONFIG += debug
 lessThan(QT_MAJOR_VERSION, 5): error("requires Qt 5")
-QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.14
+QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.12
 
 macx {
     LIBS += -framework Security
diff --git a/branding/installer/osx/se.leap.bitmask-helper.plist b/branding/installer/osx/se.leap.bitmask-helper.plist
new file mode 100644
index 0000000000000000000000000000000000000000..c9d968701af75ff0b5cc74b3f95ed4ae19e426df
--- /dev/null
+++ b/branding/installer/osx/se.leap.bitmask-helper.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>WorkingDirectory</key>
+	<string>/tmp</string>
+	<key>StandardOutPath</key>
+	<string>bitmask-helper.log</string>
+	<key>StandardErrorPath</key>
+	<string>bitmask-helper-err.log</string>
+	<key>GroupName</key>
+	<string>daemon</string>
+	<key>RunAtLoad</key>
+	<true/>
+	<key>SessionCreate</key>
+	<true/>
+	<key>KeepAlive</key>
+    <true/>
+    <key>ThrottleInterval</key>
+    <integer>5</integer>
+    <key>Label</key>
+	<string>se.leap.BitmaskHelper</string>
+	<key>Program</key>
+    <string>PATH/bitmask-helper</string>
+</dict>
+</plist>
diff --git a/branding/installer/post-install.py b/branding/installer/post-install.py
new file mode 100755
index 0000000000000000000000000000000000000000..02da859f2bccf43beba1d705fb2a13b0f28b4916
--- /dev/null
+++ b/branding/installer/post-install.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+
+import os
+import shutil
+import sys
+import subprocess
+
+HELPER = "bitmask-helper"
+HELPER_PLIST = "/Library/LaunchDaemons/se.leap.bitmask-helper.plist"
+_dir = os.path.dirname(os.path.realpath(__file__))
+
+def main():
+    log = open(os.path.join(_dir, 'post-install.log'), 'w')
+    log.write('Checking for admin privileges...\n')
+
+    _id = os.getuid()
+    if _id != 0:
+      err  = "error: need to run as root. UID: %s\n" % str(_id)
+      logErr(log, err)
+    
+    # failure: sys.exit(1)
+    
+    if isHelperRunning():
+        log.write("Trying to stop bitmask-helper...\n")
+	# if this fail, we can check if the HELPER_PLIST is there
+        ok = unloadHelper()
+        log.write("success: %s \n" % str(ok))
+
+    ok = fixHelperOwner(log)
+    log.write("chown helper: %s \n" % str(ok))
+
+    log.write("Copy launch daemon...\n")
+    copyLaunchDaemon()
+
+    out = launchHelper()
+    log.write("Copy plist: %s \n" % str(ok))
+
+    grantPermissionsOnLogFolder()
+    
+    # all done
+    log.write('post-install script: done\n')
+    sys.exit(0)
+
+
+def logErr(log, msg):
+    log.write(msg)
+    sys.exit(1)
+
+def isHelperRunning():
+    ps = _getProcessList()
+    return HELPER in ps 
+
+def unloadHelper():
+    out = subprocess.call(["launchctl", "unload", HELPER_PLIST])
+    return out == 0
+
+def fixHelperOwner(log):
+    path = os.path.join(_dir, HELPER)
+    try:
+        os.chown(path, 0, 0)
+    except OSError as exc:
+        log.write(str(exc))
+        return False
+    return True
+
+def copyLaunchDaemon():
+    plist = "se.leap.bitmask-helper.plist"
+    path = os.path.join(_dir, plist)
+    dest = os.path.join('/Library/LaunchDaemons', plist)
+    _p = _dir.replace("/", "\/")
+    subprocess.call(["sed", "-i.back", "s/PATH/%s/" % _p, path])
+    shutil.copy(path, dest)
+
+def launchHelper():
+    out = subprocess.call(["launchctl", "load", "/Library/LaunchDaemons/se.leap.bitmask-helper.plist"])
+    return out == 0
+
+def grantPermissionsOnLogFolder():
+    helperDir = os.path.join(_dir, 'helper')
+    try:
+        os.makedirs(helperDir)
+    except Exception:
+        pass
+    os.chown(helperDir, 0, 0)
+
+def _getProcessList():
+    _out = []
+    output = subprocess.Popen(["ps", "-ceA"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    stdout, stderr = output.communicate()
+    for line  in stdout.split('\n'):
+        cmd = line.split(' ')[-1]
+        _out.append(cmd.strip())
+    return _out
+
+if __name__ == "__main__":
+    main()
diff --git a/branding/thirdparty/openvpn/build.mk b/branding/thirdparty/openvpn/build.mk
new file mode 100644
index 0000000000000000000000000000000000000000..df87eb2861c8e58f82be2dda16dba5a316636e24
--- /dev/null
+++ b/branding/thirdparty/openvpn/build.mk
@@ -0,0 +1,11 @@
+build_static_openvpn:
+	pkg/thirdparty/openvpn/build_openvpn.sh
+
+upload_openvpn:
+	rsync --rsh='ssh' -avztlpog --progress --partial ~/openvpn_build/sbin/openvpn* downloads.leap.se:./public/thirdparty/linux/openvpn/
+
+download_openvpn:
+	wget https://downloads.leap.se/thirdparty/linux/openvpn/openvpn
+
+clean_openvpn_build:
+	rm -rf ~/openvpn_build
diff --git a/branding/thirdparty/openvpn/build_openvpn.sh b/branding/thirdparty/openvpn/build_openvpn.sh
new file mode 100755
index 0000000000000000000000000000000000000000..20f764a229ca8ab0c473d7a78f6d1251d4f4b024
--- /dev/null
+++ b/branding/thirdparty/openvpn/build_openvpn.sh
@@ -0,0 +1,190 @@
+#!/bin/bash
+
+#############################################################################
+# Builds OpenVPN statically against mbedtls (aka polarssl).
+# Requirements:  cmake
+# Output: ~/openvpn_build/sbin/openvpn-x.y.z
+#############################################################################
+
+set -e
+#set -x
+
+# [!] This needs to be updated for every release --------------------------
+OPENVPN="openvpn-2.4.9"
+MBEDTLS="mbedtls-2.23.0"
+LZO="lzo-2.10"
+ZLIB="zlib-1.2.11"
+MBEDTLS_SHA512="c2a04f659bf63522f10f6660c2d196d7f39a057ff5a382734ba3b839f463ead4e5c9bc0d21fb909d56fcd2ee4c711248be14861f388cd383385484d364247634"
+LZO_SHA1="4924676a9bae5db58ef129dc1cebce3baa3c4b5d"
+# -------------------------------------------------------------------------
+
+platform='unknown'
+unamestr=`uname`
+if [[ "$unamestr" == 'Linux' ]]; then
+   platform='linux'
+elif [[ "$unamestr" == 'Darwin' ]]; then
+   platform='osx'
+fi
+
+BUILDDIR="openvpn_build"
+mkdir -p ~/$BUILDDIR && cd ~/$BUILDDIR
+
+BASE=`pwd`
+SRC=$BASE/src
+mkdir -p $SRC
+
+SHASUM="/usr/bin/shasum"
+
+ZLIB_KEYS="https://keys.gnupg.net/pks/lookup?op=get&search=0x783FCD8E58BCAFBA"
+OPENVPN_KEYS="https://swupdate.openvpn.net/community/keys/security.key.asc"
+
+WGET="wget --prefer-family=IPv4"
+DEST=$BASE/install
+LDFLAGS="-L$DEST/lib -L$DEST/usr/local/lib -W"
+CPPFLAGS="-I$DEST/include"
+CFLAGS="-D_FORTIFY_SOURCE=2 -O1 -Wformat -Wformat-security -fstack-protector -fPIE"
+CXXFLAGS=$CFLAGS
+CONFIGURE="./configure --prefix=/install"
+MAKE="make -j4"
+
+
+######## ####################################################################
+# ZLIB # ####################################################################
+######## ####################################################################
+
+function build_zlib()
+{
+        gpg --fetch-keys $ZLIB_KEYS
+	mkdir $SRC/zlib && cd $SRC/zlib
+
+	if [ ! -f $ZLIB.tar.gz ]; then
+	    $WGET https://zlib.net/$ZLIB.tar.gz
+	    $WGET https://zlib.net/$ZLIB.tar.gz.asc
+	fi
+	tar zxvf $ZLIB.tar.gz
+	cd $ZLIB
+
+	LDFLAGS=$LDFLAGS \
+	CPPFLAGS=$CPPFLAGS \
+	CFLAGS=$CFLAGS \
+	CXXFLAGS=$CXXFLAGS \
+	./configure \
+	--prefix=/install
+
+	$MAKE
+	make install DESTDIR=$BASE
+}
+
+########### ##################################################################
+# MBEDTLS # ##################################################################
+########### ##################################################################
+
+function build_mbedtls()
+{
+	mkdir -p $SRC/polarssl && cd $SRC/polarssl
+	if [ ! -f $MBEDTLS.tar.gz ]; then
+	    $WGET https://github.com/ARMmbed/mbedtls/archive/$MBEDTLS.tar.gz
+	fi
+	sha512=`${SHASUM} -a 512 -p ${MBEDTLS}.tar.gz | cut -d' ' -f 1`
+	
+	if [ "${MBEDTLS_SHA512}" = "${sha512}" ]; then
+	    echo "[+] sha1 verified ok"
+	else
+	    echo "[!] problem with sha1 verification"
+	    exit 1
+	fi
+	tar zxvf $MBEDTLS.tar.gz
+	cd mbedtls-$MBEDTLS
+	mkdir -p build
+	cd build
+	cmake ..
+	$MAKE
+	make install DESTDIR=$BASE/install
+}
+
+
+######## ####################################################################
+# LZO2 # ####################################################################
+######## ####################################################################
+
+function build_lzo2()
+{
+	mkdir $SRC/lzo2 && cd $SRC/lzo2
+	if [ ! -f $LZO.tar.gz ]; then
+	    $WGET http://www.oberhumer.com/opensource/lzo/download/$LZO.tar.gz
+	fi
+	sha1=`$SHASUM $LZO.tar.gz | cut -d' ' -f 1`
+	if [ "${LZO_SHA1}" = "${sha1}" ]; then
+	    echo "[+] sha1 verified ok"
+	else
+	    echo "[!] problem with sha1 verification"
+	    exit 1
+	fi
+	tar zxvf $LZO.tar.gz
+	cd $LZO
+
+	LDFLAGS=$LDFLAGS \
+	CPPFLAGS=$CPPFLAGS \
+	CFLAGS=$CFLAGS \
+	CXXFLAGS=$CXXFLAGS \
+	$CONFIGURE --enable-static --disable-debug
+
+	$MAKE
+	make install DESTDIR=$BASE
+}
+
+########### #################################################################
+# OPENVPN # #################################################################
+########### #################################################################
+
+function build_openvpn()
+{
+	mkdir $SRC/openvpn && cd $SRC/openvpn
+	gpg --fetch-keys $OPENVPN_KEYS
+	if [ ! -f $OPENVPN.tar.gz ]; then
+            $WGET https://build.openvpn.net/downloads/releases/$OPENVPN.tar.gz
+            $WGET https://build.openvpn.net/downloads/releases/$OPENVPN.tar.gz.asc
+	fi
+	gpg --verify $OPENVPN.tar.gz.asc && echo "[+] gpg verification ok"
+	tar zxvf $OPENVPN.tar.gz
+	cd $OPENVPN
+
+	MBEDTLS_CFLAGS=-I$BASE/install/usr/local/include/ \
+	MBEDTLS_LIBS="$DEST/usr/local/lib/libmbedtls.a $DEST/usr/local/lib/libmbedcrypto.a $DEST/usr/local/lib/libmbedx509.a" \
+	LDFLAGS=$LDFLAGS \
+	CPPFLAGS=$CPPFLAGS \
+	CFLAGS="$CFLAGS -I$BASE/install/usr/local/include" \
+	CXXFLAGS=$CXXFLAGS \
+	$CONFIGURE \
+	--disable-plugin-auth-pam \
+	--with-crypto-library=mbedtls \
+	--enable-small \
+	--disable-debug
+
+	$MAKE LIBS="-all-static -lz -llzo2"
+	make install DESTDIR=$BASE/openvpn
+	mkdir -p $BASE/sbin/
+	cp $BASE/openvpn/install/sbin/openvpn $BASE/sbin/$OPENVPN
+	strip $BASE/sbin/$OPENVPN
+}
+
+function build_all()
+{
+	echo "[+] Building" $OPENVPN
+	build_zlib
+	build_lzo2
+	build_mbedtls
+	build_openvpn
+}
+
+function main()
+{
+    if [[ $platform == 'linux' ]]; then
+      build_all
+    fi
+    if [[ $platform == 'osx' ]]; then
+      build_all
+    fi
+}
+
+main "$@"
diff --git a/gui/backend.go b/gui/backend.go
index 9453d88f860ba9b9e31e3806e181e6b9ceb3f8f4..f8ee2bdb5d92bf9fad2a9a1d1b185e59358dfb66 100644
--- a/gui/backend.go
+++ b/gui/backend.go
@@ -3,6 +3,7 @@ package main
 /* a wrapper around bitmask that exposes status to a QtQml gui.
    Have a look at the pkg/backend module for further enlightment. */
 
+// #cgo CXXFLAGS: -mmacosx-version-min=10.10
 import (
 	"C"
 	"unsafe"
diff --git a/gui/build.sh b/gui/build.sh
index 91be4fcdbc94febde7845c333d32b9c0d863f9cb..9c103419b71cfb00d0988ed81c52244ffef843a4 100755
--- a/gui/build.sh
+++ b/gui/build.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 set -e
-
+set -x
 
 XBUILD=${XBUILD-no}
 WIN64="win64"
@@ -30,6 +30,7 @@ else
     fi
 fi
 
+PLATFORM=`uname -s`
 
 function init {
     mkdir -p lib
@@ -38,10 +39,18 @@ function init {
 function buildGoLib {
     echo "[+] Using go in" $GO "[`go version`]"
     $GO generate ./pkg/config/version/genver/gen.go
+    if [ "$PLATFORM" == "Darwin" ]
+    then
+        OSX_TARGET=10.12
+        GOOS=darwin
+	CC=clang
+	CGO_CFLAGS="-g -O2 -mmacosx-version-min=$OSX_TARGET"
+	CGO_LDFLAGS="-g -O2 -mmacosx-version-min=$OSX_TARGET"
+    fi
     if [ "$XBUILD" == "no" ]
     then
         echo "[+] Building Go library with standard Go compiler"
-        CGO_ENABLED=1 go build -buildmode=c-archive -o $TARGET_GOLIB $SOURCE_GOLIB
+        CGO_ENABLED=1 GOOS=$GOOS CC=$CC CGO_CFLAGS=$CGO_CFLAGS CGO_LDFLAGS=$CGO_LDFLAGS go build -buildmode=c-archive -o $TARGET_GOLIB $SOURCE_GOLIB
     fi
     if [ "$XBUILD" == "$WIN64" ]
     then
diff --git a/gui/main.cpp b/gui/main.cpp
index a177e60f1c6c5066714ee66d1f5ed69857eae108..684b0be2fa2419c778961a0f6bdd351e4cf8e4cb 100644
--- a/gui/main.cpp
+++ b/gui/main.cpp
@@ -97,12 +97,6 @@ int main(int argc, char **argv) {
                 "main",
                 "Install helpers (linux only, requires sudo)."),
         },
-        {
-            {"v", "version"},
-            QApplication::translate(
-                "main",
-                "Version of the bitmask-vpn."),
-        },
         {
             {"o", "obfs4"},
             QApplication::translate(
diff --git a/installer/bitmask-installer.pro b/installer/bitmask-installer.pro
index 1435e4c690d1a209bcd4dcb7c5dfeb686834f2f8..49179c4602ea989a8836c463c788296e11642fef 100644
--- a/installer/bitmask-installer.pro
+++ b/installer/bitmask-installer.pro
@@ -22,6 +22,11 @@ macx {
     OTHER_FILES += "packages/riseupvpn/data/riseup-vpn.app"
     OTHER_FILES += "packages/riseupvpn/data/bitmask-helper"
     OTHER_FILES += "packages/riseupvpn/data/installer.py"
+    OTHER_FILES += "packages/riseupvpn/data/se.leap.bitmask-helper.plist"
+    OTHER_FILES += "packages/riseupvpn/data/openvpn.leap"
+    OTHER_FILES += "packages/riseupvpn/data/helper/bitmask.pf.conf"
+    OTHER_FILES += "packages/riseupvpn/data/client.up.sh"
+    OTHER_FILES += "packages/riseupvpn/data/client.down.sh"
 }
 linux {
     OTHER_FILES += "packages/riseupvpn/data/riseup-vpn"
diff --git a/installer/config/config.xml b/installer/config/config.xml
index ef0e5e8b95462d3f52a57f3ee53bf1d286c37880..492e76fb975b02256163cead4d06bf38d103f591 100644
--- a/installer/config/config.xml
+++ b/installer/config/config.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Installer>
     <Name>RiseupVPN Installer 1.0</Name>
+    <Publisher>LEAP Encryption Access Project</Publisher>
     <Title>RiseupVPN Installer</Title>
     <Version>1.0.0</Version>
     <TargetDir>@ApplicationsDir@/RiseupVPN</TargetDir>
@@ -9,4 +10,5 @@
             <Url>http://localhost/repository/</Url>
         </Repository>
     </RemoteRepositories>
+    <WizardStyle>mac</WizardStyle>
 </Installer>
diff --git a/installer/packages/riseupvpn/data/.gitignore b/installer/packages/riseupvpn/data/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..63c86a1bf9e3c0bb312cf18190e6d9b7a0a42f11
--- /dev/null
+++ b/installer/packages/riseupvpn/data/.gitignore
@@ -0,0 +1,3 @@
+openvpn.leap
+bitmask-helper
+riseup-vpn.app
diff --git a/installer/packages/riseupvpn/data/post-install.py b/installer/packages/riseupvpn/data/post-install.py
index 1e1addd62bc1722ef50815590d19ea8d7be890ea..02da859f2bccf43beba1d705fb2a13b0f28b4916 100755
--- a/installer/packages/riseupvpn/data/post-install.py
+++ b/installer/packages/riseupvpn/data/post-install.py
@@ -1,49 +1,49 @@
 #!/usr/bin/env python
 
 import os
+import shutil
 import sys
 import subprocess
 
 HELPER = "bitmask-helper"
 HELPER_PLIST = "/Library/LaunchDaemons/se.leap.bitmask-helper.plist"
+_dir = os.path.dirname(os.path.realpath(__file__))
 
 def main():
-    _dir = os.path.dirname(os.path.realpath(__file__))
     log = open(os.path.join(_dir, 'post-install.log'), 'w')
-    log.write('Checking for admin privileges...')
+    log.write('Checking for admin privileges...\n')
 
     _id = os.getuid()
     if _id != 0:
       err  = "error: need to run as root. UID: %s\n" % str(_id)
-      logErr(log, msg)
+      logErr(log, err)
     
     # failure: sys.exit(1)
     
     if isHelperRunning():
-        log.write("Trying to stop bitmask-helper...")
+        log.write("Trying to stop bitmask-helper...\n")
 	# if this fail, we can check if the HELPER_PLIST is there
         ok = unloadHelper()
         log.write("success: %s \n" % str(ok))
 
-    ok = makeHelperExecutable()
-    log.write("chmod +x helper: %s \n" % str(ok))
+    ok = fixHelperOwner(log)
+    log.write("chown helper: %s \n" % str(ok))
 
-    # 3. cp se.leap.bitmask-helper.plist /Library/LaunchDaemons/
+    log.write("Copy launch daemon...\n")
     copyLaunchDaemon()
 
-    # 4. launchctl load /Library/LaunchDaemons/se.leap.bitmask-helper.plist
-    launchHelper()
+    out = launchHelper()
+    log.write("Copy plist: %s \n" % str(ok))
 
-    # 5. chown admin:wheel /Applications/$applicationName.app/Contents/helper # is this the folder?
     grantPermissionsOnLogFolder()
     
-    # all good
-    log.write('post-install script: done')
+    # all done
+    log.write('post-install script: done\n')
     sys.exit(0)
 
 
 def logErr(log, msg):
-    log.write(err)
+    log.write(msg)
     sys.exit(1)
 
 def isHelperRunning():
@@ -54,18 +54,34 @@ def unloadHelper():
     out = subprocess.call(["launchctl", "unload", HELPER_PLIST])
     return out == 0
 
-def makeHelperExecutable():
-    out = subprocess.call(["chmod", "+x", HELPER])
-    return out == 0
+def fixHelperOwner(log):
+    path = os.path.join(_dir, HELPER)
+    try:
+        os.chown(path, 0, 0)
+    except OSError as exc:
+        log.write(str(exc))
+        return False
+    return True
 
 def copyLaunchDaemon():
-    pass
+    plist = "se.leap.bitmask-helper.plist"
+    path = os.path.join(_dir, plist)
+    dest = os.path.join('/Library/LaunchDaemons', plist)
+    _p = _dir.replace("/", "\/")
+    subprocess.call(["sed", "-i.back", "s/PATH/%s/" % _p, path])
+    shutil.copy(path, dest)
 
 def launchHelper():
-    pass
+    out = subprocess.call(["launchctl", "load", "/Library/LaunchDaemons/se.leap.bitmask-helper.plist"])
+    return out == 0
 
 def grantPermissionsOnLogFolder():
-    pass
+    helperDir = os.path.join(_dir, 'helper')
+    try:
+        os.makedirs(helperDir)
+    except Exception:
+        pass
+    os.chown(helperDir, 0, 0)
 
 def _getProcessList():
     _out = []
diff --git a/installer/packages/riseupvpn/data/se.leap.bitmask-helper.plist b/installer/packages/riseupvpn/data/se.leap.bitmask-helper.plist
new file mode 100644
index 0000000000000000000000000000000000000000..c9d968701af75ff0b5cc74b3f95ed4ae19e426df
--- /dev/null
+++ b/installer/packages/riseupvpn/data/se.leap.bitmask-helper.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>WorkingDirectory</key>
+	<string>/tmp</string>
+	<key>StandardOutPath</key>
+	<string>bitmask-helper.log</string>
+	<key>StandardErrorPath</key>
+	<string>bitmask-helper-err.log</string>
+	<key>GroupName</key>
+	<string>daemon</string>
+	<key>RunAtLoad</key>
+	<true/>
+	<key>SessionCreate</key>
+	<true/>
+	<key>KeepAlive</key>
+    <true/>
+    <key>ThrottleInterval</key>
+    <integer>5</integer>
+    <key>Label</key>
+	<string>se.leap.BitmaskHelper</string>
+	<key>Program</key>
+    <string>PATH/bitmask-helper</string>
+</dict>
+</plist>
diff --git a/pkg/helper/args.go b/pkg/helper/args.go
index 1a5bd3b5e2edd909899a2e264ec8092bdeb550a8..5a7873fe396ad400fcd6001019c7add1872b49eb 100644
--- a/pkg/helper/args.go
+++ b/pkg/helper/args.go
@@ -6,6 +6,7 @@ import (
 	"os"
 	"regexp"
 	"strconv"
+	"path/filepath"
 )
 
 const (
@@ -22,11 +23,11 @@ var (
 		"--tls-client",
 		"--remote-cert-tls", "server",
 		"--dhcp-option", "DNS", nameserver,
-		"--log", LogFolder + "openvpn.log",
 		"--tls-version-min", "1.0",
+		"--log", filepath.Join(LogFolder, "openvpn-leap.log"),
 	}
 
-	allowendArgs = map[string][]string{
+	allowedArgs = map[string][]string{
 		"--remote":            []string{"IP", "NUMBER", "PROTO"},
 		"--tls-cipher":        []string{"CIPHER"},
 		"--cipher":            []string{"CIPHER"},
@@ -44,7 +45,7 @@ var (
 
 	cipher  = regexp.MustCompile("^[A-Z0-9-]+$")
 	formats = map[string]func(s string) bool{
-		"NUMBER": isNumber,
+			"NUMBER": isNumber,
 		"PROTO":  isProto,
 		"IP":     isIP,
 		"CIPHER": cipher.MatchString,
@@ -54,9 +55,9 @@ var (
 
 func parseOpenvpnArgs(args []string) []string {
 	newArgs := fixedArgs
-	newArgs = append(newArgs, platformOpenvpnFlags...)
+	newArgs = append(newArgs, getPlatformOpenvpnFlags()...)
 	for i := 0; i < len(args); i++ {
-		params, ok := allowendArgs[args[i]]
+		params, ok := allowedArgs[args[i]]
 		if !ok {
 			log.Printf("Invalid openvpn arg: %s", args[i])
 			continue
diff --git a/pkg/helper/darwin.go b/pkg/helper/darwin.go
index 82becee172951046b0ab72afe48414966b917e6a..ae4264615f15aae0316118b81a7351762b0bd7e6 100644
--- a/pkg/helper/darwin.go
+++ b/pkg/helper/darwin.go
@@ -1,5 +1,5 @@
 // +build darwin
-// Copyright (C) 2018 LEAP
+// Copyright (C) 2018-2020 LEAP
 //
 // This program is free software: you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
@@ -29,6 +29,7 @@ package helper
 import (
 	"errors"
 	"fmt"
+	"path/filepath"
 	"log"
 	"os"
 	"os/exec"
@@ -36,30 +37,39 @@ import (
 	"strconv"
 	"strings"
 
-	"0xacab.org/leap/bitmask-vpn/pkg/config"
 	"github.com/sevlyar/go-daemon"
 )
 
 const (
-	appPath     = "/Applications/" + config.ApplicationName + ".app/"
-	helperPath  = appPath + "Contents/helper/"
-	LogFolder   = helperPath
-	openvpnPath = appPath + "Contents/Resources/openvpn.leap"
-
-	rulefilePath   = helperPath + "bitmask.pf.conf"
 	bitmask_anchor = "com.apple/250.BitmaskFirewall"
 	gateways_table = "bitmask_gateways"
-
 	pfctl = "/sbin/pfctl"
+	LogFolder = "/var/log/"
 )
 
-var (
-	platformOpenvpnFlags = []string{
+func _getExecPath() string {
+	ex, err := os.Executable()
+	if err != nil {
+		log.Print("error while getting executable path!")
+	}
+	return filepath.Dir(ex)
+}
+
+func getHelperPath() string {
+	execPath := _getExecPath()
+	hp := filepath.Join(execPath, "../../../", "bitmask-helper")
+	log.Println(">>> DEBUG: helper", hp)
+	return hp
+}
+
+func getPlatformOpenvpnFlags() []string {
+	helperPath := getHelperPath()
+	return []string{
 		"--script-security", "2",
 		"--up", helperPath + "client.up.sh",
 		"--down", helperPath + "client.down.sh",
 	}
-)
+}
 
 func parseCliArgs() {
 	// OSX helper does not respond to arguments
@@ -97,6 +107,9 @@ func runServer(preferredPort int) {
 }
 
 func getOpenvpnPath() string {
+	execPath := _getExecPath()
+	openvpnPath := filepath.Join(execPath, "../../../", "openvpn.leap")
+	log.Println(">>> DEBUG: openvpn", openvpnPath)
 	return openvpnPath
 }
 
@@ -190,6 +203,9 @@ func loadBitmaskAnchor() error {
 }
 
 func getRulefilePath() (string, error) {
+	rulefilePath := filepath.Join(getHelperPath(), "helper", "bitmask.pf.conf")
+	log.Println("DEBUG: rule file path", rulefilePath)
+
 	if _, err := os.Stat(rulefilePath); !os.IsNotExist(err) {
 		return rulefilePath, nil
 	}
diff --git a/pkg/helper/linux.go b/pkg/helper/linux.go
index f1e21c808a9f5a6f1649c32892b90589f8db8aa1..d6f30f2f4a7976759ed4e47d2cbd80e5a2eaf1d4 100644
--- a/pkg/helper/linux.go
+++ b/pkg/helper/linux.go
@@ -1,5 +1,5 @@
 // +build linux
-// Copyright (C) 2018 LEAP
+// Copyright (C) 2018, 2020 LEAP
 //
 // This program is free software: you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
@@ -34,12 +34,15 @@ const (
 
 var (
 	snapOpenvpnPath      = "/snap/bin/" + config.BinaryName + ".openvpn"
-	platformOpenvpnFlags = []string{
+)
+
+func getPlatformOpenvpnFlags() []string {
+	return []string{
 		"--script-security", "1",
 		"--user", openvpnUser,
 		"--group", openvpnGroup,
 	}
-)
+}
 
 func parseCliArgs() {
 	// linux helper does not reply to args
diff --git a/pkg/helper/windows.go b/pkg/helper/windows.go
index 44ac6f50fc53c85d91a5dfab19ea954fdccdfbd6..c33a4bc98f84b9847b024346e99848a9845ed794 100644
--- a/pkg/helper/windows.go
+++ b/pkg/helper/windows.go
@@ -40,11 +40,15 @@ var (
 	openvpnPath      = path.Join(appPath, "openvpn.exe")
 	chocoOpenvpnPath = `C:\Program Files\OpenVPN\bin\openvpn.exe`
 	platformOpenvpnFlags = []string{
+	httpServerConf = &httpConf{}
+)
+
+func getPlatformOpenvpnFlags() []string {
+	return []string{
 		"--script-security", "1",
 		"--block-outside-dns",
 	}
-	httpServerConf = &httpConf{}
-)
+}
 
 func getExecDir() string {
 	ex, err := os.Executable()