Fully functioning terminal on Coolify
A few months ago, Andras, the maintainer of Coolify, requested a feature as a bounty that would allow users to connect to their terminal directly from the web browser. How cool would that be? And since Coolify is Docker-based, we needed to connect to multiple containers and servers too!
I thought it would be a great feature and an excellent opportunity to learn about WebSockets. So, I decided to give it a try. Little did I know what I was getting myself into...
The PHP Struggle is Real
Many comments on the issue led me in the right direction. Using PTY (Pseudoterminal) and WebSockets
After some research, I realized that this feature was not that simple. It would require node-pty library because, well... who's going to reinvent the wheel?
I wondered about using only PHP for this, but we needed a robust event loop and the ability to handle asynchronous I/O operations for long-running processes like a terminal. PHP isn't built for long-running processes like Node.js is. It's designed to handle requests and then bow out, not hang around for an ongoing chat with a terminal.
And on top of that, how to write the translation layer between the browser and the terminal? So... node-pty
it is!
Portainer uses it, and all Google searches about creating a terminal in web browsers pointed to this library. Its a Microsoft product, and VSCode uses it too!
Node.js to the Rescue
After banging my head against the PHP wall for a while, trying to re-use Laravel Pusher/Echo, I hit a dead-end. There's no SDK for it, and I tried to monkey-patch it, but it wasn't working. I decided to pivot to a simple Node.js server. And let me tell you, it was like a breath of fresh air! Node's event-driven, non-blocking I/O model is perfect for this kind of real-time, long-running process.
After setting up the magic of Xterm.js for the frontend and node-pty
for creating pseudo-terminals. Suddenly, things started falling into place!
(On a side note: I even stumbled upon this WebSocket library for PHP which looks promising)
PoC, PoC, PoC, Who's There?
So, I started to build a PoC (Proof of Concept), using XTerm.js and Node.js magic. I encountered some challenges with authentication on the Laravel side and the extra container for Node.js, which turned out to be unnecessary. Thus, the Frankenstein monster was born:
- A Node.js server integrated into Coolify's existing "coolify-realtime" container.
- XTerm.js powering a slick web-based terminal interface.
- WebSocket connections for real-time communication.
- PTY magic to create a genuine terminal experience.
- Robust authentication to keep things secure.
The Cool Factor
I can't overstate how awesome it is to have a fully functioning terminal right in your browser. Need to quickly check a log file? Bam! Want to restart a service? Boom! All without leaving your Coolify dashboard. It's like having your entire server infrastructure at your fingertips.
Waiting to merge
I've created a Pull Request for this feature and am anxiously waiting to be merged. Fingers crossed that it will soon be available to all Coolify users!