forked from snxraven/ravenscott-blog
257 lines
14 KiB
Markdown
257 lines
14 KiB
Markdown
<!-- lead -->
|
||
Creating a Linux Based Hosting Solution for Twitter.
|
||
|
||
It all started with a question that initially seemed a bit absurd: *Could you manage a Linux server using only Twitter?* At first glance, the idea appeared impractical. After all, social media platforms aren’t exactly designed for hosting virtual machines or executing server-side commands. But, as someone who thrives on pushing boundaries, I decided to take this concept and run with it.
|
||
|
||
I envisioned a Twitter bot that could host Linux containers, execute commands, and interact with users all through tweets. In the end, this project led me to become what I believe is the first person to host Linux containers directly through Twitter interactions. This blog post will take you through the entire process in meticulous detail — from conceptualizing the idea, writing the code, and overcoming challenges, to launching the bot and maintaining it.
|
||
|
||
<p align="center">
|
||
<img src="https://raven-scott.fyi/twit_linux.webp" alt="Twit Linux">
|
||
</p>
|
||
|
||
# Source
|
||
|
||
## https://git.ssh.surf/snxraven/codename-t
|
||
|
||
Some scripts mentioned in the above code are covered in the below Blog Post:
|
||
https://blog.raven-scott.fyi/deep-dive-discord-linux-automated-container-platform
|
||
|
||
### The Concept: Why Twitter for Linux Hosting?
|
||
|
||
Before diving into the technical details, it’s important to understand the motivations behind this project. The world of DevOps and Linux system administration is traditionally one of terminals, SSH keys, and intricate scripts. However, I wanted to bring this technical space to a more social, accessible environment. And what better place to do that than Twitter, a platform where millions of people spend their time daily?
|
||
|
||
The goal was simple: **I wanted to democratize Linux hosting by allowing users to spin up containers, execute commands, and even destroy their own instances — all with a tweet.**
|
||
|
||
Social media, particularly Twitter, has built-in engagement mechanisms that could make such a concept interactive and fun. Moreover, it would introduce new audiences to Linux without requiring them to navigate the complexities of traditional terminal-based environments. Instead, they could tweet commands like `neofetch` or `apt update` and have my bot respond with the command’s output.
|
||
|
||
Let’s break down how I made it all work.
|
||
|
||
|
||
|
||
## Phase 1: Setting Up the Infrastructure
|
||
|
||
### Tools and Technologies
|
||
To pull this off, I needed a robust stack of tools and technologies. The project hinged on several core technologies, which I’ll go over here:
|
||
|
||
1. **Node.js**: JavaScript’s asynchronous nature makes it ideal for handling Twitter streams and Docker management, two of the key tasks in this project.
|
||
2. **Docker**: Docker allows us to create isolated Linux environments for each user who interacts with the bot. Containers are lightweight, ephemeral, and easy to manage — perfect for this use case.
|
||
3. **Twit and Twitter API SDK**: Twit and the Twitter SDK provide all the necessary hooks into Twitter’s API, allowing me to listen for mentions, respond to tweets, and manage streams.
|
||
4. **Simple-Dockerode**: This library offers a simplified interface for managing Docker containers directly from Node.js.
|
||
5. **Generate-password**: I needed this to dynamically create user passwords for each container, ensuring secure access.
|
||
|
||
### Setting up Twitter's API Access
|
||
To begin with, I needed access to Twitter’s API. Twitter’s API has been around for years and allows developers to interact with almost every aspect of Twitter — from fetching user data to posting tweets. For my project, I needed the bot to:
|
||
|
||
- **Listen for mentions**: Whenever someone tweets @mybotname, it should trigger a response.
|
||
- **Respond with command outputs**: If the mention contains a command like `neofetch`, the bot needs to execute that command in a user’s container and tweet back the result.
|
||
- **Manage Docker containers**: Each user’s interaction with the bot creates or destroys their own Linux container.
|
||
|
||
I set up the basic configuration in Node.js using Twit and Twitter’s SDK.
|
||
|
||
```javascript
|
||
const config = {
|
||
consumer_key: process.env.TWITTER_API_KEY,
|
||
consumer_secret: process.env.TWITTER_API_SECRET_KEY,
|
||
access_token: process.env.TWITTER_ACCESS_TOKEN,
|
||
access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET,
|
||
};
|
||
const T = new Twit(config);
|
||
|
||
const client = new Client(process.env.TWITTER_BEARER_TOKEN);
|
||
```
|
||
|
||
This snippet initializes Twit and the Twitter SDK with my credentials, which are securely stored in environment variables.
|
||
|
||
### Docker Containers: Isolated Linux Hosts for Every User
|
||
The next big piece of the puzzle was Docker. Docker allows for easy creation and management of Linux containers, making it a perfect fit for this project. Each user interaction would generate an isolated Linux container for them, in which they could run commands.
|
||
|
||
Here’s how the code works to generate and start a container:
|
||
|
||
```javascript
|
||
const Dockerode = require('simple-dockerode');
|
||
const docker = new Dockerode({ socketPath: '/var/run/docker.sock' });
|
||
|
||
function createContainer(userID) {
|
||
docker.createContainer({
|
||
Image: 'ubuntu',
|
||
Cmd: ['/bin/bash'],
|
||
name: `container_${userID}`
|
||
}).then(container => {
|
||
container.start();
|
||
console.log(`Container for user ${userID} started.`);
|
||
});
|
||
}
|
||
```
|
||
|
||
In this code:
|
||
- A new Docker container running Ubuntu is created for each user.
|
||
- The container is named after the user’s Twitter ID to keep things organized.
|
||
- The container is started immediately after creation.
|
||
|
||
To avoid clutter and wasted resources, the containers are ephemeral — they’re automatically destroyed after seven days. This ensures that resources aren’t wasted on inactive containers.
|
||
|
||
|
||
|
||
## Phase 2: The Twitter Bot in Action
|
||
|
||
### Listening for Mentions and Running Commands
|
||
With the infrastructure in place, I had to set up the Twitter bot to continuously monitor tweets for mentions of the bot. The logic here is straightforward:
|
||
|
||
1. **Monitor Twitter for mentions** of the bot using a streaming API.
|
||
2. **Identify valid commands** like `generate`, `neofetch`, `destroy`, etc.
|
||
3. **Execute the command** in the appropriate Docker container.
|
||
4. **Tweet the result back** to the user.
|
||
|
||
Here’s the code that makes this happen:
|
||
|
||
```javascript
|
||
async function getMentionedTweet() {
|
||
const stream = await client.tweets.searchStream({
|
||
"tweet.fields": ["author_id", "id"],
|
||
"expansions": ["referenced_tweets.id.author_id"]
|
||
});
|
||
|
||
for await (const response of stream) {
|
||
if (response.data.text.includes(`@${process.env.BOT_USERNAME}`)) {
|
||
handleCommand(response.data.text, response.data.author_id);
|
||
}
|
||
}
|
||
}
|
||
|
||
async function handleCommand(tweet, userID) {
|
||
if (tweet.includes('generate')) {
|
||
createContainer(userID);
|
||
} else if (tweet.includes('destroy')) {
|
||
destroyContainer(userID);
|
||
} else {
|
||
executeCommandInContainer(userID, tweet);
|
||
}
|
||
}
|
||
```
|
||
|
||
This code does the following:
|
||
- **Listens for tweets** that mention the bot.
|
||
- **Parses the tweet** to determine whether the user wants to generate a new container, destroy an existing one, or run a command.
|
||
- **Delegates the appropriate action**: generating, destroying, or executing a command inside a Docker container.
|
||
|
||
### Command Execution: Let’s Get Interactive
|
||
For me, the real fun began when I allowed users to run Linux commands inside their containers directly from Twitter. To make this happen, I had to set up the bot to execute commands like `neofetch`, `pwd`, and more.
|
||
|
||
Here’s how the bot executes commands inside the container:
|
||
|
||
```javascript
|
||
function executeCommandInContainer(userID, command) {
|
||
const container = docker.getContainer(`container_${userID}`);
|
||
|
||
container.exec({
|
||
Cmd: ['/bin/bash', '-c', command],
|
||
AttachStdout: true,
|
||
AttachStderr: true
|
||
}, (err, exec) => {
|
||
if (err) {
|
||
console.log(err);
|
||
return;
|
||
}
|
||
|
||
exec.start({ Detach: false }, (err, stream) => {
|
||
if (err) {
|
||
console.log(err);
|
||
return;
|
||
}
|
||
|
||
stream.on('data', (data) => {
|
||
const output = data.toString();
|
||
tweetBack(userID, output);
|
||
});
|
||
});
|
||
});
|
||
}
|
||
```
|
||
|
||
In this code:
|
||
- We grab the appropriate Docker container for the user using their Twitter ID.
|
||
- We then execute their command inside the container.
|
||
- Once the command is executed, the output is captured and sent back to the user in a tweet.
|
||
|
||
### Dynamic Password Generation for User Security
|
||
One of the trickier aspects of this project was ensuring that each user’s container was secure. For this, I dynamically generated passwords for each container using the `generate-password` library:
|
||
|
||
```javascript
|
||
const password = generator.generate({
|
||
length: 10,
|
||
numbers: true
|
||
});
|
||
|
||
container.exec({
|
||
Cmd: ['/bin/bash', '-c', `echo 'root:${password}' | chpasswd`]
|
||
});
|
||
```
|
||
|
||
By dynamically generating passwords for each container and assigning them only to the user who created it, I ensured that each container had a unique, secure password. This way, only the container's owner could execute commands or access its shell.
|
||
|
||
|
||
|
||
## Phase 3: Challenges and Solutions
|
||
|
||
### 1. Twitter Rate Limits
|
||
One of the most significant challenges was Twitter’s rate limiting. Twitter’s API has strict limits on how many requests can be made in a specific timeframe. This meant I had to be strategic about how often the bot responded to users. Too many commands, and I’d hit the rate limit, rendering the bot temporarily unusable.
|
||
|
||
**Solution**: I implemented a throttling mechanism to ensure the bot could only respond to a certain number of users per minute. This keeps the bot running smoothly and prevents any downtime due to rate limiting.
|
||
|
||
### 2. Resource Management
|
||
Another challenge was ensuring that Docker containers were efficiently managed. If too many users created containers without proper monitoring, server resources could quickly be exhausted.
|
||
|
||
**Solution**: I implemented a garbage collection system to automatically destroy containers after seven days. This prevents resource leaks and keeps the system running efficiently.
|
||
|
||
```javascript
|
||
function destroyOldContainers() {
|
||
|
||
|
||
docker.listContainers((err, containers) => {
|
||
containers.forEach(container => {
|
||
if (isOlderThanSevenDays(container)) {
|
||
docker.getContainer(container.Id).stop();
|
||
docker.getContainer(container.Id).remove();
|
||
}
|
||
});
|
||
});
|
||
}
|
||
```
|
||
|
||
This simple function checks all active containers, determines their age, and destroys any that are older than seven days.
|
||
|
||
### 3. Running Complex Commands
|
||
Some users wanted to run more complex commands, which generated large outputs that Twitter couldn’t handle (due to character limits). For example, commands like `neofetch` could generate lengthy outputs that couldn’t be tweeted back directly.
|
||
|
||
**Solution**: For large outputs, I utilized an external paste service. If the command output was too large for a tweet, the bot would generate a paste and tweet the link back to the user.
|
||
|
||
```javascript
|
||
if (output.length > 280) {
|
||
const pasteURL = await createPaste(output);
|
||
tweetBack(userID, `Output too long! Check it here: ${pasteURL}`);
|
||
} else {
|
||
tweetBack(userID, output);
|
||
}
|
||
```
|
||
|
||
This way, users could still run complex commands and access their output, even if Twitter’s character limits were restrictive.
|
||
|
||
|
||
|
||
## Phase 4: Going Live and User Reactions
|
||
|
||
Finally, after weeks of coding, testing, and refining, the bot was ready to go live. I made the bot publicly accessible and tweeted out a simple message explaining how to interact with it. Within hours, users were tweeting `generate` to create containers, running `neofetch` to see their system stats, and even running complex commands like `apt update`.
|
||
|
||
The response was overwhelming. People loved the idea of managing a Linux server using only Twitter. The bot provided a fun, interactive way to introduce users to Linux without needing them to understand terminal commands or SSH keys.
|
||
|
||
## At the end of the day...
|
||
|
||
Becoming the first Linux host on Twitter was an incredible journey, blending the power of Docker, the simplicity of Twitter’s API, and a dose of creative coding. What started as a wild idea quickly evolved into a fully-fledged project that allowed people to manage Linux containers through social media. The integration of social media and DevOps opened up fascinating possibilities, and I believe this was just the beginning of what could be done in this space.
|
||
|
||
However, since Elon Musk’s acquisition of Twitter and its transformation into X, the platform's API has become significantly more expensive, making it no longer feasible to continue this project in its original form. The increased cost of access to the API means that projects like this, which rely heavily on interaction through the platform, are now difficult to sustain without a large budget.
|
||
|
||
Despite this setback, I’m excited to have developed this system in the first place. It was an innovative experiment that pushed the boundaries of what can be done with social media and cloud infrastructure. The project taught me a lot about integrating two very different worlds—social media and Linux hosting—and there’s no doubt that the lessons I learned here will fuel future innovations.
|
||
|
||
Even though it’s no longer feasible on X, this experiment will remain a unique milestone in my journey through technology. Who knows what’s next? Maybe the future holds even more exciting possibilities for blending technology with unconventional platforms.
|
||
|
||
And that’s the story of how I became the first Linux host on Twitter! |