Compare commits

..

6 Commits

Author SHA1 Message Date
Oliver
140a712abf flight 2025-08-13 09:23:21 +02:00
Oliver
dfca0844f0 remove host_vars 2025-08-11 05:27:22 -03:00
Oliver
eb172a367f Fixes in plane 2025-08-11 05:16:34 -03:00
Oliver
a84fe3f740 clean 2025-08-10 18:04:34 -03:00
Oliver
4c93fa132f rename ass 2025-08-10 17:43:04 -03:00
Oliver
73d9587e1d docker 2025-08-08 18:22:58 -03:00
43 changed files with 707 additions and 230 deletions

View File

View File

@@ -4,8 +4,14 @@ echo "command: mount_volume <volume>"
echo "alias: set_prod"
export hosts_file="/app/hosts.dev"
export host_vars_dir="/app/host_vars/"
export PS1="\[\e[32m\]\h:\w\$\[\e[0m\] "
df -h .
set_prod() {
export HOSTS_FILE="/app/hosts.all"
echo "HOSTS_FILE set to: $HOSTS_FILE"
export hosts_file="/app/hosts.all"
export host_vars_dir="/app/host_vars/vault/"
echo "LIVE MODE ENABLED !!! "
}

View File

@@ -28,7 +28,7 @@ RUN ssh-keygen -t rsa -b 4096 -f /root/.ssh/id_rsa -N "" && \
chmod 600 /root/.ssh/id_rsa && \
chmod 600 /root/.ssh/config
COPY ass /usr/bin/
COPY rex /usr/bin/
COPY template /usr/bin/
COPY dpush /usr/bin/
COPY create_volume /usr/bin/

View File

@@ -5,21 +5,21 @@ Host dev
Host saopaulo
Hostname 192.168.9.11
Hostname saopaulo
User ansible
IdentityFile /mnt/encrypted_volume/.ssh/saopaulo
Host mumbai
Hostname 192.168.9.17
Hostname mumbai
User ansible
IdentityFile /mnt/encrypted_volume/.ssh/mumbai
Host london
Hostname 192.168.9.15
Hostname london
User ansible
IdentityFile /mnt/encrypted_volume/.ssh/london
Host boston
Hostname 192.168.9.16
Hostname boston
User ansible
IdentityFile /mnt/encrypted_volume/.ssh/boston

View File

@@ -10,7 +10,8 @@ fi
FILE="/data/$1"
MAPPER_NAME="encrypted_volume"
MOUNT_POINT="/mnt/${MAPPER_NAME}"
dd if=/dev/zero of="$FILE" bs=1M count=100
dd if=/dev/zero of="$FILE" bs=1M count=10
echo "Setting up LUKS on $FILE..."
cryptsetup luksFormat "$FILE"

9
alpine/hosts Normal file
View File

@@ -0,0 +1,9 @@
127.0.0.1 dev
::1 dev
192.168.111.209 dev n8n
192.168.9.11 saopaulo
192.168.9.17 mumbai
192.168.9.15 london
192.168.9.16 boston

View File

@@ -1,13 +1,15 @@
#!/bin/bash
if [ "$#" -ne 3 ]; then
echo "Usage: $0 <localfile> <remotefile> <host_vars_dir>"
echo "Usage: $0 <localfile> <remotefile>"
exit 1
fi
localfile="$1"
remotefile="$2"
host_vars_dir="$3"
remotetmp="/var/tmp/4server"
while read -r host; do
echo "Processing host: $host"
@@ -32,7 +34,8 @@ while read -r host; do
done
echo "Copying to $host:$remotefile"
echo "$content" | ssh "$host" "cat > $remotefile"
echo "$content" | ssh "$host" "cat > $remotetmp"
rex doas mv $remotetmp $remotefile
done < "$hosts_file"

View File

@@ -1,163 +0,0 @@
#!/usr/bin/env python3
from fastapi import FastAPI, HTTPException, Depends, Response
from fastapi.security.api_key import APIKeyHeader
from fastapi.responses import RedirectResponse
from pydantic import BaseModel
import psutil
import sqlite3
import subprocess
import os
import sys
import uvicorn
from typing import Optional
# Constants
DB_PATH = "/OD8N/data/contracts/contracts.db"
BIN_PATH = "/OD8N/sbin"
API_KEY = os.getenv("API_KEY", "your-secret-api-key")
# FastAPI app
app = FastAPI()
# Security
api_key_header = APIKeyHeader(name="X-API-Key")
def verify_api_key(key: str = Depends(api_key_header)):
if key != API_KEY:
raise HTTPException(status_code=403, detail="Unauthorized")
# ---------------------- Database ----------------------
def init_db():
"""Initialize the database with containers table."""
os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS containers (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
UUID CHAR(36),
location CHAR(100),
email CHAR(100),
expires DATE,
tags TEXT,
env TEXT
)
''')
conn.commit()
conn.close()
# ---------------------- Models ----------------------
class ContainerModel(BaseModel):
UUID: str
location: str
email: str
expires: str
tags: Optional[str] = None
env: Optional[str] = None
class StartContainerRequest(BaseModel):
uuid: str
email: str
# ---------------------- Routes ----------------------
@app.get("/", include_in_schema=False)
def redirect_to_odoo():
return RedirectResponse(url="https://OD8N.com")
@app.post("/startContainer", dependencies=[Depends(verify_api_key)])
def start_container(request: StartContainerRequest):
try:
result = subprocess.run(
[os.path.join(BIN_PATH, "startContainer"), request.uuid, request.email],
capture_output=True,
text=True,
check=True
)
return {"status": "success", "output": result.stdout}
except subprocess.CalledProcessError as e:
print(f"Error in /startContainer: {e.stderr}", file=sys.stderr)
raise HTTPException(status_code=500, detail=f"Command failed: {e.stderr}")
@app.get("/system", dependencies=[Depends(verify_api_key)])
def get_system_info():
try:
with open("/etc/alpine-release") as f:
version = f.read().strip()
return {"alpine_version": version}
except FileNotFoundError:
raise HTTPException(status_code=404, detail="File not found. Press play on tape")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/resources", dependencies=[Depends(verify_api_key)])
def get_resources():
mem = psutil.virtual_memory()
disk = psutil.disk_usage("/")
return {
"memory": {"total": mem.total, "available": mem.available, "used": mem.used},
"disk": {"total": disk.total, "used": disk.used, "free": disk.free},
"cpu_count": psutil.cpu_count(logical=True),
}
@app.get("/containers", dependencies=[Depends(verify_api_key)])
def get_containers():
result = subprocess.run(['/OD8N/sbin/getContainers'], capture_output=True, text=True)
if result.returncode != 0:
return Response(content='{"error": "Script failed"}', media_type="application/json", status_code=500)
return Response(content=result.stdout, media_type="application/json")
@app.post("/container", dependencies=[Depends(verify_api_key)])
def upsert_container(container: ContainerModel):
try:
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT 1 FROM containers WHERE UUID = ?", (container.UUID,))
exists = cursor.fetchone()
if exists:
cursor.execute("""
UPDATE containers SET
location = ?, email = ?, expires = ?, tags = ?, env = ?
WHERE UUID = ?
""", (
container.location, container.email, container.expires,
container.tags, container.env, container.UUID
))
operation = "update"
else:
cursor.execute("""
INSERT INTO containers (UUID, location, email, expires, tags, env)
VALUES (?, ?, ?, ?, ?, ?)
""", (
container.UUID, container.location, container.email,
container.expires, container.tags, container.env
))
operation = "insert"
conn.commit()
return {"status": "success", "operation": operation}
except Exception as e:
print(f"Error in /container: {e}", file=sys.stderr)
raise HTTPException(status_code=500, detail=str(e))
finally:
conn.close()
# ---------------------- Entry Point ----------------------
if __name__ == "__main__":
print("Version 0.1")
init_db()
uvicorn.run(app, host="10.5.0.1", port=8888)

15
app/etc/.bashrc Normal file
View File

@@ -0,0 +1,15 @@
# ~/.bashrc
echo "command: mount_volume <volume>"
echo "alias: set_prod"
export hosts_file="/app/hosts.dev"
export PS1="\[\e[32m\]\h:\w\$\[\e[0m\] "
df -h .
set_prod() {
export HOSTS_FILE="/app/hosts.all"
echo "HOSTS_FILE set to: $HOSTS_FILE"
}

30
app/etc/certs/dev.crt Normal file
View File

@@ -0,0 +1,30 @@
-----BEGIN CERTIFICATE-----
MIIFNzCCAx+gAwIBAgIUCIJuU/7oPy1PrksppEPukIs4MfgwDQYJKoZIhvcNAQEL
BQAwEjEQMA4GA1UEAwwHKi5sb2NhbDAeFw0yNTA4MDgyMTMyMzlaFw0yNjA4MDgy
MTMyMzlaMBIxEDAOBgNVBAMMByoubG9jYWwwggIiMA0GCSqGSIb3DQEBAQUAA4IC
DwAwggIKAoICAQC+uBU5mo8h8LK00Hrw9AtaPI2yXBaVh5S8KrAJ0eoUSxc0gg7q
dwsD9+boyaDbiePcllTLvmIKqX8K2TbiucEaqNGzJauop0+UZjjCQrzuq+cD6xPh
+1bzcWN+oLubUtv4wi3mRNCtP56YyM4c72OweXB9Mhi9Z8e2caTjCLdcCS10i5Oy
NWYZFhnjBxXJoElTt4HZFLDj60Iqi9thVGO4virv7VBwOvAKaCgOOuagPtISgHO7
1t1hV9TNTHRcE37xpOZT6moPsEBitkszwPx24SgATGrG5J8UbDJ5EdY+kA4wD0mU
hi9pUWaRlKWQjqRRszvsSnbQUPHORHSUFFpycworeNUBCmTs5jm0/+RqI4TLTUX6
ZbJ6azgGpgbJtMbMlywW1Yuy9ACrSP/jncKekiR+0uQ5s+y2crT+aeuzHsyMtUUn
TI1ExsOE/QWGH7MV298D+jvSSWg4WTf3dzAiFsDxP4JtDZ1NmDwm6Pjmano1Y57g
uU++4RvYN6YKxDnkcWXIZFpUvW+dr7oLZaOcqwCx4KVCFo4e2qqigYgWgz8r05iE
ngj7UZO70n3dZrkL4Iu2tFATHLBy1SYZIu3ewZodOeK54q63bYtVFj7ECAE4Eb7J
6DgjOtN3GH9E2aKMjzFRvWzItRufLWIycPN/tAOh6dOPuX9oZQf71sxe3wIDAQAB
o4GEMIGBMB0GA1UdDgQWBBSGznETTeVc5FVFEGbdVUzR5jfQADAfBgNVHSMEGDAW
gBSGznETTeVc5FVFEGbdVUzR5jfQADAPBgNVHRMBAf8EBTADAQH/MC4GA1UdEQQn
MCWCCWFwcC5sb2NhbIIJYXBpLmxvY2Fsgg10cmFlZmlrLmxvY2FsMA0GCSqGSIb3
DQEBCwUAA4ICAQCl+LRB+6Rz0EJFbZnhLWvumY2KegS+QkB6YUDycJIuq/2Q9RWB
Z0yV94asZcvHE21/BHhnMk4Qa2PsQn8gQIGCAhj+/2DVt5mGwWVgoes1gtAg6okH
YYKhTljjfpMFqyp/lyzanzF4VdnhzDKpaRLxKwuCf0xe9V03S4/fri/tVjxpjUyc
eaTgfDlzJgQu2rZZz8dG7fltCEhl9gBGbQ3WWaSDYOW49UXqS3LR0eBZ4s/RAG7Z
LiBIKzOFQjLplaODsCOpOguzRfL6O2WXDADbuh7XAQmmhkfsuruPvP/5E1G1hb6K
khsKyiYo4WLpdGJACezN/jmQVcqULz8iLI/jRaoT5g3dwvBkzyolIF+A6a33D3Ph
vQd5ta6BT/EWTBp4T5MSyvd03rkqV0oCHeF+wTQ3iR4b5jrxlVtqCFlsK32NrB9e
ZAboJitgxLgs6ZKXhoxCGjtZdpgYyxqgEOtJazzNitNxB8Xyb3hCc2t7VPpRUfUa
gyddQFd1yZmhPZqhugXI+LL7xO7HHyrz+CwqeWkObJNDRIe6Me4Rxo9H0ZQfjLa1
fAgxubtAsGr0AwQSg3X/PamEhVdjvCBCtadgHQZQLaP7ilPBcER/xBQ1jbI1LYzF
BTCypCFykXbDxxbOwzhwRLoUHzWS2XAYT7vOHE60AokMKwArz9s3Hu+wUg==
-----END CERTIFICATE-----

52
app/etc/certs/dev.key Normal file
View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
YV/U3ImFkT12e6nwfgrMRfQCZrRsp9g=
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,21 @@
#!/sbin/openrc-run
name="4server-api"
description="4server API Service"
command="/4server/sbin/api"
command_args=""
pidfile="/run/${RC_SVCNAME}.pid"
command_background="yes"
output_log="/4server/data/api.log"
error_log="/4server/data/api.log"
depend() {
need net
use logger dns
after firewall
}

View File

@@ -1 +1,4 @@
API_KEY=4h6lDzAOVksuCqmhEB3
hostname="dev"
nebula_key="123"
nebula_cert="456"

View File

39
app/onboarding Executable file
View File

@@ -0,0 +1,39 @@
#!/bin/bash
template templates/hosthostname /etc/hostname
# ass swap file ????
# ------ create user 4server
# ------ disable root user and login
# ----- install nabula
echo "prsync nebula bin"
prsync -h "$hosts_file" -avz ./templates/nebula/nebula /4server/nebula
rex doas mv /4server/nebula /usr/bin/
rex doas mkdir -p /etc/nebula
rex doas chmod 700 /etc/nebula
template templates/nebula/nebula.yml /etc/nebula/config.yml
template templates/nebula/host.key /etc/nebula/host.key
template templates/nebula/host.crt /etc/nebula/host.crt
rex doas chmod 700 /etc/nebula
template templates/init.d/nebula /etc/init.d/nebula
rex doas chmod 0755 /etc/init.d/nebula
rex doas chown root:root /etc/init.d/nebula
rex doas rc-update add nebula default
rex doas rc-service nebula restart
template templates/init.d/ping_service /etc/init.d/ping_service
rex doas chmod 0755 /etc/init.d/ping_service
rex doas chown root:root /etc/init.d/ping_service
rex doas rc-update add ping_service default
rex doas rc-service ping_service restart
#! ----------- install ufe
- ssh, 8080 only on nebula
- only 80, 443 to the world

View File

@@ -1,4 +1,2 @@
#!/bin/ass
doas apk update
doas apk upgrade
#!/bin/bash
rex doas restart

163
app/sbin/api Executable file
View File

@@ -0,0 +1,163 @@
#!/usr/bin/env python3
from fastapi import FastAPI, HTTPException, Depends, Response
from fastapi.security.api_key import APIKeyHeader
from fastapi.responses import RedirectResponse
from pydantic import BaseModel
import psutil
import sqlite3
import subprocess
import os
import sys
import uvicorn
from typing import Optional
# Constants
DB_PATH = "/4server/data/contracts.db"
BIN_PATH = "/4server/sbin"
API_KEY = os.getenv("API_KEY", "your-secret-api-key")
VERSION = "API: 0.0.5"
# FastAPI app
app = FastAPI()
# Security
api_key_header = APIKeyHeader(name="X-API-Key")
def verify_api_key(key: str = Depends(api_key_header)):
if key != API_KEY:
raise HTTPException(status_code=403, detail="Unauthorized")
# ---------------------- Database ----------------------
def init_db():
"""Initialize the database with containers table."""
os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS containers (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
UUID CHAR(50),
email CHAR(100),
expires DATE,
tags TEXT,
env TEXT,
affiliate char(30),
image char(50),
history text,
comment text,
domains text,
status char (20).
created DATE,
bump DATE
)
''')
conn.commit()
conn.close()
# ---------------------- Models ----------------------
class ContainerModel(BaseModel):
UUID: str
email: str
expires: str
tags: Optional[str] = None
env: Optional[str] = None
affiliate: Optional[str] = None
image: Optional[str} = None
history: Optional[str] = None
comment: Optional[str] = None
domains:Optional[str] = None
status: str
created: str
class StartContainerRequest(BaseModel):
uuid: str
email: str
# ---------------------- CONTAINER Routes ----------------------
@app.get("/", include_in_schema=False)
def redirect_to_odoo():
return RedirectResponse(url="https://ODOO4PROJECTS.com")
@app.post("/container/update", dependencies=[Depends(verify_api_key)])
def update_container(request: UpdateContainerRequest):
--> Insert the new container into the database. Create, if container does not exist
@app.post("/container/start", dependencies=[Depends(verify_api_key)])
def start_container(request: StartContainerRequest):
--> refactor, so that only the container is is given in the request. the shell script BIN_PATH/startContainer is called withtge containerid as parameter
@app.post("/container/stop", dependencies=[Depends(verify_api_key)])
def stop_container(request: StopContainerRequest):
--> refactor, so that only the container is is given in the request. the shell script BIN_PATH/stopContainer is called withtge containerid as parameter
@app.post("/container/nuke", dependencies=[Depends(verify_api_key)])
def nuke_container(request: StopContainerRequest):
--> refactor, so that only the container is is given in the request.
when the status of the database is "nuke" then
the shell script BIN_PATH/nukeContainer is called withtge containerid as parameter
@app.post("/container/info", dependencies=[Depends(verify_api_key)])
def info_container(request: InfoContainerRequest):
--> refactor: When no container id is given, query all containers from the database. when a containeris is given, just select that one. Return the result
--> create an endpoint that changes the container image to the latest version of that image /container/bump besides updating the container image, also update the SQL for this container and put the current date into "bump"
--> add /container/quota return the disk and ram usage of this container. I think you can obtain this from docker
# ------------------------ SYSTEM Routes
@app.get("/system/containers", dependencies=[Depends(verify_api_key)])
def get_containers():
result = subprocess.run([BIN_PATH+'/getContainers'], capture_output=True, text=True)
if result.returncode != 0:
return Response(content='{"error": "Script failed"}', media_type="application/json", status_code=500)
return Response(content=result.stdout, media_type="application/json")
--> create an endpoint that lkists all docker images available on the system /system/images
@app.get("/system/info", dependencies=[Depends(verify_api_key)])
def get_system_info():
return all INFOas JSON
in this function add last_update and return the content of /4server/data/update
if this file does not exist return NONE
also add the latest bump date of all images in the database
return the VERSION as well.
try:
with open("/etc/alpine-release") as f:
version = f.read().strip()
return {"alpine_version": version}
except FileNotFoundError:
raise HTTPException(status_code=404, detail="File not found. Press play on tape")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/system/resources", dependencies=[Depends(verify_api_key)])
def get_resources():
--> consolidate this API into /system/info
mem = psutil.virtual_memory()
disk = psutil.disk_usage("/")
return {
"memory": {"total": mem.total, "available": mem.available, "used": mem.used},
"disk": {"total": disk.total, "used": disk.used, "free": disk.free},
"cpu_count": psutil.cpu_count(logical=True),
}
--> create an endpoint that docker pulls all containers /system/pull
# ---------------------- Entry Point ----------------------
if __name__ == "__main__":
print(VERSION)
init_db()
uvicorn.run(app, host="10.5.0.1", port=8888)

BIN
app/sbin/nebula Executable file

Binary file not shown.

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
exec > /OD8N/data/startContainer.log 2>&1
exec > /4server/data/startContainer.log 2>&1
echo "$(date '+%Y-%m-%d %H:%M') - startContainer $1"
@@ -9,11 +9,11 @@ CONTAINER_NAME="$1"
# Get the hostname of the machine
HOSTNAME=$(hostname)
mkdir -p /OD8N/data/${CONTAINER_NAME}/n8n
mkdir -p /OD8N/data/${CONTAINER_NAME}/data
mkdir -p /4server/data/${CONTAINER_NAME}/n8n
mkdir -p /4server/data/${CONTAINER_NAME}/data
sudo chmod 777 /OD8N/data/${CONTAINER_NAME}/n8n
sudo chmod 777 /OD8N/data/${CONTAINER_NAME}/data
sudo chmod 777 /4server/data/${CONTAINER_NAME}/n8n
sudo chmod 777 /4server/data/${CONTAINER_NAME}/data
# Stop the container if it exists
@@ -37,8 +37,8 @@ docker run -d \
-e NODE_ENV=production \
-e WEBHOOK_URL="https://${CONTAINER_NAME}.od8n.com/" \
-e GENERIC_TIMEZONE="UTC-3" \
-v "/OD8N/data/${CONTAINER_NAME}/n8n:/home/node/.n8n" \
-v "/OD8N/data/${CONTAINER_NAME}/data:/data" \
-v "/4server/data/${CONTAINER_NAME}/n8n:/home/node/.n8n" \
-v "/4server/data/${CONTAINER_NAME}/data:/data" \
--label "traefik.enable=true" \
--label "traefik.http.routers.${CONTAINER_NAME}.rule=Host(\`${CONTAINER_NAME}.od8n.com\`)" \
--label "traefik.http.routers.${CONTAINER_NAME}.entrypoints=web,websecure" \
@@ -49,4 +49,4 @@ docker run -d \
n8nio/n8n:latest
echo "Done $1"
echo "Started $1"

14
app/sbin/startContainer Normal file
View File

@@ -0,0 +1,14 @@
this script gets a container UUID
Wtrite a bash script, that gets all info out off the Sqlite3 Database usind the UUID and stores the values in environment variables
setr the BIN_BATH to /4srver/sbin/
the uuid looks like xxx-xxx-xxxx-xxxx-xxxx-....
get the second number
When the number is 001 call the script BIN_PATH/start/n8n
When the number is 002 call the sctipr BIN_ÜATH/start/ODOO18
WHen the number is 003 call the script BIN_PATH/start/ODOO19

View File

@@ -0,0 +1,41 @@
services:
beedb:
image: postgres:16
restart: always
environment:
- POSTGRES_DB=postgres
- POSTGRES_PASSWORD=deradmin
- POSTGRES_USER=deradmin1
volumes:
- /4server/data/postgres:/var/lib/postgresql/data/
- /4server/data/pg_backup/:/BACKUP/
networks:
4projects:
ipv4_address: 10.5.0.200
traefik:
image: docker.io/library/traefik:3.1
container_name: traefik
ports:
- 80:80
- 443:443
- 8080:8080
volumes:
- /run/docker.sock:/run/docker.sock:ro
- /4server/data/traefik/config/traefik/etc:/etc/traefik
- /4server/data/traefik/certs:/certs
- /4server/data/traefik/traefik-logs:/var/log/traefik
networks:
- 4projects
restart: unless-stopped
networks:
4projects:
driver: bridge
ipam:
config:
- subnet: 10.5.0.0/16
gateway: 10.5.0.1
ip_range: 10.5.0.0/26

1
app/templates/hostname Normal file
View File

@@ -0,0 +1 @@
{{hostname}}

2
app/templates/hosts Normal file
View File

@@ -0,0 +1,2 @@
127.0.0.1 {{hostname}} localhost
10.5.0.200 beedb

View File

@@ -0,0 +1,20 @@
#!/sbin/openrc-run
name="4server-api"
description="4server API Service"
command="/4server/sbin/api"
command_args=""
pidfile="/run/${RC_SVCNAME}.pid"
command_background="yes"
output_log="/4server/data/api.log"
error_log="/4server/data/api.log"
depend() {
need net
use logger dns
after firewall
}

12
app/templates/init.d/nebula Executable file
View File

@@ -0,0 +1,12 @@
#!/sbin/openrc-run
command="/usr/bin/nebula"
command_args="-config /etc/nebula/config.yml"
command_background="yes"
pidfile="/run/nebula.pid"
name="nebula"
depend() {
need localmount
after networking
}

17
app/templates/init.d/ping_check Executable file
View File

@@ -0,0 +1,17 @@
#!/sbin/openrc-run
description="Ping 192.168.9.1 every minute"
pidfile="/run/ping_check.pid"
start() {
ebegin "Starting ping_check service"
start-stop-daemon --start --background --make-pidfile --pidfile $pidfile --exec /bin/sh -- -c "while true; do ping -c 1 192.168.9.1; sleep 60; done"
eend $?
}
stop() {
ebegin "Stopping ping_check service"
start-stop-daemon --stop --pidfile $pidfile
eend $?
}

View File

@@ -0,0 +1,69 @@
pki:
ca: /etc/nebula/ca.crt
cert: /etc/nebula/host.crt
key: /etc/nebula/host.key
static_host_map:
"192.168.9.1": ["167.71.79.60:4242"]
lighthouse:
am_lighthouse: false
interval: 60
hosts:
listen:
host: 0.0.0.0
port: 4242
punchy:
punch: true
relay:
am_relay: false
use_relays: true
tun:
disabled: false
dev: nebula1
drop_local_broadcast: false
drop_multicast: false
tx_queue: 500
mtu: 1300
routes:
#- mtu: 8800
# route: 10.0.0.0/16
unsafe_routes:
logging:
level: info
format: text
firewall:
outbound_action: drop
inbound_action: drop
conntrack:
tcp_timeout: 12m
udp_timeout: 3m
default_timeout: 10m
outbound:
- port: any
proto: any
host: any
inbound:
- port: any #ping
proto: icmp
host: any
- port: 22 #GIT
proto: tcp
groups:
- admin
- ansible
- port: 8080
proto: tcp
groups:
-admin

View File

@@ -1,25 +0,0 @@
#!/sbin/openrc-run
name="od8n-api"
description="OD8N API Service"
command="/OD8N/sbin/api"
command_args=""
pidfile="/run/${RC_SVCNAME}.pid"
command_background="yes"
if [ -f /etc/od8n ]; then
. /etc/od8n
export $(cut -d= -f1 /etc/od8n)
fi
output_log="/OD8N/data/api.log"
error_log="/OD8N/data/api.log"
depend() {
need net
use logger dns
after firewall
}

View File

@@ -0,0 +1,3 @@
https://dl-cdn.alpinelinux.org/alpine/v3.22/main
https://dl-cdn.alpinelinux.org/alpine/v3.22/community

102
app/templates/traefik.yaml Normal file
View File

@@ -0,0 +1,102 @@
global:
checkNewVersion: false
sendAnonymousUsage: false
accesslog:
filePath: /var/log/traefik/access.log
api:
dashboard: true
disableDashboardAd: true
insecure: true
entryPoints:
web:
address: :80
# -- (Optional) Redirect all HTTP to HTTPS
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
# http:
# middlewares:
# - crowdsec-bouncer@file
address: :443
transport:
respondingTimeouts:
readTimeout: 0
writeTimeout: 0
idleTimeout: 42
# -- (Optional) Add custom Entrypoint
# custom:
# address: :8080
# -- Configure your CertificateResolver here...
certificatesResolvers:
# staging:
# acme:
# email: your-email@example.com
# storage: /etc/traefik/certs/acme.json
# caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
# httpChallenge:
# entryPoint: web
production:
acme:
email: oliver@odoo4projects.com
storage: /certs/acme.json
caServer: "https://acme-v02.api.letsencrypt.org/directory"
httpChallenge:
entryPoint: web
# -- (Optional) Disable TLS Cert verification check
# serversTransport:
# insecureSkipVerify: true
# -- (Optional) Overwrite Default Certificates
# tls:
# stores:
# default:
# defaultCertificate:
# certFile: /etc/traefik/certs/cert.pem
# keyFile: /etc/traefik/certs/cert-key.pem
# -- (Optional) Disable TLS version 1.0 and 1.1
# options:
# default:
# minVersion: VersionTLS12
providers:
docker:
# -- (Optional) Enable this, if you want to expose all containers automatically
exposedByDefault: true
file:
directory: /etc/traefik
watch: true
http:
middlewares:
crowdsec-bouncer:
forwardauth:
address: http://bouncer-traefik:8080/api/v1/forwardAuth
trustForwardHeader: true
routers:
saopaulo-router:
rule: "Host(`dev.local`)"
service: saopaulo-service
entryPoints:
- websecure
tls:
certResolver: production
services:
saopaulo-service:
loadBalancer:
servers:
- url: "http://10.5.0.1:8888"

View File

@@ -0,0 +1,8 @@
write a curl request that creatrs a container with
a uuid starting with 000-001-....
email o.arnold@projektbox.de
domain n8n.local
and the rest with sane info

5
app/test/start_container Normal file
View File

@@ -0,0 +1,5 @@
start the container
000-001-
add a random uuid

3
app/todo.txt Normal file
View File

@@ -0,0 +1,3 @@
create user
set bash as default user

View File

@@ -1,25 +1,46 @@
#!/bin/bash
ass doas mkdir -p /OD8N
ass doas chmod 777 /OD8N
ass mkdir -p /OD8N/data
### SYSTEM SETUP
rex doas mkdir -p /4server
rex doas chmod 777 /4server
rex mkdir -p /4server/data
template templates/hosts /etc/hosts
ass doas apk update
ass doas apk upgrade
ass doas apk add jq rsync mc vim
### PACKAGES
template templates/repositories /etc/apk/repositories
rex doas apk update && upgrade
rex doas apk add jq rsync mc vim docker docker-compose htop linux-lts sqlite bash postgresql-16-client
prsync -h "$hosts_file" -avz ./bin/OD8N/sbin/ /OD8N/sbin/
### own bins
prsync -h "$hosts_file" -avz ./sbin/ /4server/sbin/
### API
#INSTALL API KEYS
template templates/od8n /OD8N/od8n ./host_vars
ass doas mv /OD8N/od8n /etc/od8n
template templates/4server /etc/4server
#INSTALL API SERVICE
template templates/od8n-api /OD8N/od8n-api ./host_vars/
ass doas mv /OD8N/od8n-api /etc/init.d/od8n-api
ass doas chmod 0755 /etc/init.d/od8n-api
ass doas chown root:root /etc/init.d/od8n-api
ass doas rc-update add od8n-api default
ass doas rc-service od8n-api restart
ass doas rc-update add od8n-api default
template templates/init.d/4server-api /etc/init.d/4server-api:
rex doas chmod 0755 /etc/init.d/4server-api
rex doas chown root:root /etc/init.d/4server-api
rex doas rc-update add 4server-api default
rex doas rc-service 4server-api restart
### Infrastructure
##### Docker
rex doas rc-service docker start
rex doas rc-update add docker boot
rex mkdir -p /4server/data/treafik/config/
template templates/traefik.yaml /4server/data/traefik/config/traefik.yaml
rex mkdir -p /4server/data/traefik/etc/certs
prsync -h "$hosts_file" -avz ./etc/certs/* /4server/data/traefik/etc/certs/
template templates/docker-compose.yml /4server/docker-compose.yml
rex doas docker-compose -f /4server/docker-compose.yml up -d

View File

@@ -4,7 +4,6 @@ services:
context: ./alpine
volumes:
- ./app:/app
- ./od8n:/app/od8n
tty: true
privileged: true

View File

@@ -1,6 +1,14 @@
#/bin/bash
cp alpine.qcow2 tmp/alpine.qcow2
#cp alpine.qcow2 tmp/alpine.qcow2
sudo qemu-system-x86_64 \
-m 1024M \
-hda tmp/alpine.qcow2 \
-boot d \
-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::80-:80,hostfwd=tcp::443-:443,hostfwd=tcp::8080-:8080 \
-device e1000,netdev=net0 \
-enable-kvm \
-cpu host
qemu-system-x86_64 -m 1024M -hda tmp/alpine.qcow2 -boot d -netdev user,id=net0,hostfwd=tcp::2222-:22 -device e1000,netdev=net0 -enable-kvm -cpu host