diff --git a/.gitignore b/.gitignore
index a939dce30324c1f8dc1b16110f678177057a4637..d1be8c7e288e1154a8d1eafd9306c892832f547a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,4 +16,6 @@ _deps
 _plugins
 _tdeps
 logs
-_build
\ No newline at end of file
+_build
+rebar3
+rebar.lock
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..94888404a044597a76d1a749e2c9bce9e64573c6
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,67 @@
+before_script:
+  - rebar3 update
+
+stages:
+  - compile
+  - test
+  - publish
+  - docker
+
+compile:
+  stage: compile
+  script:
+    - rebar3 as production do compile
+
+test:
+  stage: test
+  script:
+    - ERL_AFLAGS="-args_file config/test-vm.args -config config/test-sys.config" rebar3 as test do eunit --cover --application=consul-proxy --dir=apps/consul-proxy/test, cover --verbose
+    - coverage.escript _build/test/cover/eunit.coverdata
+
+publish_hex:
+  stage: publish
+  only:
+    - /^\d+[.]\d+[.]\d+$/ # Only publish HEAD tagged with semantic version
+  script:
+    - mkdir -p ~/.hex && printf "{key,<<\"$HEX_KEY\">>}.\n{username,<<\"$HEX_USERNAME\">>}.\n" > ~/.hex/hex.config
+    - mkdir -p ~/.config/rebar3 && printf "{plugins, [rebar3_hex]}.\n" > ~/.config/rebar3/rebar.config
+    - echo "Y" | rebar3 hex publish
+
+publish_aws:
+  stage: publish
+  only:
+    - /^\d+[.]\d+[.]\d+$/ # Only publish HEAD tagged with semantic version
+  script:
+    - rebar3 edoc
+    - aws s3 cp doc s3://s3.erlang.ninja/consul-proxy/$CI_BUILD_REF_NAME/ --recursive
+    - rebar3 as production do tar
+    - aws s3 cp _build/production/rel/consul-proxy/consul-proxy-$CI_BUILD_REF_NAME.tar.gz s3://s3.erlang.ninja/consul-proxy/
+    - aws s3 cp s3://s3.erlang.ninja/consul-proxy/consul-proxy-$CI_BUILD_REF_NAME.tar.gz s3://s3.erlang.ninja/consul-proxy/consul-proxy-latest.tar.gz
+
+docker_x86:
+  stage: docker
+  only:
+    - master # Only master branch
+  script:
+    - rebar3 as production do release
+    - PLATFORM=x86 envsubst '$PLATFORM' < apps/consul-proxy/priv/Dockerfile > _build/production/Dockerfile
+    - docker build --no-cache=true -t ehedenst/consul-proxy:x86 -f _build/production/Dockerfile _build/production
+    - if [ ! -f ~/.docker/config.json ]; then docker login --username=$DOCKER_HUB_USERNAME --password=$DOCKER_HUB_PASSWORD --email=$DOCKER_HUB_EMAIL; fi
+    - docker push ehedenst/consul-proxy:x86
+  tags:
+    - docker
+    - x86_64
+
+docker_arm:
+  stage: docker
+  only:
+    - master # Only master branch
+  script:
+    - rebar3 as production do release
+    - PLATFORM=arm envsubst '$PLATFORM' < apps/consul-proxy/priv/Dockerfile > _build/production/Dockerfile
+    - docker build --no-cache=true -t ehedenst/consul-proxy:arm -f _build/production/Dockerfile _build/production
+    - if [ ! -f ~/.docker/config.json ]; then docker login --username=$DOCKER_HUB_USERNAME --password=$DOCKER_HUB_PASSWORD --email=$DOCKER_HUB_EMAIL; fi
+    - docker push ehedenst/consul-proxy:arm
+  tags:
+    - docker
+    - armv7l
diff --git a/LICENSE b/LICENSE
index 4f8d9dc730b913b6c12b6dafec7ad745971f1bea..2bf1f48e24b43b6f402f1b1e5a8b7753ef827585 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,29 +1,21 @@
-Copyright (c) 2016, Erik Hedenström <erik@hedenstroem.com>.
-All rights reserved.
+The MIT License (MIT)
 
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
+Copyright (c) 2016 Erik Hedenström <erik@democra.se>
 
-* Redistributions of source code must retain the above copyright
-  notice, this list of conditions and the following disclaimer.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
 
-* Redistributions in binary form must reproduce the above copyright
-  notice, this list of conditions and the following disclaimer in the
-  documentation and/or other materials provided with the distribution.
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
 
-* The names of its contributors may not be used to endorse or promote
-  products derived from this software without specific prior written
-  permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..6670b4488752aacd34e50718ad0f27cf1479e790
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,38 @@
+REBAR_VERSION := $(shell rebar3 --version 2>/dev/null)
+ifdef REBAR_VERSION
+REBAR := rebar3
+else
+REBAR := $(CURDIR)/rebar3
+$(shell if ! [ -e "$(REBAR)" ]; then curl -jksSL -o $(REBAR) https://s3.amazonaws.com/rebar3/rebar3; chmod +x $(REBAR); fi)
+endif
+
+all: eunit
+
+compile:
+	@$(REBAR) compile
+
+eunit:
+	@ERL_AFLAGS="-args_file config/test-vm.args -config config/test-sys.config" $(REBAR) as test do eunit --cover --application=consul-proxy --dir=apps/consul-proxy/test, cover --verbose
+
+dialyzer:
+	@$(REBAR) dialyzer
+
+release:
+	@$(REBAR) release
+
+image:
+	@$(REBAR) release -d false
+	PLATFORM=x86 envsubst '$$PLATFORM' < apps/consul-proxy/priv/Dockerfile > _build/default/Dockerfile
+	docker build --no-cache=true -t ehedenst/consul-proxy:x86 -f _build/default/Dockerfile _build/default
+
+edoc:
+	@$(REBAR) edoc
+
+clean:
+	@$(REBAR) clean
+
+distclean:
+	@rm -rf _build rebar.lock log $(REBAR)
+
+shell:
+	@$(REBAR) shell --config=config/test-sys.config
diff --git a/apps/consul-proxy/include/consul-proxy.hrl b/apps/consul-proxy/include/consul-proxy.hrl
new file mode 100644
index 0000000000000000000000000000000000000000..7a96c87001a1a2b5332a62b5b18b3f45f405a4a7
--- /dev/null
+++ b/apps/consul-proxy/include/consul-proxy.hrl
@@ -0,0 +1 @@
+-define(APPLICATION, 'consul-proxy').
diff --git a/apps/consul-proxy/priv/Dockerfile b/apps/consul-proxy/priv/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..3692242fa7733fd8a7b4c35f0bc532e297255b86
--- /dev/null
+++ b/apps/consul-proxy/priv/Dockerfile
@@ -0,0 +1,20 @@
+FROM        ehedenst/erlang:${PLATFORM}
+MAINTAINER  Erik Hedenström <erik@hedenstroem.com>
+
+ENV NAME_PREFIX consul-proxy
+ENV COOKIE Nax7jEj7bay6ril
+
+RUN apk --update add \
+    erlang-inets=$ERLANG_VERSION \
+    erlang-ssl=$ERLANG_VERSION \
+    erlang-asn1=$ERLANG_VERSION \
+    erlang-observer=$ERLANG_VERSION \
+    erlang-public-key=$ERLANG_VERSION && \
+    rm -rf /var/cache/apk/*
+
+COPY rel/consul-proxy /opt/consul-proxy
+
+EXPOSE 80 443
+
+ENTRYPOINT [ "/opt/consul-proxy/bin/consul-proxy-wrapper" ]
+CMD [ "foreground" ]
diff --git a/apps/consul-proxy/priv/consul-proxy-wrapper b/apps/consul-proxy/priv/consul-proxy-wrapper
new file mode 100755
index 0000000000000000000000000000000000000000..41733518d2e9a0b449c68da0004f7a962a7f336f
--- /dev/null
+++ b/apps/consul-proxy/priv/consul-proxy-wrapper
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+set -e
+
+SCRIPT=$(readlink $0 || true)
+if [ -z $SCRIPT ]; then
+    SCRIPT=$0
+fi;
+SCRIPT_DIR="$(cd `dirname "$SCRIPT"` && pwd -P)"
+
+if [ -z "$NAME_PREFIX" ]; then
+    NAME_PREFIX="consul-proxy-$(openssl rand -hex 4)"
+fi
+
+if [ -z "$COOKIE" ]; then
+    export COOKIE=$(openssl rand -hex 16)
+fi
+
+if [ -z "$HOST_IP" ]; then
+    HOST_IP=$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p' | head -n 1)
+fi
+
+export RELX_REPLACE_OS_VARS=true
+export NODE_NAME=${NAME_PREFIX}@${HOST_IP}
+
+echo "Starting ${NODE_NAME} with cookie ${COOKIE}"
+
+${SCRIPT_DIR}/consul-proxy $@
diff --git a/apps/consul-proxy/src/consul-proxy.app.src b/apps/consul-proxy/src/consul-proxy.app.src
index 928a0473bee2228a1096ec1d1f9386048917e6cb..865972d765cc3d5f1315f8f123d122a5b85604df 100644
--- a/apps/consul-proxy/src/consul-proxy.app.src
+++ b/apps/consul-proxy/src/consul-proxy.app.src
@@ -1,16 +1,20 @@
-{application, 'consul-proxy',
- [{description, "An OTP application"},
-  {vsn, "0.1.0"},
-  {registered, []},
-  {mod, {'consul-proxy_app', []}},
-  {applications,
-   [kernel,
-    stdlib
-   ]},
-  {env,[]},
-  {modules, []},
-
-  {contributors, []},
-  {licenses, []},
-  {links, []}
- ]}.
+{application, 'consul-proxy', [
+    {description, "Proxy for docker swarm using consul and vegur"},
+    {vsn, "0.1.0"},
+    {registered, []},
+    {mod, {'consul-proxy_app', []}},
+    {applications, [
+        kernel,
+        stdlib,
+        sasl,
+        inets,
+        lager,
+        tsuru
+    ]},
+    {env, []},
+    {modules, []},
+    {maintainers, ["Erik Hedenstrom"]},
+    {contributors, []},
+    {licenses, ["MIT"]},
+    {links, [{"GitLab", "https://gitlab.hedenstroem.com/erlang-ninja/consul-proxy"}]}
+]}.
diff --git a/apps/consul-proxy/src/consul-proxy_app.erl b/apps/consul-proxy/src/consul-proxy_app.erl
index af8717e63d7e262716e4d4dc833f2b873df16baf..c4d65d5202da3be2898155f30b1a45c7b6ab2446 100644
--- a/apps/consul-proxy/src/consul-proxy_app.erl
+++ b/apps/consul-proxy/src/consul-proxy_app.erl
@@ -15,8 +15,9 @@
 %% API
 %%====================================================================
 
-start(_StartType, _StartArgs) ->
-    'consul-proxy_sup':start_link().
+start(_StartType, StartArgs) ->
+    tsuru_application:set_env('consul-proxy'),
+    'consul-proxy_sup':start_link(StartArgs).
 
 %%--------------------------------------------------------------------
 stop(_State) ->
diff --git a/apps/consul-proxy/src/consul-proxy_sup.erl b/apps/consul-proxy/src/consul-proxy_sup.erl
index 5310530fc4b11203b361dd1ac8117358b4691d9e..afdf97b55bdd3800ed77cfad2688bc164e55b378 100644
--- a/apps/consul-proxy/src/consul-proxy_sup.erl
+++ b/apps/consul-proxy/src/consul-proxy_sup.erl
@@ -8,7 +8,7 @@
 -behaviour(supervisor).
 
 %% API
--export([start_link/0]).
+-export([start_link/1]).
 
 %% Supervisor callbacks
 -export([init/1]).
@@ -19,16 +19,23 @@
 %% API functions
 %%====================================================================
 
-start_link() ->
-    supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+start_link(Args) ->
+    supervisor:start_link({local, ?SERVER}, ?MODULE, Args).
 
 %%====================================================================
 %% Supervisor callbacks
 %%====================================================================
 
 %% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules}
-init([]) ->
-    {ok, { {one_for_all, 0, 1}, []} }.
+init(_Args) ->
+
+    SupFlags = #{
+        strategy => one_for_one,
+        intensity => 10,
+        period => 10
+    },
+
+    {ok, {SupFlags, []}}.
 
 %%====================================================================
 %% Internal functions
diff --git a/apps/consul-proxy/test/features_test.erl b/apps/consul-proxy/test/features_test.erl
new file mode 100644
index 0000000000000000000000000000000000000000..457c303c3b4c07f7790e0a968e74b8abae97ef96
--- /dev/null
+++ b/apps/consul-proxy/test/features_test.erl
@@ -0,0 +1,16 @@
+-module(features_test).
+
+-include_lib("eunit/include/eunit.hrl").
+
+features_test_() ->
+    setup(),
+    Features = fun() ->
+        filelib:fold_files("features", ".*[.]feature", true, fun(File, Files) -> [File | Files] end, [])
+               end,
+    gurka_eunit:setup(Features, fun teardown/1).
+
+setup() ->
+    lager:start().
+
+teardown(_) ->
+    ok.
diff --git a/config/sys.config b/config/sys.config
index 266026b2d3e465bf9e3f29b10a2715d93f16c381..b590738204facf8cb7c8126e6f01a8eadd79b1aa 100644
--- a/config/sys.config
+++ b/config/sys.config
@@ -1,3 +1,31 @@
 [
-  {'consul-proxy', []}
+    {kernel, [
+        {start_timer, true},
+        {inet_default_listen_options, [{nodelay, true}, {sndbuf, 32768}, {recbuf, 32768}]},
+        {inet_default_connect_options, [{delay_send, true}]}
+    ]},
+    {sasl, [
+        {sasl_error_logger, {file, "log/sasl-error.log"}},
+        {errlog_type, error},
+        {error_logger_mf_dir, "log/sasl"},
+        {error_logger_mf_maxbytes, 10485760},
+        {error_logger_mf_maxfiles, 5},
+        {utc_log, true}
+    ]},
+    {lager, [
+        {colored, true},
+        {handlers, [
+            {lager_console_backend, [info, {lager_default_formatter, [color, time, " {", {module, "?"}, ":", {line, "?"}, "} ", pid, " [", severity, "] ", message, "\n"]}]},
+            {lager_file_backend, [{file, "log/error.log"}, {level, error}, {size, 10485760}, {date, "$D0"}, {count, 5}]},
+            {lager_file_backend, [{file, "log/console.log"}, {level, info}, {size, 10485760}, {date, "$D0"}, {count, 5}]}
+        ]},
+        {crash_log, "log/crash.log"},
+        {crash_log_msg_size, 65536},
+        {crash_log_size, 10485760},
+        {crash_log_date, "$D0"},
+        {crash_log_count, 5},
+        {error_logger_redirect, true}
+    ]},
+    {'consul-proxy', [
+    ]}
 ].
diff --git a/config/test-sys.config b/config/test-sys.config
new file mode 100644
index 0000000000000000000000000000000000000000..ab6277330b299b69ca9793606bc2ee50f543e7ee
--- /dev/null
+++ b/config/test-sys.config
@@ -0,0 +1,29 @@
+[
+    {kernel, [
+        {start_timer, true},
+        {inet_default_listen_options, [{nodelay, true}, {sndbuf, 32768}, {recbuf, 32768}]},
+        {inet_default_connect_options, [{delay_send, true}]}
+    ]},
+    {sasl, [
+        {sasl_error_logger, {file, "log/sasl-error.log"}},
+        {errlog_type, error},
+        {error_logger_mf_dir, "log/sasl"},
+        {error_logger_mf_maxbytes, 10485760},
+        {error_logger_mf_maxfiles, 5},
+        {utc_log, true}
+    ]},
+    {lager, [
+        {colored, true},
+        {handlers, [
+            {lager_console_backend, [debug, {lager_default_formatter, [color, time, " {", {module, "?"}, ":", {line, "?"}, "} ", pid, " [", severity, "] ", message, "\n"]}]}
+        ]},
+        {crash_log, "log/crash.log"},
+        {crash_log_msg_size, 65536},
+        {crash_log_size, 10485760},
+        {crash_log_date, "$D0"},
+        {crash_log_count, 5},
+        {error_logger_redirect, true}
+    ]},
+    {'consul-proxy', [
+    ]}
+].
diff --git a/config/test-vm.args b/config/test-vm.args
new file mode 100644
index 0000000000000000000000000000000000000000..dbfc87f76dcdccd0f0a4b4eef49fa89730494eb4
--- /dev/null
+++ b/config/test-vm.args
@@ -0,0 +1,19 @@
+## Name of the node
+-name consul-proxy@127.0.01
+
+## Cookie for distributed erlang
+-setcookie Nax7jEj7bay6ril
+
+## Enable kernel poll and a few async threads
++K true
++A 64
++P 262144
+
+## enable smp support
+-smp auto
+
+## Increase number of concurrent ports/sockets
+-env ERL_MAX_PORTS 16384
+
+## Tweak GC to run more often
+-env ERL_FULLSWEEP_AFTER 10
diff --git a/config/vm.args b/config/vm.args
index 7f923d12449eeff68be47cdbf396b46643896836..3394a1a741197be045d0245e96af91904da9eff3 100644
--- a/config/vm.args
+++ b/config/vm.args
@@ -1,6 +1,19 @@
--sname consul-proxy
+## Name of the node
+-name ${NODE_NAME}
 
--setcookie consul-proxy_cookie
+## Cookie for distributed erlang
+-setcookie ${COOKIE}
 
+## Enable kernel poll and a few async threads
 +K true
-+A30
++A 64
++P 262144
+
+## enable smp support
+-smp auto
+
+## Increase number of concurrent ports/sockets
+-env ERL_MAX_PORTS 16384
+
+## Tweak GC to run more often
+-env ERL_FULLSWEEP_AFTER 10
diff --git a/rebar.config b/rebar.config
index dee631fe2118b7ab8a04f1ed50ea57eece022a68..506cd390c4628d578675fbe4a63a883b3ee05cee 100644
--- a/rebar.config
+++ b/rebar.config
@@ -1,20 +1,39 @@
-{erl_opts, [debug_info]}.
-{deps, []}.
+{erl_opts, [{parse_transform, lager_transform}]}.
 
-{relx, [{release, {'consul-proxy', "0.1.0"},
-         ['consul-proxy',
-          sasl]},
+{eunit_opts, [{report, {eunit_surefire, [{dir, "_build/test"}]}}]}.
 
-        {sys_config, "./config/sys.config"},
-        {vm_args, "./config/vm.args"},
+{edoc_opts, []}.
 
-        {dev_mode, true},
-        {include_erts, false},
+{deps, [
+    {lager, "3.0.2"},
+    {tsuru, "1.0.2"},
+    {vegur, {git, "https://github.com/heroku/vegur.git", {branch, "master"}}}
+]}.
 
-        {extended_start_script, true}]
-}.
+{relx, [
+    {release, {'consul-proxy', "0.1.0"}, ['consul-proxy']},
+    {sys_config, "./config/sys.config"},
+    {vm_args, "./config/vm.args"},
+    {dev_mode, true},
+    {include_erts, false},
+    {extended_start_script, true},
+    {overlay, [
+        {copy, "apps/consul-proxy/priv/consul-proxy-wrapper", "bin/consul-proxy-wrapper"}
+    ]}
+]}.
 
-{profiles, [{prod, [{relx, [{dev_mode, false},
-                            {include_erts, true}]}]
-            }]
-}.
+{profiles, [
+    {test, [
+        {deps, [
+            {gurka, "0.1.3"}
+        ]},
+        {erl_opts, [debug_info, nowarn_unused_vars]}
+    ]},
+    {prod, [
+        {relx, [
+            {dev_mode, false},
+            {include_erts, false}
+        ]},
+        {erl_opts, [no_debug_info, warnings_as_errors]}
+    ]}
+]}.