diff --git a/.env.example b/.env.example
index b2f91e96f0ce4588aa9d68673a568d750b88c121..fee4edc9b50cdd0e52b40847367f90dd6cb2a5f2 100644
--- a/.env.example
+++ b/.env.example
@@ -12,3 +12,6 @@ DB_PASSWORD=my_db_password
 # === HASURA ===
 HASURA_GRAPHQL_ADMIN_SECRET=my_hasura_password
 HASURA_LISTEN_PORT=8765
+
+# === GATEWAY
+GATEWAY_LISTEN_PORT=3000
\ No newline at end of file
diff --git a/src/gateway/README.md b/src/gateway/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..2af5a1c0048e766302abd256062407f9c334db82
--- /dev/null
+++ b/src/gateway/README.md
@@ -0,0 +1,7 @@
+# Gateway
+
+This gateway is a way for non-p2p clients to submit data to a http endpoint that will then be forwarded to the p2p network.
+
+It is a stupid gateway that puts all content to local kubo node (but does not pin) and forwards the cid of the first block on pubsub topic.
+
+Since it does not include any protection mechanism because it relies on datapod network security, it is recommanded to limit the incoming network traffic and apply IP-based protections, preventing an attacker to trigger IPFS garbage collection too easily. Or to limit connection to trusted users.
\ No newline at end of file
diff --git a/src/gateway/start.ts b/src/gateway/start.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0203a4a94ed3685d03d5686f89133799a5a37a95
--- /dev/null
+++ b/src/gateway/start.ts
@@ -0,0 +1,71 @@
+import { TOPIC } from '../consts'
+import { kubo } from '../kubo'
+import * as http from 'http'
+
+// we could use this hack to allow submitting json data with html form
+// https://systemoverlord.com/2016/08/24/posting-json-with-an-html-form.html
+const GATEWAY_LANDING_PAGE = `<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="UTF-8">
+		<meta name="viewport" content="width=device-width, initial-scale=1"/>
+		<title>Datapod Gateway</title>
+	</head>
+	<body>
+		<h1>Datapod Gateway</h1>
+        <p>Use POST requests to submit data programatically. Alternatively, you can submit data manually in the form below for testing purpose.</p>
+        <form method="post" action="http://localhost:3000" enctype='text/plain'>
+            Blocks as base64 json list: 
+            <input type="text" name="blocks" size=100 placeholder="['index request as base64', 'data as base 64', 'optional aditionnal data as base64'...]"/>
+            <input type="submit" value="Submit" />
+        </form>
+	</body>
+</html>
+`
+
+function handleRequest(request: http.IncomingMessage, response: http.ServerResponse<http.IncomingMessage>) {
+  if (request.method == 'POST') {
+    let body = ''
+    request.on('data', function (data) {
+      body += data
+    })
+    request.on('end', function () {
+      // hack to allow submitting data with form
+      if (body.startsWith('blocks=')) {
+        body = body.slice(7)
+      }
+      console.log('Body: ' + body)
+      try {
+        const blocks = JSON.parse(body)
+        let first = true
+        for (const b of blocks) {
+          // first item is the index request CID
+          if (first) {
+            kubo.pubsub.publish(TOPIC, new TextEncoder().encode(b + '\n'))
+            first = false
+            continue
+          }
+          // other items are blocks
+          const buffer = Buffer.from(b, 'base64')
+          const bytes = new Uint8Array(buffer)
+          kubo.block.put(bytes).then((cid) => {})
+        }
+        response.writeHead(200, { 'Content-Type': 'text/html' })
+        response.end('data received and forwarded<br/>' + JSON.stringify(blocks, null, 4))
+      } catch (e: any) {
+        response.writeHead(400, { 'Content-Type': 'text/html' })
+        response.end('invalid request\n' + e.toString())
+      }
+    })
+  } else {
+    var html = GATEWAY_LANDING_PAGE
+    response.writeHead(200, { 'Content-Type': 'text/html' })
+    response.end(html)
+  }
+}
+
+const server = http.createServer(handleRequest)
+const port = process.env.GATEWAY_LISTEN_PORT || 3000
+const host = '127.0.0.1'
+server.listen(port)
+console.log(`Listening on http://${host}:${port}`)