diff --git a/docker-compose.yml b/docker-compose.yml
index 3df763f40..25d62b4fb 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,45 +1,39 @@
-version: '3'
+version: "3"
 
 services:
-  postgres:
-    container_name: mobilizon_db
-    restart: unless-stopped
-    image: mdillon/postgis:11
+  mobilizon:
+    image: mobilizon
     environment:
-      POSTGRES_PASSWORD: postgres
-      POSTGRES_DB: mobilizon_dev
+      - MOBILIZON_INSTANCE_NAME
+      - MOBILIZON_INSTANCE_HOST
+      - MOBILIZON_INSTANCE_EMAIL
+      - MOBILIZON_REPLY_EMAIL
+      - MOBILIZON_INSTANCE_REGISTRATIONS_OPEN=true
+      - MOBILIZON_DATABASE_USERNAME=${POSTGRES_USER}
+      - MOBILIZON_DATABASE_PASSWORD=${POSTGRES_PASSWORD}
+      - MOBILIZON_DATABASE_DBNAME=${POSTGRES_DB}
+      - MOBILIZON_DATABASE_HOST=db
+      - MOBILIZON_INSTANCE_SECRET_KEY_BASE
+      - MOBILIZON_INSTANCE_SECRET_KEY
+      - MOBILIZON_SMTP_SERVER=yoursmtpserver
+      - MOBILIZON_SMTP_HOSTNAME=your.smtp.domain
+      - MOBILIZON_SMTP_USERNAME
+      - MOBILIZON_SMTP_PASSWORD
     volumes:
-      - pgdata:/var/lib/postgresql/data
-  api:
-    container_name: mobilizon_api
-    restart: unless-stopped
-    build: .
-    volumes:
-      - '.:/app'
+      - /tmp/public/upload:/app/upload
     ports:
-      - "4000:4000"
-    depends_on:
-      - postgres
+     - "4000:4000"
+
+  db:
+    image: postgis/postgis
+    volumes:
+      - /tmp/db:/var/lib/postgresql/data
     environment:
-      MIX_ENV: "dev"
-      DOCKER: "true"
-      MOBILIZON_INSTANCE_NAME: My Mobilizon Instance
-      MOBILIZON_INSTANCE_HOST: mobilizon.me
-      MOBILIZON_INSTANCE_EMAIL: noreply@mobilizon.me
-      MOBILIZON_INSTANCE_REGISTRATIONS_OPEN: "true"
-      MOBILIZON_DATABASE_PASSWORD: postgres
-      MOBILIZON_DATABASE_USERNAME: postgres
-      MOBILIZON_DATABASE_DBNAME: mobilizon_dev
-      MOBILIZON_DATABASE_HOST: postgres
-    command: >
-      sh -c "cd js &&
-      yarn install &&
-      cd ../ &&
-      mix deps.get &&
-      mix compile &&
-      mix ecto.create &&
-      mix ecto.migrate &&
-      mix phx.server"
-volumes:
-  pgdata:
-  .:
+      - POSTGRES_USER
+      - POSTGRES_PASSWORD
+      - POSTGRES_DB
+
+networks:
+  default:
+    ipam:
+      driver: default
diff --git a/docker/production/Dockerfile b/docker/production/Dockerfile
index 259efd41d..71abc377b 100644
--- a/docker/production/Dockerfile
+++ b/docker/production/Dockerfile
@@ -1,62 +1,41 @@
-FROM elixir:slim
+# First build the application assets
+FROM node:alpine as assets
 
-# Install dependencies, NodeJS, YARN & clean apt
-RUN apt update \
- && apt -y dist-upgrade \
- && apt -y install build-essential \
-  curl \
-  wget \
-  unzip \
-  vim \
-  openssl \
-  git \
-  cmake \
-  imagemagick \
-  webp \
-  gifsicle \
-  jpegoptim \
-  optipng  \
-  pngquant \
-  postgresql-client \
- && curl -sL https://deb.nodesource.com/setup_12.x | bash - \
- && apt -y install nodejs \
- && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
- && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
- && apt -y update && apt -y install yarn \
- && apt -y clean \
- && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+RUN apk add --no-cache python build-base
 
-# Add mobilizon user
-RUN groupadd -r mobilizon \
-    && useradd -r -g mobilizon -m mobilizon
+COPY js .
+RUN yarn install \
+ && yarn run build
 
-USER mobilizon
+# Then, build the application binary
+FROM elixir:alpine AS builder
 
-# ENV
+RUN apk add --no-cache build-base git cmake
+
+COPY mix.exs mix.lock ./
 ENV MIX_ENV=prod
+RUN mix local.hex --force \
+ && mix local.rebar --force \
+ && mix deps.get
 
-# PORT
+COPY lib ./lib
+COPY priv ./priv
+COPY config ./config
+COPY docker/production/releases.exs ./config/
+COPY --from=assets ./priv/static ./priv/static
+
+RUN mix phx.digest \
+ && mix release
+
+# Finally setup the app
+FROM alpine
+
+RUN apk add --no-cache openssl ncurses-libs
+
+USER nobody
 EXPOSE 4000
 
-# Copy repo
-COPY . /app
-WORKDIR /app
+COPY --from=builder --chown=nobody:nobody _build/prod/rel/mobilizon ./
 
-# Compile dependencies, Mobilizon and build front-end
-RUN mix local.hex --force && mix local.rebar --force \
- && HEX_HTTP_CONCURRENCY=4 HEX_HTTP_TIMEOUT=60 mix do deps.get, compile \
- && cd js && NODE_BUILD_MEMORY=2024 yarn install && NODE_BUILD_MEMORY=2024 yarn run build \
- # free space
- && rm -rf js doc deps docs support \
- && rm -rf /home/mobilizon/.cache/* \
- # copy config secret env based file
- && cp docker/production/prod.secret config/ \
- # set start script mod
- && chmod +x /app/docker/production/start.sh
-
-CMD /app/docker/production/start.sh
-
-## start.sh:
-# !/bin/bash
-# mix ecto.migrate
-# mix phx.server
+ENTRYPOINT ["/bin/mobilizon"]
+CMD ["start"]
diff --git a/docker/production/README.md b/docker/production/README.md
index 6b9c9c87c..68055e518 100644
--- a/docker/production/README.md
+++ b/docker/production/README.md
@@ -2,49 +2,54 @@
 
 You will need to :
 - build the image
-- adapte env file
-- run docker-compose
+- tune the environment file
+- use docker-compose to run the service
 
 ## Build the image
 
-    docker build -t mymobilizon -f docker/prod/Dockerfile .
+    git clone https://forge.tedomum.net/tedomum/mobilizon
+    cd mobilizon
+    docker build -t mobilizon -f docker/production/Dockerfile .
 
-## Adapt env file
+## Update the env file
 
-    cp env .env
+    cd docker/production/
+    cp env.example .env
 
-- Edit .env content with your params.
-- Edit docker-compose file with your params (environment section for mobilizon & posgres).
+Edit the `.env` content with your own settings.
 
 You can generate `MOBILIZON_INSTANCE_SECRET_KEY_BASE` and `MOBILIZON_INSTANCE_SECRET_KEY` with:
 
     gpg --gen-random --armor 1 50
 
-## run docker-compose
+## Run the service
 
-    docker-compose -f docker-compose-simple.yml up
-    # set user for volumes
-    sudo chown 999:999 db public wal public/upload
-    # in another shell
-    docker-compose -f docker-compose-simple.yml exec -u 0 mobilizon bash
-    su - mobilizon
-    # backup secret
-    mv config/prod.secret.exs config/prod.secret.exs.env
-    # run config generation
-    MIX_ENV=prod mix mobilizon.instance gen -f
-    # reply anything (not used after) except for :
-    # - What is the name of your database? [mobilizon_prod]
-    # - What is the user used to connect to your database? [mobilizon] 
-    # - What is the password used to connect to your database? [autogenerated]
-    # get secret env based bak
-    mv config/prod.secret.exs.env config/prod.secret.exs 
-    # run the db init script as root
-    exit
-    psql -U postgres -p 5432 -h postgres -f setup_db.psql
-    # delete db init sript
-    rm setup_db.psql
-    # create an admin with mobilizon user
-    su - mobilizon
-    cd /app
-    MIX_ENV=prod mix mobilizon.users.new pascoual@tedomum.fr --password mobilizon
-    # exit with ctrl+d (twice times)
+Start by initializing and running the database:
+
+    docker-compose up -d db
+
+Instanciate required Postgres extensions:
+
+    docker-compose exec db psql -U <username>
+    # CREATE EXTENSION pg_trgm;
+    # CREATE EXTENSION unaccent;
+
+
+Then run migrations:
+
+    docker-compose run --rm mobilizon eval Mobilizon.Cli.migrate
+
+Finally, run the application:
+
+    docker-compose up -d mobilizon
+
+## Update the service
+
+Pull the latest image, then run the migrations:
+
+    docker-compose pull mobilizon
+    docker-compose run --rm mobilizon eval Mobilizon.Cli.migrate
+
+Finally, update the service:
+
+    docker-compose up -d mobilizon
diff --git a/docker/production/docker-compose.yml b/docker/production/docker-compose.yml
index db38e50c9..c3b521624 100644
--- a/docker/production/docker-compose.yml
+++ b/docker/production/docker-compose.yml
@@ -1,42 +1,37 @@
-version: "2.1"
+version: "3"
 
 services:
   mobilizon:
     image: mobilizon
     environment:
-      - MOBILIZON_INSTANCE_NAME="My Mobilizon Instance"
-      - MOBILIZON_INSTANCE_HOST=mobilizon.lan
-      - MOBILIZON_INSTANCE_EMAIL=noreply@mobilizon.lan
+      - MOBILIZON_INSTANCE_NAME
+      - MOBILIZON_INSTANCE_HOST
+      - MOBILIZON_INSTANCE_EMAIL
+      - MOBILIZON_REPLY_EMAIL
       - MOBILIZON_INSTANCE_REGISTRATIONS_OPEN=true
-      - MOBILIZON_DATABASE_USERNAME
-      - MOBILIZON_DATABASE_PASSWORD
-      - MOBILIZON_DATABASE_DBNAME=mobilizon_prod
-      - MOBILIZON_DATABASE_HOST=postgres
+      - MOBILIZON_DATABASE_USERNAME=${POSTGRES_USER}
+      - MOBILIZON_DATABASE_PASSWORD=${POSTGRES_PASSWORD}
+      - MOBILIZON_DATABASE_DBNAME=${POSTGRES_DB}
+      - MOBILIZON_DATABASE_HOST=db
       - MOBILIZON_INSTANCE_SECRET_KEY_BASE
       - MOBILIZON_INSTANCE_SECRET_KEY
-      - MOBILIZON_ADMIN_EMAIL=your@email.com
-      - MOBILIZON_SMPT_SERVER=yoursmtpserver
-      - MOBILIZON_SMPT_MOBILIZON_SMPT_HOSTNAME=your.smtp.domain
-      - MOBILIZON_SMPT_PORT=25
-      - MOBILIZON_SMPT_USERNAME
-      - MOBILIZON_SMPT_PASSWORD
-      - MOBILIZON_SMPT_SSL=false
+      - MOBILIZON_SMTP_SERVER=yoursmtpserver
+      - MOBILIZON_SMTP_HOSTNAME=your.smtp.domain
+      - MOBILIZON_SMTP_USERNAME
+      - MOBILIZON_SMTP_PASSWORD
     volumes:
       - ./public/upload:/app/upload
     ports:
      - "4000:4000"
-    depends_on:
-      - postgres
 
-  postgres:
+  db:
     image: postgis/postgis
     volumes:
       - ./db:/var/lib/postgresql/data
-      - ./wal:/wal
-      - ./postgresql.conf:/var/lib/postgresql/data/postgresql.conf
     environment:
+      - POSTGRES_USER
       - POSTGRES_PASSWORD
-      - PGDATA=/var/lib/postgresql/data/pgdata
+      - POSTGRES_DB
 
 networks:
   default:
diff --git a/docker/production/env b/docker/production/env
index e1a7972d9..3b003dd38 100644
--- a/docker/production/env
+++ b/docker/production/env
@@ -1,10 +1,27 @@
-# You need to:
-# cp env .env
-# edite .env with your settings
-MOBILIZON_DATABASE_PASSWORD=postgres
-MOBILIZON_DATABASE_USERNAME=postgres
-MOBILIZON_INSTANCE_SECRET_KEY_BASE=MmU1NWQyYWQtM2MzZC00ZTU5LTg0MmItMmY5NDZlMmNhNmEwCg
-MOBILIZON_INSTANCE_SECRET_KEY=NjJhMGU5MDctZGNkOC00NGM0LWI5OWItZDEyY2FkNjRlODYyCg
-MOBILIZON_SMPT_USERNAME=username
+# Copy this file to env, then update it with your own settings
+
+# Database settings
+POSTGRES_USER=mobilizon
+POSTGRES_PASSWORD=changethis
+POSTGRES_DB=mobilizon
+
+# Application config
+MOBILIZON_INSTANCE_SECRET_KEY_BASE=changethis
+MOBILIZON_INSTANCE_SECRET_KEY=changethis
+MOBILIZON_SMTP_USERNAME=username
+MOBILIZON_SMPT_PASSWORD=password
+POSTGRES_PASSWORD=postgres
+
+# Instance configuration
+MOBILIZON_INSTANCE_NAME=My Mobilizon Instance
+MOBILIZON_INSTANCE_HOST=mobilizon.lan
+MOBILIZON_INSTANCE_SECRET_KEY_BASE=changethis
+MOBILIZON_INSTANCE_SECRET_KEY=changethis
+MOBILIZON_INSTANCE_EMAIL=noreply@mobilizon.lan
+MOBILIZON_REPLY_EMAIL=contact@mobilizon.lan
+
+# Email settings
+MOBILIZON_SMPT_SERVER=localhost
+MOBILIZON_SMPT_HOSTNAME=localhost
+MOBILIZON_SMPT_USERNAME=noreply@mobilizon.lan
 MOBILIZON_SMPT_PASSWORD=password
-POSTGRES_PASSWORD=postgres
\ No newline at end of file
diff --git a/docker/production/prod.secret.exs b/docker/production/releases.exs
similarity index 63%
rename from docker/production/prod.secret.exs
rename to docker/production/releases.exs
index 96cc31781..64a6ef993 100644
--- a/docker/production/prod.secret.exs
+++ b/docker/production/releases.exs
@@ -3,12 +3,13 @@
 import Config
 
 config :mobilizon, Mobilizon.Web.Endpoint,
+   server: true,
    url: [host: System.get_env("MOBILIZON_INSTANCE_HOST", "mobilizon.lan")],
    http: [port: 4000],
-   secret_key_base: System.get_env("MOBILIZON_INSTANCE_SECRET_KEY_BASE", "ZcvexeC7cnwtKR8ADMBDwrYu2aYHUyjrOu4yA181Z112HNu/I5jyRleo4hoxOMqQ")
+   secret_key_base: System.get_env("MOBILIZON_INSTANCE_SECRET_KEY_BASE", "changethis")
 
 config :mobilizon, Mobilizon.Web.Auth.Guardian,
-  secret_key: System.get_env("MOBILIZON_INSTANCE_SECRET_KEY", "KsdUIvp6hQ7b97yxUZcDQyGH0g4LS3fF0OvIsIATpkKzd1MDvSS4KexWXsjXeMQZ")
+  secret_key: System.get_env("MOBILIZON_INSTANCE_SECRET_KEY", "changethis")
 
 config :mobilizon, :instance,
   name: System.get_env("MOBILIZON_INSTANCE_NAME", "Mobilizon"),
@@ -19,7 +20,7 @@ config :mobilizon, :instance,
   allow_relay: true,
   federating: true,
   email_from: System.get_env("MOBILIZON_INSTANCE_EMAIL", "noreply@mobilizon.lan"),
-  email_reply_to: System.get_env("MOBILIZON_INSTANCE_EMAIL", "noreply@mobilizon.lan")
+  email_reply_to: System.get_env("MOBILIZON_REPLY_EMAIL", "noreply@mobilizon.lan")
 
 config :mobilizon, Mobilizon.Storage.Repo,
   adapter: Ecto.Adapters.Postgres,
@@ -32,18 +33,14 @@ config :mobilizon, Mobilizon.Storage.Repo,
 
 config :mobilizon, Mobilizon.Web.Email.Mailer,
   adapter: Bamboo.SMTPAdapter,
-  server: System.get_env("MOBILIZON_SMPT_SERVER", "localhost"),
-  hostname: System.get_env("MOBILIZON_SMPT_HOSTNAME", "localhost"),
-  port: System.get_env("MOBILIZON_SMPT_PORT", "25"),
-  username: System.get_env("MOBILIZON_SMPT_USERNAME", nil),
-  password: System.get_env("MOBILIZON_SMPT_PASSWORD", nil),
-  # can be `:always` or `:never`
+  server: System.get_env("MOBILIZON_SMTP_SERVER", "localhost"),
+  hostname: System.get_env("MOBILIZON_SMTP_HOSTNAME", "localhost"),
+  port: System.get_env("MOBILIZON_SMTP_PORT", "25"),
+  username: System.get_env("MOBILIZON_SMTP_USERNAME", nil),
+  password: System.get_env("MOBILIZON_SMTP_PASSWORD", nil),
   tls: :if_available,
   allowed_tls_versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"],
-  # can be `true`
-  ssl: System.get_env("MOBILIZON_SMPT_SSL", "false"),
+  ssl: System.get_env("MOBILIZON_SMTP_SSL", "false"),
   retries: 1,
-  # can be `true`
   no_mx_lookups: false,
-  # can be `:always`. If your smtp relay requires authentication set it to `:always`.
   auth: :if_available
diff --git a/docker/production/start.sh b/docker/production/start.sh
deleted file mode 100755
index 25b32dd12..000000000
--- a/docker/production/start.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-mix ecto.migrate
-mix phx.server
\ No newline at end of file
diff --git a/lib/mobilizon/cli.ex b/lib/mobilizon/cli.ex
new file mode 100644
index 000000000..88f5bda2d
--- /dev/null
+++ b/lib/mobilizon/cli.ex
@@ -0,0 +1,11 @@
+defmodule Mobilizon.Cli do
+  @app :mobilizon
+
+  def migrate do
+    Application.load(@app)
+
+    for repo <- Application.fetch_env!(@app, :ecto_repos) do
+      {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
+    end
+  end
+end
\ No newline at end of file