Skip to main content

How to put a express server in Browser

· 4 min read
A Independent developer

While exploring WebRTC, I had a simple thought:

WebRTC communication feels a lot like HTTP — so why not abstract it as an HTTP-like service?

If you compare a typical Node.js HTTP server with WebRTC data channel communication, they’re actually quite similar:

  • Both listen for incoming messages/events
  • Both process requests
  • Both send responses back

🔍 A Quick Comparison

HTTP Server (Node.js)

const http = require('http');

const PORT = 3000;

const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, World!\n');
});

server.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}/`);
});

WebRTC DataChannel

const peerConnection = new RTCPeerConnection(configuration);

const dataChannel = peerConnection.createDataChannel('my-channel');

dataChannel.onopen = () => {
console.log('Data channel opened');
};

dataChannel.onmessage = (event) => {
console.log('received data:', event.data);
};

let remoteChannel = null;

peerConnection.ondatachannel = (event) => {
remoteChannel = event.channel;

remoteChannel.onmessage = (event) => {
console.log('received remote message:', event.data);

// reply
remoteChannel.send('gotcha');
};
};

From this, it becomes obvious:

👉 The DataChannel is essentially an event-driven transport layer, just like HTTP.

So I asked:

Can I build an HTTP-like server abstraction on top of WebRTC?

The answer turned out to be: yes.


🧱 Step 1: Define a Message Protocol

Unlike HTTP, we don’t need to support complex content types.

We can keep things simple and use JSON.

Important: All peers must follow the same message structure.

export type PeerMessage = {
id: string;
src: string;
dest: string;
method: string;
path: string;
body: Record<string, any>;
headers: Record<string, any>;
status: string;
guid?: string;
timestamp: number | string;
metadata?: Record<string, any>;
scope: 'request' | 'response';
};

🧭 Step 2: Build a Router (Like Express)

If you’ve ever read the source code of Express or Koa, you’ll notice:

A router is surprisingly simple — you can build one in under 100 lines.

I built a slightly enhanced version with:

  • Routing (GET / POST)
  • Middleware support
  • Error handling
  • Route caching
  • Performance monitoring

Here’s the core idea:

export class PeerRouter {
protected routes = [];
protected middleware = [];

get(path: string, callback: RequestCallbackFn) {
this.routes.push({ path, method: 'GET', callback });
}

post(path: string, callback: RequestCallbackFn) {
this.routes.push({ path, method: 'POST', callback });
}

use(handler: RequestCallbackFn) {
this.middleware.push(handler);
}

async run(conn: DataConnection, message: PeerMessage) {
const route = this.routes.find((r) => r.path === message.path);

if (!route) {
console.warn(`No route for ${message.method} ${message.path}`);
return;
}

for (const mw of this.middleware) {
await mw(conn, message);
}

await route.callback(conn, message);
}
}

⚙️ Step 3: Create a PeerServer

This is where everything comes together.

  • Handle incoming requests
  • Match routes
  • Track request/response lifecycle
class PeerServer {
private router = new PeerRouter();
private requests = new Map();

use(handler: RequestCallbackFn) {
this.router.use(handler);
}

addRoute(route: RouteItem) {
this.router.add(route);
}

async onMessage(conn: DataConnection, message: PeerMessage) {
if (message.scope === 'request') {
return this.router.run(conn, message);
}

if (message.scope === 'response') {
const cb = this.requests.get(message.id);
if (cb) cb(message);
}
}
}

🧪 Step 4: Use It Like Express

Now comes the fun part.

We can write WebRTC logic just like Express:

const server = new PeerServer();

server.use(async (conn, message, next) => {
if (message.headers['x-device-id'] !== 'xx') {
throw new Error('Invalid device id');
}
return next();
});

server.get('/ping', (conn, message) => {
conn.send({
...message,
body: { message: 'ok' },
status: 200,
});
});

Hook it into WebRTC:

dataChannel.onmessage = (event) => {
server.onMessage(dataChannel, event.data);
};

peerConnection.ondatachannel = (event) => {
const remoteChannel = event.channel;

remoteChannel.onmessage = (event) => {
server.onMessage(remoteChannel, event.data);
};
};

🎯 The Result

You now have:

An Express-like server running entirely inside the browser, powered by WebRTC.

No ports. No servers. No traditional backend.


🌍 Real-world Usage

This architecture is already powering 👉 https://egosapp.com

All P2P communication in EGOS is built on top of this system.

It lets me:

  • Write WebRTC logic like Express APIs
  • Treat devices as distributed endpoints
  • Build a decentralized file network

🧠 Final Thought

HTTP changed how we build applications by standardizing communication.

WebRTC opens the door to something new:

Peer-to-peer applications that feel like traditional client-server systems — but without servers.


If you're interested, feel free to try it out or share feedback.

Why Egos

· 2 min read
A Independent developer

A few months ago, I dropped my phone into a river while fishing.

It died instantly.

What hurt wasn’t the phone — it was the data. Photos, videos… all gone. No backup.

So I did what many people here probably did: I bought a UGREEN NAS and told myself:

“I’ll never lose data again.”

But after a few months, I noticed something weird.

I only have ~40GB of photos and videos. I don’t run Plex. I don’t watch movies on TV. I don’t need a 24/7 home server.

And yet… I now own one.

In the end, my NAS became… a very expensive photo backup box that I use maybe once a quarter but running 24 hours every day.

I went deeper into the self-hosted world:

  • ownCloud

  • Alist

  • fnOS

  • TrueNAS

As a developer, I expected this to be easy.

It wasn’t.

Config files, services, ports, permissions, LAN limit…

Everything feels like it’s built for sysadmins, not normal users.

Even for me, it was tiring.

So I asked myself a simple question:

What do I actually need?

  • Not a media center.
  • Not RAID.
  • Not a dashboard with 20 widgets.

Just:

A way to not lose files A way to move files between devices easily

So I built a small tool for myself.

It’s basically a minimal personal file system with a different approach:

  • No setup (just run it)
  • Fast data backup
  • Cross-platform and Portable
  • Keep data in hand
  • Access data not only in a same LAN

it works like this:

Need a file from device A → download it directly, Want to send something → upload it to A target folder

That’s it.

I’ve been using it for half a year, and honestly:

It replaced my NAS for 90% of what I actually do.

I’m curious how others feel:

Do you actually use your NAS daily? Or is it mostly just sitting there? Was it worth the complexity?

If anyone here had the same frustration with overcomplicated self-hosted tools, I made this project public:

👉 https://egosapp.com

Would genuinely love feedback — especially from people in this sub. Not trying to replace NAS for power users, just exploring a simpler option.

Welcome

· 2 min read
A Independent developer

Founded in 2020, Egos was born from a simple observation: I wanna build a tool for myself to improve my work efficiency. I put all I need in this app. It's a Stitches and personalize app. The real reason that made me to build a new product is: When I was fired by Publicis Group at 2024, I was tired of life in big cities. I returned to my hometown and started planting oranges with my father. One day, my father said to me, "Son, you should go back to your work? You known, every day, when I seeing you laboring in the fields, I wish that you were working in a city with your own career. Only then I would sleep peacefully at night without worrying about you. You're not a farmer, nor can you ever become one. Your heart is like a little bird; you'd spare a weed just because it looks different. You let the fruit trees grow wild, simply because you think pruning them would hurt the trees. Go back and do what you're good at. Keeping and doing one thing well."

I cut up most function of the original App(4/5), just keep one core function: File Transfer & Sharing.