diff --git a/Dockerfile b/Dockerfile
index 88eb14e..1d70ac1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -22,6 +22,8 @@ USER user
 
 COPY optimizerapi/ /code
 
+ENV FLASK_ENV=production
+
 ENV PATH=/opt/venv/bin:${PATH}
 
 CMD [ "python", "./server.py" ]
\ No newline at end of file
diff --git a/README.md b/README.md
index ea51886..af771c2 100644
--- a/README.md
+++ b/README.md
@@ -16,9 +16,30 @@ Alternatively the project can be build and run with the following commands:
     python optimizerapi/server.py
 
 Now open [http://localhost:9090/v1.0/ui/](http://localhost:9090/v1.0/ui/) in a browser to explore the API through Swagger UI
-
 # Running tests
 
 Unit tetsts are located in the "tests" folder and can be run witht the following command
 
     python -m pytest
+
+# Building docker container
+
+    docker build -t process-optimizer-api .
+# Obtain encryption key
+
+Run server once and extract a fresh encryption key from the logs.
+
+    python optimizerapi/server.py
+
+or using docker
+
+    docker run --rm -it process-optimizer-api
+# Running in production
+
+Running using python
+
+    FLASK_ENV=production PICKLE_KEY=<key from previous step> python optimizerapi/server.py
+
+or use docker
+
+    docker run -d --name process-optimizer-api --env PICKLE_KEY=<key from previous step> -p 9090:9090 process-optimizer-api:latest
diff --git a/optimizerapi/openapi/specification.yml b/optimizerapi/openapi/specification.yml
index bac7a98..04d1e5c 100644
--- a/optimizerapi/openapi/specification.yml
+++ b/optimizerapi/openapi/specification.yml
@@ -97,6 +97,8 @@ components:
         result:
           type: object
           properties:
+            pickled:
+              type: string
             next:
               type: array
               items:
diff --git a/optimizerapi/optimizer.py b/optimizerapi/optimizer.py
index ba0aa4d..adf401b 100644
--- a/optimizerapi/optimizer.py
+++ b/optimizerapi/optimizer.py
@@ -1,5 +1,3 @@
-import codecs
-import pickle
 import json
 from json_tricks import dumps
 from ProcessOptimizer import Optimizer, expected_minimum
@@ -10,6 +8,8 @@
 import base64
 import io 
 from numbers import Number
+from securepickle import pickleToString, unpickleFromString, get_crypto
+
 import numpy
 numpy.random.seed(42)
 """ProcessOptimizer web request handler
@@ -110,9 +110,10 @@ def processResult(result, optimizer, dimensions, cfg, data, space):
         addPlot(response["plots"], "convergence")
 
         plot_objective(result, dimensions=dimensions, usepartialdependence=False)
-        addPlot(response["plots"], "objective", debug=True)
+        addPlot(response["plots"], "objective")
     
-    print(str(response))
+    prettyResult["pickled"] = pickleToString(result, get_crypto())
+    # print(str(response))
     return response
 
 def addPlot(result, id="generic", close=True, debug=False):
diff --git a/optimizerapi/securepickle/__init__.py b/optimizerapi/securepickle/__init__.py
new file mode 100644
index 0000000..b59a9a9
--- /dev/null
+++ b/optimizerapi/securepickle/__init__.py
@@ -0,0 +1,2 @@
+from .pickler import pickleToString, unpickleFromString
+from .secure import get_crypto
\ No newline at end of file
diff --git a/optimizerapi/securepickle/pickler.py b/optimizerapi/securepickle/pickler.py
new file mode 100644
index 0000000..ad029c7
--- /dev/null
+++ b/optimizerapi/securepickle/pickler.py
@@ -0,0 +1,11 @@
+import codecs
+import pickle
+
+def pickleToString(obj, crypto):
+    pickled = codecs.encode(crypto.encrypt(pickle.dumps(obj)), "base64").decode()
+    return pickled
+
+def unpickleFromString(pickled, crypto):
+    unpickled = pickle.loads(crypto.decrypt(codecs.decode(pickled.encode(), "base64")))
+    return unpickled
+
diff --git a/optimizerapi/securepickle/secure.py b/optimizerapi/securepickle/secure.py
new file mode 100644
index 0000000..c9aee33
--- /dev/null
+++ b/optimizerapi/securepickle/secure.py
@@ -0,0 +1,11 @@
+from cryptography.fernet import Fernet
+import os
+
+def get_crypto(key=None):
+    if key == None: key = os.getenv("PICKLE_KEY", None)
+    if key == None: 
+        print("No key found, generating new key")
+        key = Fernet.generate_key()
+        os.environ["PICKLE_KEY"] = key.decode("utf-8")
+        print("To reuse key for future server runs, set environment variable PICKLE_KEY=" + os.environ["PICKLE_KEY"])
+    return Fernet(key)
\ No newline at end of file
diff --git a/optimizerapi/server.py b/optimizerapi/server.py
index fd5fcae..f46f7ab 100644
--- a/optimizerapi/server.py
+++ b/optimizerapi/server.py
@@ -1,6 +1,15 @@
+import os
 import connexion
+from securepickle import get_crypto
+from waitress import serve
 
 if __name__ == '__main__':
+    # Initialize crypto
+    get_crypto()
     app = connexion.FlaskApp(__name__, port=9090, specification_dir='./openapi/')
     app.add_api('specification.yml', arguments={'title': 'Hello World Example'})
-    app.run()
\ No newline at end of file
+    if os.getenv("FLASK_ENV", "development") == "development":
+        os.environ["FLASK_ENV"] = "development"
+        app.run()
+    else:
+        serve(app, listen='*:9090')
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 32b37b6..0ea2dba 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,4 +2,6 @@ connexion==2.7.0
 connexion[swagger-ui]
 Flask==1.1.2
 ProcessOptimizer==0.6.1
-json-tricks==3.15.5
\ No newline at end of file
+json-tricks==3.15.5
+cryptography==3.4.7
+waitress==2.0.0
\ No newline at end of file
diff --git a/tests/test_securepickle.py b/tests/test_securepickle.py
new file mode 100644
index 0000000..c367fc5
--- /dev/null
+++ b/tests/test_securepickle.py
@@ -0,0 +1,15 @@
+from optimizerapi.securepickle import pickleToString, unpickleFromString, get_crypto
+
+def test_pickleToString():
+    f = get_crypto()
+    encoded = pickleToString("myString", f)
+    assert encoded != "myString"
+
+def test_unpickleFromString():
+    f = get_crypto()
+    encoded = pickleToString("myString", f)
+    decoded = unpickleFromString(encoded, f)
+    assert decoded == "myString"
+
+
+
