diff --git a/Dockerfile b/Dockerfile
index aecb3ace57906e432f5326289525db50a63d2c25..38a57e6dc31ea194150eb3e7b63b8c03b44d4699 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -19,7 +19,8 @@ CMD ["pnpm", "exec", "tsx", "src/indexer/start.ts"]
 # TODO build image only for indexer without app
 # TODO really build for node and not use tsx (is it necessary)
 
-# build and run for test
-# docker buildx build . -t test-datapod
-# docker run --rm -it test-datapod
+# build and run
+# docker buildx build . -t h30x/duniter-datapod
+# docker image push h30x/duniter-datapod
+# docker run --rm -it h30x/duniter-datapod
 # CMD ["pnpm", "exec", "tsx", "src/scripts/hello.ts"]
diff --git a/Dockerfile.Hasura b/Dockerfile.Hasura
new file mode 100644
index 0000000000000000000000000000000000000000..ac2ec44fdb666448ee45f9868abd7d061a246372
--- /dev/null
+++ b/Dockerfile.Hasura
@@ -0,0 +1,5 @@
+FROM hasura/graphql-engine:v2.38.1.cli-migrations-v3
+COPY ./hasura/migrations /hasura-migrations
+COPY ./hasura/metadata /hasura-metadata
+# docker buildx build -f Dockerfile.Hasura . -t h30x/datapod-hasura
+# docker image push h30x/datapod-hasura
\ No newline at end of file
diff --git a/Dockerfile.Kubo b/Dockerfile.Kubo
new file mode 100644
index 0000000000000000000000000000000000000000..4cb3d2e0bdbab57e60a4da2b28403961b6111275
--- /dev/null
+++ b/Dockerfile.Kubo
@@ -0,0 +1,5 @@
+FROM ipfs/kubo:v0.28.0
+COPY ./scripts/remove-default-bootstrap.sh /container-init.d/001-remove-default-bootstrap.sh
+CMD ["daemon", "--enable-pubsub-experiment"]
+# docker buildx build -f Dockerfile.Kubo . -t h30x/datapod-kubo
+# docker image push h30x/datapod-kubo
\ No newline at end of file
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
new file mode 100644
index 0000000000000000000000000000000000000000..fd55b8fbd4af1a78cca939784e0b64cd61f8e844
--- /dev/null
+++ b/docker-compose.prod.yml
@@ -0,0 +1,72 @@
+# prod compose file
+
+services:
+  # ------
+  postgres:
+    image: postgres:16
+    restart: always
+    volumes:
+      - db_data:/var/lib/postgresql/data
+    environment:
+      POSTGRES_USER: ${DB_USER:-postgres}
+      POSTGRES_PASSWORD: ${DB_PASSWORD:-postgrespassword}
+      POSTGRES_DB: ${DB_DATABASE:-postgres}
+    healthcheck:
+      test: ['CMD-SHELL', 'pg_isready -U postgres -d postgres']
+      interval: 1s
+
+  # ------
+  hasura:
+    image: h30x/datapod-hasura
+    depends_on:
+      postgres:
+        condition: service_healthy
+    restart: always
+    ports:
+      - '${HASURA_LISTEN_PORT:-8765}:8080'
+    environment:
+      HASURA_GRAPHQL_DATABASE_URL: postgres://${DB_USER:-postgres}:${DB_PASSWORD:-postgrespassword}@postgres:5432/${DB_DATABASE:-postgres}
+      HASURA_GRAPHQL_ENABLE_CONSOLE: true
+      HASURA_GRAPHQL_DEV_MODE: false
+      HASURA_GRAPHQL_UNAUTHORIZED_ROLE: public
+      HASURA_GRAPHQL_ENABLE_TELEMETRY: false
+      HASURA_GRAPHQL_ADMIN_SECRET: ${HASURA_GRAPHQL_ADMIN_SECRET:-my_hasura_secret}
+
+  # ------
+  kubo:
+    image: h30x/datapod-kubo
+    ports:
+      # p2p port public
+      - 4001:4001
+      - 4001:4001/udp
+      # public gateway
+      - 8080:8080
+      # expose RPC locally to allow access with ssh tunnel
+      - 127.0.0.1:5001:5001
+    volumes:
+      - kubo_data:/data/ipfs
+    healthcheck:
+      test: ['CMD', 'ipfs', 'diag', 'cmds']
+      interval: 1s
+    restart: always
+
+  # ------
+  datapod:
+    image: h30x/duniter-datapod
+    depends_on:
+      postgres:
+        condition: service_healthy
+      kubo:
+        condition: service_healthy
+    environment:
+      KUBO_RPC: "http://kubo:5001"
+      DB_HOST: postgres
+      DB_PORT: 5432
+      DB_USER: ${DB_USER:-postgres}
+      DB_PASSWORD: ${DB_PASSWORD:-postgrespassword}
+    restart: always
+
+
+volumes:
+  db_data:
+  kubo_data:
diff --git a/docker-compose.yml b/docker-compose.yml
index e9bfd326c016aac6b646130435d00f94b3f27d98..f38f1ac59713b7b16eff86b8073fe600f4391958 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,10 +1,11 @@
-version: '3.6'
+# development compose file
+
 services:
   postgres:
     image: postgres:16
     restart: always
     ports:
-      - '5432:5432'
+      - '5432:5432' # expose db for indexer
     volumes:
       - db_data:/var/lib/postgresql/data
     environment:
@@ -16,13 +17,13 @@ services:
       retries: 5
 
   hasura:
-    image: hasura/graphql-engine:v2.38.1.cli-migrations-v3
+    image: hasura/graphql-engine:v2.38.1.cli-migrations-v3 # dev image to apply migrations
     depends_on:
       postgres:
         condition: service_healthy
     restart: always
     ports:
-      - '${HASURA_LISTEN_PORT}:8080'
+      - '${HASURA_LISTEN_PORT}:8080' # because kubo gateway is already listening on 8080
     environment:
       HASURA_GRAPHQL_DATABASE_URL: postgres://postgres:${DB_PASSWORD}@postgres:5432/postgres
       HASURA_GRAPHQL_ENABLE_CONSOLE: true
diff --git a/scripts/remove-default-bootstrap.sh b/scripts/remove-default-bootstrap.sh
new file mode 100644
index 0000000000000000000000000000000000000000..bb0cc116bd65cbb2f4393092716347699b43df51
--- /dev/null
+++ b/scripts/remove-default-bootstrap.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+set -ex
+ipfs bootstrap rm all
diff --git a/src/kubo.ts b/src/kubo.ts
index 507985bbdef2d97e9574353d7a0104868e27c82f..0854bf6e5845514934b24257b2f950782ac6f090 100644
--- a/src/kubo.ts
+++ b/src/kubo.ts
@@ -3,7 +3,8 @@ import type { IPFSHTTPClient } from 'kubo-rpc-client'
 import { CID } from 'multiformats'
 
 // env
-var process : NodeJS.Process | undefined = typeof(process) == "undefined" ? undefined : process
+// TODO clean way to declare KUBO_RPC for Vue App
+// var process : NodeJS.Process | undefined = typeof(process) == "undefined" ? undefined : process
 const KUBO_RPC = process?.env.KUBO_RPC || 'http://127.0.0.1:5001'
 const KUBO_GATEWAY = process?.env.KUBO_GATEWAY || 'http://127.0.0.1:8080'