Skip to content
This repository was archived by the owner on Nov 24, 2025. It is now read-only.

Commit 57e0f16

Browse files
committed
added README.md reff://REDDIT
1 parent da37d22 commit 57e0f16

6 files changed

Lines changed: 315 additions & 44 deletions

File tree

LICENSE.txt

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
GNU GENERAL PUBLIC LICENSE
2+
Version 3, 29 June 2007
3+
4+
Copyright (C) 2024 Akshat Kotpalliwar <https://github.com/IntegerAlex/flexr>
5+
6+
This program is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
This program is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License
17+
along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
19+
TERMS AND CONDITIONS
20+
21+
0. Definitions.
22+
23+
"This License" refers to version 3 of the GNU General Public License.
24+
25+
"Copyright" also means copyright-like laws that apply to other kinds of
26+
works, such as semiconductor masks.
27+
28+
"The Program" refers to any copyrightable work licensed under this
29+
License. Each licensee is addressed as "you". "Licensees" and
30+
"recipients" may be individuals or organizations.
31+
32+
To "modify" a work means to copy from or adapt all or part of the work
33+
in a fashion requiring copyright permission, other than the making of an
34+
exact copy. The resulting work is called a "modified version" of the
35+
earlier work or a work "based on" the earlier work.
36+
37+
A "covered work" means either the unmodified Program or a work based
38+
on the Program.
39+
40+
To "propagate" a work means to do anything with it that, without
41+
permission, would make you directly or secondarily liable for
42+
infringement under applicable copyright law, except executing it on a
43+
computer or modifying a private copy. Propagation includes copying,
44+
distribution (with or without modification), making available to the
45+
public, and in some countries other activities as well.
46+
47+
To "convey" a work means any kind of propagation that enables other
48+
parties to make or receive copies. Mere interaction with a user through
49+
a computer network, with no transfer of a copy, is not conveying.
50+
51+
An interactive user interface displays "Appropriate Legal Notices"
52+
to the extent that it includes a convenient and prominently visible
53+
feature that (1) displays an appropriate copyright notice, and (2)
54+
tells the user that there is no warranty for the work (except to the
55+
extent that warranties are provided), that licensees may convey the
56+
work under this License, and how to view a copy of this License.
57+
58+
[Complete GPL-3.0 License Text: https://www.gnu.org/licenses/gpl-3.0.txt]

README.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Flexr
2+
3+
> A self-hosted platform that automates containerization and deployment of Node.js applications with automatic SSL, DNS management, and container orchestration.
4+
5+
[![License: GPL-3.0](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
6+
[![TypeScript](https://img.shields.io/badge/TypeScript-5.0-blue)](https://www.typescriptlang.org/)
7+
[![Node.js Version](https://img.shields.io/badge/node-v18%2B-green)](https://nodejs.org)
8+
9+
## Overview
10+
11+
Flexr simplifies application deployment by automating container builds, SSL certification, DNS configuration, and deployment monitoring. It integrates with GitHub for seamless deployment workflows and provides real-time deployment status updates.
12+
13+
## Features
14+
15+
- **Automated Deployment Pipeline**
16+
- Container build automation with Podman
17+
- Automatic SSL certificate generation via Certbot
18+
- Dynamic DNS configuration through Cloudflare
19+
- NGINX reverse proxy setup
20+
21+
- **Monitoring & Management**
22+
- Real-time deployment status
23+
- Container health monitoring
24+
- Resource usage tracking
25+
- Deployment history
26+
27+
- **Security**
28+
- Auth0 integration for authentication
29+
- Automatic SSL/TLS certification
30+
- Secure proxy configuration
31+
- Container isolation
32+
33+
## Prerequisites
34+
35+
- Node.js (v18+) & TypeScript
36+
- Podman
37+
- PostgreSQL
38+
- Redis
39+
- NGINX
40+
- Auth0 Account
41+
- Cloudflare Account
42+
43+
## Environment Variables
44+
45+
```bash
46+
# Auth0 Configuration
47+
SECRET=your_auth0_secret
48+
BASEURL=your_base_url
49+
CLIENTID=your_auth0_client_id
50+
ISSUERBASEURL=your_auth0_issuer_url
51+
52+
# Cloudflare Configuration
53+
CLOUDFLARE_ZONE_ID=your_zone_id
54+
CLOUDFLARE_EMAIL=your_email
55+
CLOUDFLARE_GLOBAL_TOKEN=your_api_token
56+
57+
# Certbot Configuration
58+
CERTBOT_EMAIL=your_email
59+
```
60+
61+
## Quick Start
62+
63+
1. Clone the repository:
64+
```bash
65+
git clone https://github.com/IntegerAlex/flexr.git
66+
cd flexr
67+
```
68+
69+
2. Install dependencies:
70+
```bash
71+
npm install
72+
```
73+
74+
3. Build TypeScript:
75+
```bash
76+
npm run build
77+
```
78+
79+
4. Start development server:
80+
```bash
81+
npm run dev
82+
```
83+
84+
## API Reference
85+
86+
### Deployment Endpoints
87+
88+
```typescript
89+
POST /v1/runContainer
90+
{
91+
"userName": "string",
92+
"projectName": "string",
93+
"repoLink": "string",
94+
"entryPoint": "string",
95+
"buildCommand": "string",
96+
"runCommand": "string"
97+
}
98+
```
99+
100+
### Management Endpoints
101+
102+
- `GET /v1/health` - System health check
103+
- `GET /v1/repositories` - List GitHub repositories
104+
- `GET /v1/profile` - User profile information
105+
- `GET /htmx/deployments` - Deployment history
106+
107+
## Architecture
108+
109+
- **Frontend**: HTMX + Vanilla JavaScript
110+
- **Backend**: TypeScript & Express.js
111+
- **Database**: PostgreSQL + Redis
112+
- **Container**: Podman
113+
- **Proxy**: NGINX
114+
- **DNS**: Cloudflare API
115+
- **SSL**: Certbot
116+
117+
## Contributing
118+
119+
1. Fork the repository
120+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
121+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
122+
4. Push to the branch (`git push origin feature/amazing-feature`)
123+
5. Open a Pull Request
124+
125+
## License
126+
127+
This program is free software: you can redistribute it and/or modify
128+
it under the terms of the GNU General Public License as published by
129+
the Free Software Foundation, either version 3 of the License, or
130+
(at your option) any later version.
131+
132+
---
133+
Made with ❤️ by Akshat Kotpalliwar (alias IntegerAlex on GitHub)

package.json

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
{
2-
"name": "cloudrun",
2+
"name": "flexr",
33
"version": "1.0.0",
4-
"main": "index.js",
4+
"main": "dist/server/setup.js",
55
"scripts": {
6-
"dev": "node dist/server/setup.js",
7-
"build": "tsc"
6+
"dev": "nodemon --exec ts-node server/setup.ts",
7+
"build": "tsc",
8+
"start": "node dist/server/setup.js",
9+
"lint": "eslint . --ext .ts",
10+
"test": "jest",
11+
"db:migrate": "node dist/db/create.js"
812
},
9-
"keywords": [],
10-
"author": "",
11-
"license": "ISC",
13+
"keywords": [
14+
"deployment",
15+
"containers",
16+
"podman",
17+
"nodejs"
18+
],
19+
"author": "Akshat Kotpalliwar",
20+
"license": "GPL-3.0",
1221
"description": "",
1322
"dependencies": {
1423
"cloudflare": "^3.5.0",
@@ -18,12 +27,23 @@
1827
"express-openid-connect": "^2.17.1",
1928
"htmx": "^0.0.2",
2029
"pg": "^8.12.0",
21-
"redis": "^4.7.0"
30+
"redis": "^4.7.0",
31+
"winston": "^3.11.0",
32+
"helmet": "^7.1.0",
33+
"compression": "^1.7.4"
2234
},
2335
"devDependencies": {
2436
"@types/cors": "^2.8.17",
2537
"@types/express": "^4.17.21",
2638
"@types/node": "^20.14.12",
27-
"@types/pg": "^8.11.6"
39+
"@types/pg": "^8.11.6",
40+
"@types/jest": "^29.5.0",
41+
"@typescript-eslint/eslint-plugin": "^6.0.0",
42+
"@typescript-eslint/parser": "^6.0.0",
43+
"eslint": "^8.57.0",
44+
"jest": "^29.7.0",
45+
"nodemon": "^3.0.0",
46+
"ts-jest": "^29.1.0",
47+
"ts-node": "^10.9.0"
2848
}
2949
}

server/config.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
export const config = {
2+
server: {
3+
port: process.env.PORT || 8080,
4+
baseUrl: process.env.BASEURL || 'http://localhost:8080'
5+
},
6+
auth: {
7+
secret: process.env.SECRET,
8+
clientId: process.env.CLIENTID,
9+
issuerBaseUrl: process.env.ISSUERBASEURL,
10+
authRequired: false,
11+
auth0Logout: true,
12+
scope: 'openid profile'
13+
},
14+
cloudflare: {
15+
zoneId: process.env.CLOUDFLARE_ZONE_ID,
16+
email: process.env.CLOUDFLARE_EMAIL,
17+
token: process.env.CLOUDFLARE_GLOBAL_TOKEN
18+
},
19+
certbot: {
20+
email: process.env.CERTBOT_EMAIL
21+
},
22+
redis: {
23+
url: process.env.REDIS_URL || 'redis://localhost:6379'
24+
},
25+
postgres: {
26+
url: process.env.DATABASE_URL || 'postgresql://localhost:5432/flexhost'
27+
}
28+
};

server/setup.ts

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -27,41 +27,50 @@ app.post('/v1/runContainer', async (req, res) => {
2727
projectName,
2828
repoLink,
2929
entryPoint,
30-
buildCommand,
31-
runCommand,
30+
buildCommand = 'npm install',
31+
runCommand = 'node',
3232
} = req.body as {
3333
userName: string;
3434
projectName: string;
3535
repoLink: string;
3636
entryPoint: string;
37-
buildCommand: string;
38-
runCommand: string;
37+
buildCommand?: string;
38+
runCommand?: string;
3939
};
4040

41-
if (!userName || !projectName || !repoLink || !entryPoint) {
42-
return res.status(400).send('Invalid Request');
41+
const missingFields = [];
42+
if (!userName) missingFields.push('userName');
43+
if (!projectName) missingFields.push('projectName');
44+
if (!repoLink) missingFields.push('repoLink');
45+
if (!entryPoint) missingFields.push('entryPoint');
46+
47+
if (missingFields.length > 0) {
48+
return res.status(400).json({
49+
error: 'Missing required fields',
50+
fields: missingFields
51+
});
4352
}
4453

4554
try {
46-
console.log(`Creating image for project: ${projectName}`);
47-
const imageName = await createImage(
48-
userName,
49-
projectName,
50-
repoLink,
51-
entryPoint,
52-
buildCommand,
53-
runCommand
54-
);
55-
56-
console.log(`Running container for image: ${imageName}`);
57-
const containerId = await runContainer(userName, projectName);
58-
59-
console.log(`Container running with ID: ${containerId}`);
60-
database.dbRedisSet(userName.toLowerCase(), true);
61-
res.json({ containerId: containerId });
55+
const [imageName, containerId] = await Promise.all([
56+
createImage(userName, projectName, repoLink, entryPoint, buildCommand, runCommand),
57+
runContainer(userName, projectName)
58+
]);
59+
60+
console.log(`Container ${containerId} running with image: ${imageName}`);
61+
62+
await database.dbRedisSet(userName.toLowerCase(), true);
63+
res.json({
64+
containerId,
65+
imageName,
66+
status: 'deployed'
67+
});
6268
} catch (err) {
63-
console.error(`Error: ${err.message}`);
64-
res.status(500).send('Error running container');
69+
console.error(`Deployment error: ${err.message}`);
70+
res.status(500).json({
71+
error: 'Deployment failed',
72+
message: err.message
73+
});
6574
}
6675
});
6776

@@ -130,6 +139,18 @@ app.get('/v1/repositories', (req, res) => {
130139
});
131140
});
132141

142+
// Add error handling middleware
143+
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
144+
console.error(err.stack);
145+
res.status(500).send('Something broke!');
146+
});
147+
148+
// Add request logging middleware
149+
app.use((req: express.Request, res: express.Response, next: express.NextFunction) => {
150+
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
151+
next();
152+
});
153+
133154
app.listen(8080, () => {
134155
console.log('Server is running on port 8080');
135156
});

0 commit comments

Comments
 (0)