diff --git a/.dockerignore b/.dockerignore
index 56e5249f5bb5687a53c9d4c986a6e9b94871e013..c85612566423b7ba2c8d21b091a75a40ced15e54 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,6 +1,7 @@
 .git
 .gitignore
 
+Dockerfile
 .dockerignore
 
 **/node_modules
diff --git a/Dockerfile b/Dockerfile
index 0d6818ab8a12782747a05d871e016a4109c987fb..77c4353f161714c9f86bdc4c6f34bba65011fad6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -17,16 +17,36 @@ COPY jams-common/pom.xml jams-common/pom.xml
 COPY jams-launcher/pom.xml jams-launcher/pom.xml
 COPY ldap-connector/pom.xml ldap-connector/pom.xml
 COPY jams-server/pom.xml jams-server/pom.xml
+
 # RUN mvn verify --fail-never
 # RUN mvn dependency:resolve --fail-never
-RUN mvn dependency:go-offline --fail-never
-
+# RUN mvn dependency:go-offline --fail-never -am
+RUN mvn install -pl ad-connector,authentication-module,datastore,jami-dht,jami-nameserver,jams-ca,jams-common,jams-launcher,ldap-connector,jams-server -am -DskipTests
 COPY . .
-# RUN mvn clean package
+
+FROM build as dev
+WORKDIR /app
+RUN mkdir -p /app/jams-server/src/main/resources/webapp \
+    && echo '<h1>Dev build, please connect to <a href="http://localhost:3000">localhost:3000</a> instead</h1>' \
+    > /app/jams-server/src/main/resources/webapp/index.html
 RUN mvn package
+WORKDIR /app/jams
+EXPOSE 3000 8080
+CMD java -jar jams-launcher.jar & npm start --prefix ../jams-react-client
 
-FROM adoptopenjdk/openjdk11:jdk-11.0.2.9-alpine
+FROM build as prod
+WORKDIR /app/jams-react-client
+RUN npm run build
+RUN mv build ../jams-server/src/main/resources/webapp
 WORKDIR /app
-COPY --from=build /app/jams .
-EXPOSE 8080
-ENTRYPOINT ["java","-jar","jams-launcher.jar"]
+RUN mvn package
+
+ENV JAMS_VERSION=3.4
+RUN python3 generate-versions.py net.jami.jams.ca.JamsCA $JAMS_VERSION libs/cryptoengine.jar
+RUN python3 generate-versions.py net.jami.jams.authmodule.UserAuthenticationModule $JAMS_VERSION libs/authentication-module.jar
+RUN python3 generate-versions.py net.jami.jams.server.Server $JAMS_VERSION jams-server.jar
+RUN python3 generate-versions.py net.jami.jams.ad.connector.ADConnector $JAMS_VERSION libs/ad-connector.jar
+RUN python3 generate-versions.py net.jami.jams.ldap.connector.LDAPConnector $JAMS_VERSION libs/ldap-connector.jar
+
+RUN ./build-doc.sh
+CMD ["cp", "-r", "jams/.", "/jams"]
diff --git a/README.md b/README.md
index 03708ff7a55f48f833a9765723d75895f5e78c52..8446ea3632dd8550a48766ca356d6d943315bdfd 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,15 @@
-#### JAMS (Jami Account Management Server)
+# JAMS (Jami Account Management Server)
 
-##### Requirements
+## Requirements
 
 - JDK 11+
 - maven
 
-##### Building from source
+## Building from source
 
 Clone the contents of this repository and run
 
 ```
-cd jams-react-client
-npm install
-npm start
-cd ..
 mvn clean package
 ```
 
@@ -32,7 +28,7 @@ from 8080, then run:
 
 Where the `pem` and `key` files are a pem encoded certificate and key.
 
-##### How to generate server.pem and server.key pair
+## How to generate server.pem and server.key pair
 
 In order to generate a pair of pem and key use the following command using openssl
 
@@ -45,7 +41,7 @@ This can be completed by running `npm install -g apidoc`, if for some reason
 that does not work, you can clone their project from : https://github.com/apidoc/apidoc
 and install it from source.
 
-To build the documentation, change enter the `jams-server` directory and simply run:
+To build the documentation, enter the `jams-server` directory and simply run:
 
 `apidoc -i src/ -o doc/`
 
@@ -62,16 +58,26 @@ chmod +x .git/hooks/pre-commit
 
 ## Development Docker container
 
-You can build the docker container using:
-
+A development environment with react hot reloading can be created using:
 ```
-docker build -f Dockerfile -t jams:latest .
+docker build -f Dockerfile -t jams:dev --target dev .
+docker run -it -p 3000:3000 -p 8080:8080 \
+    -v $(pwd)/jams-react-client/src:/app/jams-react-client/src \
+    -v $(pwd)/jams-react-client/public:/app/jams-react-client/public \
+    --rm jams:dev
 ```
 
-To run the docker container (assuming you want to have it on port 8080 locally):
+Note: It is possible that after 15 minutes, the user's token expires, the server
+will answer with a "You are not authentified" and forget to put the CORS
+headers, thus the browser will refuse to read the response. In this case, you
+will need to restart the server.
 
+## Generate jams with Docker
+The following commands will generate the userguide and the jars needed:
 ```
-docker run -p 8080:8080 --rm jams:latest
+docker build -f Dockerfile -t jams:latest --target prod .
+docker run -v $(pwd)/jams:/jams --rm jams:latest
+sudo chown -R $(whoami) jams
 ```
 
 ## About jams-server/src/main/java/net/jami/jams/server/filters
diff --git a/generate-versions.py b/generate-versions.py
index 695366da41600642eed1b95b369b703d5fc2d6ad..a460bdc19795281182f2371126fd212d9287450e 100644
--- a/generate-versions.py
+++ b/generate-versions.py
@@ -1,32 +1,42 @@
+import hashlib
 import json
 import sys
-import hashlib
-import os
+from pathlib import Path
+
+
+def read_versions(versions_file: Path) -> dict:
+    if not versions_file.exists():
+        return {}
+
+    with open(versions_file) as f:
+        return json.load(f)
+
 
-os.chdir("..")
 
-className = sys.argv[1]
-version = sys.argv[2]
-try:
-    filename = sys.argv[3].split("/")[1]
-except:
+def main() -> None:
+    here = Path(__file__).parent
+    versions_file = here / "versions.json"
+
+    class_name = sys.argv[1]
+    version = sys.argv[2]
     filename = sys.argv[3]
 
-try:
-    f = open("versions.json", "r")
-    map = json.loads(f.read())
-except:
-    map = {}
-map[className] = {}
-map[className]['version'] = version
-map[className]['filename'] = filename
-md5_hash = hashlib.md5()
-a_file = open("jams/" + sys.argv[3], "rb")
-content = a_file.read()
-md5_hash.update(content)
-digest = md5_hash.hexdigest()
-map[className]['md5'] = digest
-f = open("versions.json", "w")
-f.write(json.dumps(map,indent=4))
-f.close()
+    versions = read_versions(versions_file)
+
+    md5_hash = hashlib.md5()
+
+    with open(here / "jams" / filename, "rb") as jar:
+        md5_hash.update(jar.read())
+
+    versions[class_name] = {
+        "version": version,
+        "filename": filename,
+        "md5": md5_hash.hexdigest(),
+    }
+
+    with open(versions_file, "w") as f:
+        json.dump(versions, f, indent=4)
+
 
+if __name__ == "__main__":
+    main()
diff --git a/jams-server/build-ui.sh b/jams-server/build-ui.sh
index fdb7d78c1dfbdc487cefab6e3744619af11bfc28..7265b800363ef8d88b6f705ccda1961b22e7c06c 100755
--- a/jams-server/build-ui.sh
+++ b/jams-server/build-ui.sh
@@ -1,4 +1,7 @@
 #!/bin/bash
+
+set -eo pipefail
+
 #Build the UI from the react js folder.
 cd ../jams-react-client || exit
 npm install