upload current sources
Some checks failed
Test / test (push) Has been cancelled

This commit is contained in:
2025-12-14 07:02:02 +00:00
commit cd78becb97
35 changed files with 1283 additions and 0 deletions

45
.github/workflows/renovate.yml vendored Executable file
View File

@@ -0,0 +1,45 @@
name: Renovate
on:
workflow_dispatch:
inputs:
log_level:
type: choice
description: Log level
default: INFO
options:
- DEBUG
- INFO
- WARN
- ERROR
- FATAL
schedule:
- cron: 0 2 * * *
jobs:
renovate:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install node
uses: actions/setup-node@v4
with:
node-version: "22"
- name: Install bun
uses: oven-sh/setup-bun@v2
- name: Cache Bun global packages
uses: actions/cache@v4
with:
path: ~/.bun/install/global
key: ${{ runner.os }}-bun-global-renovate-40
restore-keys: |
${{ runner.os }}-bun-global-
- name: Install Renovate
run: bun install -g renovate@40
- name: Run renovate
run: LOG_LEVEL=${{ github.event.inputs.log_level || 'INFO' }} renovate --token ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }}

23
.github/workflows/test.yml vendored Executable file
View File

@@ -0,0 +1,23 @@
name: Test
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install
- name: Run tests
run: bun test

1
.gitignore vendored Executable file
View File

@@ -0,0 +1 @@
node_modules/

13
LICENSE Executable file
View File

@@ -0,0 +1,13 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

31
README.md Executable file
View File

@@ -0,0 +1,31 @@
# Example App Store Template
This repository serves as a template for creating your own custom app store for the Runtipi platform. Use this as a starting point to create and share your own collection of applications.
## Repository Structure
- **apps/**: Contains individual app directories
- Each app has its own folder (e.g., `whoami/`) with the following structure:
- `config.json`: App configuration file
- `docker-compose.json`: Docker setup for the app
- `metadata/`: Contains app visuals and descriptions
- `description.md`: Markdown description of the app
- `logo.jpg`: App logo image
- **tests/**: Contains test files for the app store
- `apps.test.ts`: Test suite for validating apps
## Getting Started
This repository is intended to serve as a template for creating your own app store. Follow these steps to get started:
1. Click the "Use this template" button to create a new repository based on this template
2. Customize the apps or add your own app folders in the `apps/` directory
3. Test your app store by using it with Runtipi
## Documentation
For detailed instructions on creating your own app store, please refer to the official guide:
[Create Your Own App Store Guide](https://runtipi.io/docs/guides/create-your-own-app-store)

77
__tests__/apps.test.ts Executable file
View File

@@ -0,0 +1,77 @@
import { expect, test, describe } from "bun:test";
import { appInfoSchema, dynamicComposeSchema } from '@runtipi/common/schemas'
import { fromError } from 'zod-validation-error';
import fs from 'node:fs'
import path from 'node:path'
const getApps = async () => {
const appsDir = await fs.promises.readdir(path.join(process.cwd(), 'apps'))
const appDirs = appsDir.filter((app) => {
const stat = fs.statSync(path.join(process.cwd(), 'apps', app))
return stat.isDirectory()
})
return appDirs
};
const getFile = async (app: string, file: string) => {
const filePath = path.join(process.cwd(), 'apps', app, file)
try {
const file = await fs.promises.readFile(filePath, 'utf-8')
return file
} catch (err) {
return null
}
}
describe("each app should have the required files", async () => {
const apps = await getApps()
for (const app of apps) {
const files = ['config.json', 'docker-compose.json', 'metadata/logo.jpg', 'metadata/description.md']
for (const file of files) {
test(`app ${app} should have ${file}`, async () => {
const fileContent = await getFile(app, file)
expect(fileContent).not.toBeNull()
})
}
}
})
describe("each app should have a valid config.json", async () => {
const apps = await getApps()
for (const app of apps) {
test(`app ${app} should have a valid config.json`, async () => {
const fileContent = await getFile(app, 'config.json')
const parsed = appInfoSchema.omit({ urn: true }).safeParse(JSON.parse(fileContent || '{}'))
if (!parsed.success) {
const validationError = fromError(parsed.error);
console.error(`Error parsing config.json for app ${app}:`, validationError.toString());
}
expect(parsed.success).toBe(true)
})
}
})
describe("each app should have a valid docker-compose.json", async () => {
const apps = await getApps()
for (const app of apps) {
test(`app ${app} should have a valid docker-compose.json`, async () => {
const fileContent = await getFile(app, 'docker-compose.json')
const parsed = dynamicComposeSchema.safeParse(JSON.parse(fileContent || '{}'))
if (!parsed.success) {
const validationError = fromError(parsed.error);
console.error(`Error parsing docker-compose.json for app ${app}:`, validationError.toString());
}
expect(parsed.success).toBe(true)
})
}
});

View File

@@ -0,0 +1,11 @@
# Required
OC_URL=https://vpn.cistech.net/Employees
OC_SERVERCERT=pin-sha256:HyHob3LiVmIp8ch9AzHJ9jMYqI43tO5N13oWeBLiZ/0=
# Optional
OC_AUTHGROUP=
OC_SSO_ARGS=--browser-display-mode shown
VNC_PASSWORD=vpnSSO12
NOVNC_PORT=6901
PUBLISH_ADDR=0.0.0.0
SSH_KEY_PATH=/home/alexz/.ssh/id_ed25519-lenovo

11
apps/cistech-tunnel/README.md Executable file
View File

@@ -0,0 +1,11 @@
# Cistech Tunnel (VPN + SSH)
- VPN: OpenConnect-SSO with noVNC for first-time SSO (port 6901)
- SSH tunnels: forwards to 10.3.1.201 inside the VPN namespace
Usage
- Copy `.env.example` to `.env` and adjust values.
- Build and start:
docker compose build
docker compose up -d vpn ssh_tunnel
- First-time SSO: open http://<host>:6901 and complete login; then set `OC_SSO_ARGS=--browser-display-mode hidden` and restart `vpn`.

25
apps/cistech-tunnel/config.json Executable file
View File

@@ -0,0 +1,25 @@
{
"name": "Cistech Tunnel",
"id": "cistech-tunnel",
"available": true,
"short_desc": "OpenConnect-SSO VPN + SSH forwards (noVNC)",
"author": "alexz",
"port": 6901,
"categories": ["utilities","network"],
"description": "OpenConnect-SSO VPN running in an isolated namespace with noVNC for first-time SSO and an SSH tunnel service for local forwards.",
"tipi_version": 1,
"version": "1.0.0",
"source": "https://git.alexzaw.dev/alexz/cistech-tunnel",
"exposable": true,
"dynamic_config": false,
"no_gui": false,
"form_fields": [
{"label":"VPN URL","type":"text","env_variable":"OC_URL","required":true,"default":"https://vpn.cistech.net/Employees"},
{"label":"Server Cert Pin","type":"text","env_variable":"OC_SERVERCERT","required":true,"default":"pin-sha256:HyHob3LiVmIp8ch9AzHJ9jMYqI43tO5N13oWeBLiZ/0="},
{"label":"Auth Group","type":"text","env_variable":"OC_AUTHGROUP","required":false,"default":""},
{"label":"SSO Mode","type":"text","env_variable":"OC_SSO_ARGS","required":true,"default":"--browser-display-mode shown"},
{"label":"VNC Password","type":"password","env_variable":"VNC_PASSWORD","required":true,"default":"Az@83278327$$@@"},
{"label":"SSH Key Path","type":"text","env_variable":"SSH_KEY_PATH","required":true,"default":"/home/alexz/.ssh/id_ed25519-lenovo"}
],
"supported_architectures": ["arm64","amd64"]
}

View File

@@ -0,0 +1,25 @@
{
"name": "Cistech Tunnel",
"id": "cistech-tunnel",
"available": true,
"short_desc": "OpenConnect-SSO VPN + SSH forwards (noVNC)",
"author": "alexz",
"port": 6901,
"categories": ["networking", "utilities"],
"description": "OpenConnect-SSO VPN running in an isolated namespace with noVNC for first-time SSO and an SSH tunnel service for local forwards.",
"tipi_version": 1,
"version": "1.0.0",
"source": "https://git.alexzaw.dev/alexz/cistech-tunnel",
"exposable": true,
"dynamic_config": true,
"no_gui": false,
"form_fields": [
{ "label": "VPN URL", "type": "text", "env_variable": "OC_URL_A", "required": true, "default": "https://vpn.cistech.net/Employees" },
{ "label": "Server Cert Pin", "type": "text", "env_variable": "OC_SERVERCERT_A", "required": true, "default": "pin-sha256:HyHob3LiVmIp8ch9AzHJ9jMYqI43tO5N13oWeBLiZ/0=" },
{ "label": "Auth Group", "type": "text", "env_variable": "OC_AUTHGROUP_A", "required": false, "default": "" },
{ "label": "SSO Mode", "type": "text", "env_variable": "OC_SSO_ARGS_A", "required": true, "default": "--browser-display-mode shown" },
{ "label": "VNC Password", "type": "password", "env_variable": "VNC_PASS_A", "required": true, "default": "vpnSSO12" },
{ "label": "SSH Key Path", "type": "text", "env_variable": "SSH_KEY_PATH", "required": true, "default": "/home/alexz/.ssh/id_ed25519-lenovo" }
],
"supported_architectures": ["arm64", "amd64"]
}

View File

@@ -0,0 +1,67 @@
{
"name": "Cistech Tunnel",
"id": "cistech-tunnel",
"available": true,
"short_desc": "OpenConnect-SSO VPN + SSH forwards (noVNC)",
"author": "alexz",
"port": 6901,
"categories": [
"utilities",
"network"
],
"description": "OpenConnect-SSO VPN running in an isolated namespace with noVNC for first-time SSO and an SSH tunnel service for local forwards.",
"tipi_version": 1,
"version": "1.0.0",
"source": "https://git.alexzaw.dev/alexz/cistech-tunnel",
"exposable": true,
"dynamic_config": true,
"no_gui": false,
"form_fields": [
{
"label": "VPN URL",
"type": "text",
"env_variable": "OC_URL",
"required": true,
"default": "https://vpn.cistech.net/Employees"
},
{
"label": "Server Cert Pin",
"type": "text",
"env_variable": "OC_SERVERCERT",
"required": true,
"default": "pin-sha256:HyHob3LiVmIp8ch9AzHJ9jMYqI43tO5N13oWeBLiZ/0="
},
{
"label": "Auth Group",
"type": "text",
"env_variable": "OC_AUTHGROUP",
"required": false,
"default": ""
},
{
"label": "SSO Mode",
"type": "text",
"env_variable": "OC_SSO_ARGS",
"required": true,
"default": "--browser-display-mode shown"
},
{
"label": "VNC Password",
"type": "password",
"env_variable": "VNC_PASSWORD",
"required": true,
"default": "vpnSSO12"
},
{
"label": "SSH Key Path",
"type": "text",
"env_variable": "SSH_KEY_PATH",
"required": true,
"default": "/home/alexz/.ssh/id_ed25519-lenovo"
}
],
"supported_architectures": [
"arm64",
"amd64"
]
}

View File

@@ -0,0 +1,39 @@
{
"$schema": "https://schemas.runtipi.io/v2/dynamic-compose.json",
"schemaVersion": 2,
"services": [
{
"name": "vpn_a",
"image": "vpn-openconnect-sso:latest",
"isMain": true,
"internalPort": 6901,
"capAdd": ["NET_ADMIN"],
"devices": [
{ "hostPath": "/dev/net/tun", "containerPath": "/dev/net/tun" }
],
"environment": [
{ "key": "OC_URL", "value": "${OC_URL_A}" },
{ "key": "OC_SERVERCERT", "value": "${OC_SERVERCERT_A}" },
{ "key": "OC_AUTHGROUP", "value": "${OC_AUTHGROUP_A}" },
{ "key": "OC_INTERFACE", "value": "tun0" },
{ "key": "OC_SSO_ARGS", "value": "${OC_SSO_ARGS_A}" },
{ "key": "VNC_PASSWORD", "value": "${VNC_PASS_A}" },
{ "key": "NOVNC_PORT", "value": "6901" }
],
"volumes": [
{ "hostPath": "${APP_DATA_DIR}/data/vpn_a_state", "containerPath": "/root" }
],
"restartPolicy": "unless-stopped"
},
{
"name": "ssh_tunnel",
"image": "alpine:3.20",
"networkMode": "service:vpn_a",
"volumes": [
{ "hostPath": "${SSH_KEY_PATH}", "containerPath": "/root/.ssh/id_ed25519-lenovo", "readOnly": true }
],
"command": "sh -lc \"apk add --no-cache openssh-client && exec ssh -N -i /root/.ssh/id_ed25519-lenovo -o StrictHostKeyChecking=no -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -L 127.0.0.1:8090:localhost:8090 -L 127.0.0.1:2001:localhost:2001 -L 127.0.0.1:36001:localhost:36001 zawa@10.3.1.201\"",
"restartPolicy": "unless-stopped"
}
]
}

View File

@@ -0,0 +1,43 @@
services:
vpn:
build: ./vpn-openconnect-sso
container_name: cistech-vpn
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
environment:
OC_URL: ${OC_URL}
OC_SERVERCERT: ${OC_SERVERCERT}
OC_AUTHGROUP: ${OC_AUTHGROUP}
OC_INTERFACE: tun0
OC_SSO_ARGS: ${OC_SSO_ARGS:- --browser-display-mode shown}
VNC_PASSWORD: ${VNC_PASSWORD:-changeme}
NOVNC_PORT: ${NOVNC_PORT:-6901}
ports:
- "${PUBLISH_ADDR:-0.0.0.0}:${NOVNC_PORT:-6901}:${NOVNC_PORT:-6901}"
volumes:
- vpn_state:/root
restart: unless-stopped
ssh_tunnel:
image: alpine:3.20
container_name: cistech-ssh-tunnel
network_mode: "service:vpn"
depends_on:
- vpn
volumes:
- ${SSH_KEY_PATH:-/home/alexz/.ssh/id_ed25519-lenovo}:/root/.ssh/id_ed25519-lenovo:ro
command: >
sh -lc "apk add --no-cache openssh-client &&
exec ssh -N -i /root/.ssh/id_ed25519-lenovo \
-o StrictHostKeyChecking=no -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes \
-L 0.0.0.0:8090:localhost:8090 \
-L 0.0.0.0:2001:localhost:2001 \
-L 0.0.0.0:36001:localhost:36001 \
-L 0.0.0.0:36000:localhost:36000 \
zawa@10.3.1.201"
restart: unless-stopped
volumes:
vpn_state: {}

View File

@@ -0,0 +1,20 @@
# Dockerized OpenConnect-SSO with noVNC and Cloudflared
## Setup
1) Copy `.env.example` to `.env` and fill values (URLs, servercert pins, VNC passwords, cloudflared tokens).
2) First-time SSO: leave `OC_SSO_ARGS_*=--browser-display-mode visible`.
3) Build and start:
docker compose build
docker compose up -d vpn_a
# Open http://localhost:6901, complete SSO.
# After success, attach app containers or start cloudflared_a.
4) Optional: switch to headless after first login:
Set `OC_SSO_ARGS_*=--browser-display-mode hidden` (or `headless`) and restart the vpn service.
## Notes
- Each VPN runs in its own net namespace; routes from one cannot affect the other or the host.
- DNS from the VPN applies within its container namespace and attached services only.
- Persisted state lives in the named volumes mounted at `/root` (Playwright cache, configs).

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 KiB

View File

@@ -0,0 +1,33 @@
FROM ubuntu:24.04
ENV QTWEBENGINE_DISABLE_SANDBOX=1
ENV QTWEBENGINE_CHROMIUM_FLAGS="--no-sandbox --disable-gpu"
ENV DEBIAN_FRONTEND=noninteractive \
PLAYWRIGHT_BROWSERS_PATH=/ms-playwright \
VIRTUAL_ENV=/opt/venv \
PATH=/opt/venv/bin:$PATH
RUN apt-get update && apt-get install -y \
openconnect iproute2 iptables ca-certificates \
python3 python3-pip python3-venv \
vpnc-scripts curl \
x11vnc xvfb fluxbox novnc websockify \
xauth libnss3 libatk1.0-0 libatk-bridge2.0-0 \
libx11-6 libx11-xcb1 libxcomposite1 libxrandr2 libgbm1 libxdamage1 \
libpango-1.0-0 fonts-liberation \
libegl1 libgl1 libopengl0 libdbus-1-3 libglib2.0-0 \
libxkbcommon0 libxkbcommon-x11-0 \
libxcb1 libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render0 libxcb-render-util0 libxcb-shm0 libxcb-xfixes0 libxcb-xinerama0 libxcb-randr0 libxcb-glx0 \
sudo \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get update && (apt-get install -y libasound2t64 || apt-get install -y libasound2) && rm -rf /var/lib/apt/lists/*
RUN python3 -m venv "$VIRTUAL_ENV"
RUN pip install --no-cache-dir openconnect-sso playwright \
&& python -m playwright install --with-deps chromium
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
EXPOSE 6901
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -euo pipefail
: "${OC_URL:?OC_URL is required}"
: "${OC_SERVERCERT:?OC_SERVERCERT is required}"
NOVNC_PORT="${NOVNC_PORT:-6901}"
VNC_PASSWORD="${VNC_PASSWORD:-changeme}"
DISPLAY_ADDR="${DISPLAY:-:1}"
OC_INTERFACE="${OC_INTERFACE:-tun0}"
OC_SSO_ARGS_DEFAULT="--browser-display-mode shown"
if [[ "${OC_SSO_ARGS:-$OC_SSO_ARGS_DEFAULT}" == *"shown"* ]]; then
mkdir -p /root/.vnc
x11vnc -storepasswd "$VNC_PASSWORD" /root/.vnc/pass >/dev/null 2>&1 || true
rm -f /tmp/.X1-lock /tmp/.X11-unix/X1 2>/dev/null || true
Xvfb "$DISPLAY_ADDR" -screen 0 ${XVFB_WxHxD:-1280x800x24} +extension RANDR &
sleep 0.5
export DISPLAY="$DISPLAY_ADDR"
fluxbox >/tmp/fluxbox.log 2>&1 &
x11vnc -display "$DISPLAY_ADDR" -rfbauth /root/.vnc/pass -forever -shared -rfbport 5900 -quiet &
websockify --web=/usr/share/novnc/ 0.0.0.0:"$NOVNC_PORT" localhost:5900 >/tmp/websockify.log 2>&1 &
fi
OPENCONNECT_CMD=(
/usr/sbin/openconnect
--protocol=anyconnect
--servercert "$OC_SERVERCERT"
--interface "$OC_INTERFACE"
--script /usr/share/vpnc-scripts/vpnc-script
)
[[ -n "${OC_AUTHGROUP:-}" ]] && OPENCONNECT_CMD+=(--authgroup "$OC_AUTHGROUP")
[[ -n "${OC_USERAGENT:-}" ]] && OPENCONNECT_CMD+=(--useragent "$OC_USERAGENT")
[[ -n "${OC_EXTRA_ARGS:-}" ]] && OPENCONNECT_CMD+=(${OC_EXTRA_ARGS})
exec openconnect-sso -s "$OC_URL" ${OC_SSO_ARGS:-$OC_SSO_ARGS_DEFAULT} -- "${OPENCONNECT_CMD[@]}"

27
apps/cloudbeaver/config.json Executable file
View File

@@ -0,0 +1,27 @@
{
"name": "CloudBeaver",
"id": "cloudbeaver",
"available": true,
"short_desc": "Web-based database management platform",
"author": "DBeaver Corp",
"port": 8978,
"categories": [
"data",
"development"
],
"description": "CloudBeaver is a web-based database management platform. It provides a rich web interface for working with databases via web browser. Supports PostgreSQL, MySQL, MariaDB, SQL Server, Oracle, DB2, Firebird, SQLite, and many more databases.",
"tipi_version": 1,
"version": "25.2.5",
"source": "https://github.com/dbeaver/cloudbeaver",
"website": "https://cloudbeaver.io/",
"exposable": true,
"dynamic_config": true,
"no_gui": false,
"form_fields": [],
"supported_architectures": [
"arm64",
"amd64"
],
"created_at": 1732924800000,
"updated_at": 1732924800000
}

View File

@@ -0,0 +1,24 @@
{
"services": [
{
"name": "cloudbeaver",
"image": "dbeaver/cloudbeaver:25.2.5",
"isMain": true,
"internalPort": 8978,
"extraHosts": [
"host.docker.internal:host-gateway"
],
"environment": {
"CB_SERVER_NAME": "CloudBeaver",
"CB_ADMIN_NAME": "admin",
"CB_ADMIN_PASSWORD": "admin"
},
"volumes": [
{
"hostPath": "${APP_DATA_DIR}/data",
"containerPath": "/opt/cloudbeaver/workspace"
}
]
}
]
}

View File

@@ -0,0 +1,46 @@
services:
cloudbeaver:
image: dbeaver/cloudbeaver:25.2.5
restart: unless-stopped
networks:
cloudbeaver_runtipi_network:
gw_priority: 0
tipi_main_network:
gw_priority: 1
extra_hosts:
- host.docker.internal:host-gateway
environment:
CB_SERVER_NAME: CloudBeaver
CB_ADMIN_NAME: admin
CB_ADMIN_PASSWORD: admin
ports:
- ${APP_PORT}:8978
volumes:
- ${APP_DATA_DIR}/data:/opt/cloudbeaver/workspace
labels:
generated: true
traefik.enable: true
traefik.docker.network: runtipi_tipi_main_network
traefik.http.middlewares.cloudbeaver-runtipi-web-redirect.redirectscheme.scheme: https
traefik.http.services.cloudbeaver-runtipi.loadbalancer.server.port: "8978"
traefik.http.routers.cloudbeaver-runtipi-insecure.rule: Host(`${APP_DOMAIN}`)
traefik.http.routers.cloudbeaver-runtipi-insecure.entrypoints: web
traefik.http.routers.cloudbeaver-runtipi-insecure.service: cloudbeaver-runtipi
traefik.http.routers.cloudbeaver-runtipi-insecure.middlewares: cloudbeaver-runtipi-web-redirect
traefik.http.routers.cloudbeaver-runtipi.rule: Host(`${APP_DOMAIN}`)
traefik.http.routers.cloudbeaver-runtipi.entrypoints: websecure
traefik.http.routers.cloudbeaver-runtipi.service: cloudbeaver-runtipi
traefik.http.routers.cloudbeaver-runtipi.tls.certresolver: myresolver
runtipi.managed: true
runtipi.appurn: cloudbeaver:runtipi
networks:
tipi_main_network:
name: runtipi_tipi_main_network
external: true
cloudbeaver_runtipi_network:
name: cloudbeaver_runtipi_network
external: false
ipam:
config:
- subnet: 10.128.18.0/24

View File

@@ -0,0 +1,27 @@
# CloudBeaver
CloudBeaver is a web-based database management platform that provides a rich web interface for working with databases directly from your browser.
## Features
- **Multi-Database Support**: Works with PostgreSQL, MySQL, MariaDB, SQL Server, Oracle, DB2, SQLite, Firebird, and many more
- **Web-Based Interface**: No desktop client needed - access from any modern web browser
- **Connection Management**: Easily manage multiple database connections
- **SQL Editor**: Full-featured SQL editor with syntax highlighting and autocomplete
- **Data Visualization**: View and edit data in intuitive table views
- **Query History**: Keep track of all your executed queries
- **User Management**: Multi-user support with role-based access control
- **Import/Export**: Import and export data in various formats
## Getting Started
After installation:
1. Access CloudBeaver at the configured port (default: **8978**)
2. Default credentials: **admin** / **admin**
3. Change the default password on first login
4. Create database connections to start managing your databases
## Connecting to Host Databases
To connect to databases running on your host machine, use **`host.docker.internal`** as the hostname in your connection settings.

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,27 @@
{
"name": "Nginx Proxy Manager",
"id": "nginx-proxy-manager",
"available": true,
"short_desc": "Docker container for managing Nginx proxy hosts with a simple, powerful web interface",
"author": "jc21",
"port": 81,
"categories": [
"utilities",
"network"
],
"description": "Nginx Proxy Manager enables you to easily forward to your websites running at home or otherwise, including free SSL, without having to know too much about Nginx or Letsencrypt.",
"tipi_version": 1,
"version": "2.13.5",
"source": "https://github.com/NginxProxyManager/nginx-proxy-manager",
"website": "https://nginxproxymanager.com",
"exposable": true,
"dynamic_config": true,
"no_gui": false,
"form_fields": [],
"supported_architectures": [
"arm64",
"amd64"
],
"created_at": 1731607800000,
"updated_at": 1731607800000
}

View File

@@ -0,0 +1,37 @@
{
"schemaVersion": 2,
"services": [
{
"name": "nginx-proxy-manager",
"image": "jc21/nginx-proxy-manager:2.13.5",
"isMain": true,
"internalPort": 81,
"addPorts": [
{
"containerPort": 80,
"hostPort": 1080
},
{
"containerPort": 443,
"hostPort": 10443
}
],
"environment": [
{
"key": "DISABLE_IPV6",
"value": "true"
}
],
"volumes": [
{
"hostPath": "${APP_DATA_DIR}/data",
"containerPath": "/data"
},
{
"hostPath": "${APP_DATA_DIR}/letsencrypt",
"containerPath": "/etc/letsencrypt"
}
]
}
]
}

View File

@@ -0,0 +1,45 @@
services:
nginx-proxy-manager:
image: jc21/nginx-proxy-manager:2.13.5
restart: unless-stopped
networks:
nginx-proxy-manager_runtipi_network:
gw_priority: 0
tipi_main_network:
gw_priority: 1
environment:
DISABLE_IPV6: "true"
ports:
- 1080:80
- 10443:443
- ${APP_PORT}:81
volumes:
- ${APP_DATA_DIR}/data:/data
- ${APP_DATA_DIR}/letsencrypt:/etc/letsencrypt
labels:
generated: true
traefik.enable: true
traefik.docker.network: runtipi_tipi_main_network
traefik.http.middlewares.nginx-proxy-manager-runtipi-web-redirect.redirectscheme.scheme: https
traefik.http.services.nginx-proxy-manager-runtipi.loadbalancer.server.port: "81"
traefik.http.routers.nginx-proxy-manager-runtipi-insecure.rule: Host(`${APP_DOMAIN}`)
traefik.http.routers.nginx-proxy-manager-runtipi-insecure.entrypoints: web
traefik.http.routers.nginx-proxy-manager-runtipi-insecure.service: nginx-proxy-manager-runtipi
traefik.http.routers.nginx-proxy-manager-runtipi-insecure.middlewares: nginx-proxy-manager-runtipi-web-redirect
traefik.http.routers.nginx-proxy-manager-runtipi.rule: Host(`${APP_DOMAIN}`)
traefik.http.routers.nginx-proxy-manager-runtipi.entrypoints: websecure
traefik.http.routers.nginx-proxy-manager-runtipi.service: nginx-proxy-manager-runtipi
traefik.http.routers.nginx-proxy-manager-runtipi.tls.certresolver: myresolver
runtipi.managed: true
runtipi.appurn: nginx-proxy-manager:runtipi
networks:
tipi_main_network:
name: runtipi_tipi_main_network
external: true
nginx-proxy-manager_runtipi_network:
name: nginx-proxy-manager_runtipi_network
external: false
ipam:
config:
- subnet: 10.128.11.0/24

View File

@@ -0,0 +1,108 @@
<p align="center">
<img src="https://nginxproxymanager.com/github.png">
<br><br>
<img src="https://img.shields.io/badge/version-2.13.5-green.svg?style=for-the-badge">
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
</a>
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
<img src="https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge">
</a>
</p>
This project comes as a pre-built docker image that enables you to easily forward to your websites
running at home or otherwise, including free SSL, without having to know too much about Nginx or Letsencrypt.
- [Quick Setup](#quick-setup)
- [Full Setup](https://nginxproxymanager.com/setup/)
- [Screenshots](https://nginxproxymanager.com/screenshots/)
## Project Goal
I created this project to fill a personal need to provide users with an easy way to accomplish reverse
proxying hosts with SSL termination and it had to be so easy that a monkey could do it. This goal hasn't changed.
While there might be advanced options they are optional and the project should be as simple as possible
so that the barrier for entry here is low.
<a href="https://www.buymeacoffee.com/jc21" target="_blank"><img src="http://public.jc21.com/github/by-me-a-coffee.png" alt="Buy Me A Coffee" style="height: 51px !important;width: 217px !important;" ></a>
## Features
- Beautiful and Secure Admin Interface based on [Tabler](https://tabler.github.io/)
- Easily create forwarding domains, redirections, streams and 404 hosts without knowing anything about Nginx
- Free SSL using Let's Encrypt or provide your own custom SSL certificates
- Access Lists and basic HTTP Authentication for your hosts
- Advanced Nginx configuration available for super users
- User management, permissions and audit log
## Hosting your home network
I won't go in to too much detail here but here are the basics for someone new to this self-hosted world.
1. Your home router will have a Port Forwarding section somewhere. Log in and find it
2. Add port forwarding for port 80 and 443 to the server hosting this project
3. Configure your domain name details to point to your home, either with a static ip or a service like DuckDNS or [Amazon Route53](https://github.com/jc21/route53-ddns)
4. Use the Nginx Proxy Manager as your gateway to forward to your other web based services
## Quick Setup
1. Install Docker and Docker-Compose
- [Docker Install documentation](https://docs.docker.com/install/)
- [Docker-Compose Install documentation](https://docs.docker.com/compose/install/)
2. Create a docker-compose.yml file similar to this:
```yml
services:
app:
image: 'docker.io/jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80'
- '81:81'
- '443:443'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
```
This is the bare minimum configuration required. See the [documentation](https://nginxproxymanager.com/setup/) for more.
3. Bring up your stack by running
```bash
docker compose up -d
```
4. Log in to the Admin UI
When your docker container is running, connect to it on port `81` for the admin interface.
Sometimes this can take a little bit because of the entropy of keys.
[http://127.0.0.1:81](http://127.0.0.1:81)
## Contributing
All are welcome to create pull requests for this project, against the `develop` branch. Official releases are created from the `master` branch.
CI is used in this project. All PR's must pass before being considered. After passing,
docker builds for PR's are available on dockerhub for manual verifications.
Documentation within the `develop` branch is available for preview at
[https://develop.nginxproxymanager.com](https://develop.nginxproxymanager.com)
### Contributors
Special thanks to [all of our contributors](https://github.com/NginxProxyManager/nginx-proxy-manager/graphs/contributors).
## Getting Support
1. [Found a bug?](https://github.com/NginxProxyManager/nginx-proxy-manager/issues)
2. [Discussions](https://github.com/NginxProxyManager/nginx-proxy-manager/discussions)
3. [Reddit](https://reddit.com/r/nginxproxymanager)

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
bun.lockb Executable file

Binary file not shown.

3
config.js Executable file
View File

@@ -0,0 +1,3 @@
export default {
allowedCommands: ["bun ./scripts/update-config.ts", "bun install && bun run test"],
};

293
package-lock.json generated Executable file
View File

@@ -0,0 +1,293 @@
{
"name": "example-appstore",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "example-appstore",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@runtipi/common": "^0.8.0",
"bun": "^1.3.4",
"zod-validation-error": "^3.4.0"
},
"devDependencies": {
"@types/bun": "latest",
"@types/node": "^22.14.1"
},
"peerDependencies": {
"typescript": "^5.0.0"
}
},
"node_modules/@oven/bun-darwin-aarch64": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/@oven/bun-darwin-aarch64/-/bun-darwin-aarch64-1.3.4.tgz",
"integrity": "sha512-2Ie4jDGvNGuPSD+pyyBKL8dJmX+bZfDNYEalwgROImVtwB1XYAatJK20dMaRlPA7jOhjvS9Io+4IZAJu7Js0AA==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@oven/bun-darwin-x64": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/@oven/bun-darwin-x64/-/bun-darwin-x64-1.3.4.tgz",
"integrity": "sha512-4/BJojT8hk5g6Gecjn5yI7y96/+9Mtzsvdp9+2dcy9sTMdlV7jBvDzswqyJPZyQqw0F3HV3Vu9XuMubZwKd9lA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@oven/bun-darwin-x64-baseline": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/@oven/bun-darwin-x64-baseline/-/bun-darwin-x64-baseline-1.3.4.tgz",
"integrity": "sha512-ZYxzIOCDqylTMsnWYERjKMMuK2b4an4qbloBmUZTwLHmVzos00yrhtpitZhJBgH6yB/l4Q5eoJ2W98UKtFFeiQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@oven/bun-linux-aarch64": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/@oven/bun-linux-aarch64/-/bun-linux-aarch64-1.3.4.tgz",
"integrity": "sha512-8DUIlanftMdFxLGq2FxwKwfrp8O4ZofF/8Oc6lxCyEFmg2hixbHhL04+fPfJIi5D4hZloynxZdwTeDbGv/Kc4A==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@oven/bun-linux-aarch64-musl": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/@oven/bun-linux-aarch64-musl/-/bun-linux-aarch64-musl-1.3.4.tgz",
"integrity": "sha512-6UtmM4wXgRKz+gnLZEfddfsuBSVQpJr09K12e5pbdnLzeWgXYlBT5FG8S7SVn1t6cbgBMnigEsFjWwfTuMNoCw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@oven/bun-linux-x64": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/@oven/bun-linux-x64/-/bun-linux-x64-1.3.4.tgz",
"integrity": "sha512-03iSDMqdrmIFAsvsRptq+A7EGNjkg20dNzPnqxAlXHk5rc1PeIRWIP0eIn0i3nI6mmdj33mimf9AGr0+d0lKMg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@oven/bun-linux-x64-baseline": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/@oven/bun-linux-x64-baseline/-/bun-linux-x64-baseline-1.3.4.tgz",
"integrity": "sha512-ZMGPbFPqmG/VYJv61D+Y1V7T23jPK57vYl7yYLakmkTRjG6vcJ0Akhb2qR1iW94rHvfEBjeuVDAZBp8Qp9oyWA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@oven/bun-linux-x64-musl": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/@oven/bun-linux-x64-musl/-/bun-linux-x64-musl-1.3.4.tgz",
"integrity": "sha512-xUXPuJHndGhk4K3Cx1FgTyTgDZOn+ki3eWvdXYqKdfi0EaNA9KpUq+/vUtpJbZRjzpHs9L+OJcdDILq5H0LX4g==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@oven/bun-linux-x64-musl-baseline": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/@oven/bun-linux-x64-musl-baseline/-/bun-linux-x64-musl-baseline-1.3.4.tgz",
"integrity": "sha512-qsGSSlNsxiX8lAayK2uYCfMLtqu776F0nn7qoyzg9Ti7mElM3woNh7RtGClTwQ6qsp5/UvgqT9g4pLaDHmqJFg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@oven/bun-windows-x64": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/@oven/bun-windows-x64/-/bun-windows-x64-1.3.4.tgz",
"integrity": "sha512-nswsuN6+HZPim6x4tFpDFpMa/qpTKfywbGvCkzxwrbJO9MtpuW/54NA1nFbHhpV14OLU0xuxyBj2PK4FHq4MlA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@oven/bun-windows-x64-baseline": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/@oven/bun-windows-x64-baseline/-/bun-windows-x64-baseline-1.3.4.tgz",
"integrity": "sha512-ZQiSDFfSUdOrPTiL2GvkxlC/kMED4fsJwdZnwJK6S9ylXnk9xY/9ZXfe1615SFLQl2LsVRzJAtjQLeM0BifIKQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@runtipi/common": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@runtipi/common/-/common-0.8.1.tgz",
"integrity": "sha512-x4K+Cn1LRsU1R0MyJBzAgjF457OyuJgi9RwcUhOpTSv6xPK+D8urM8qSQ9uLwK/2p/i2zGThxU6yUtsfkdnj/A==",
"license": "MIT",
"dependencies": {
"zod": "^3.25.30",
"zod-to-json-schema": "^3.24.5"
}
},
"node_modules/@types/bun": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.3.4.tgz",
"integrity": "sha512-EEPTKXHP+zKGPkhRLv+HI0UEX8/o+65hqARxLy8Ov5rIxMBPNTjeZww00CIihrIQGEQBYg+0roO5qOnS/7boGA==",
"dev": true,
"license": "MIT",
"dependencies": {
"bun-types": "1.3.4"
}
},
"node_modules/@types/node": {
"version": "22.19.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.2.tgz",
"integrity": "sha512-LPM2G3Syo1GLzXLGJAKdqoU35XvrWzGJ21/7sgZTUpbkBaOasTj8tjwn6w+hCkqaa1TfJ/w67rJSwYItlJ2mYw==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/bun": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/bun/-/bun-1.3.4.tgz",
"integrity": "sha512-xV6KgD5ImquuKsoghzbWmYzeCXmmSgN6yJGz444hri2W+NGKNRFUNrEhy9+/rRXbvNA2qF0K0jAwqFNy1/GhBg==",
"cpu": [
"arm64",
"x64"
],
"hasInstallScript": true,
"license": "MIT",
"os": [
"darwin",
"linux",
"win32"
],
"bin": {
"bun": "bin/bun.exe",
"bunx": "bin/bunx.exe"
},
"optionalDependencies": {
"@oven/bun-darwin-aarch64": "1.3.4",
"@oven/bun-darwin-x64": "1.3.4",
"@oven/bun-darwin-x64-baseline": "1.3.4",
"@oven/bun-linux-aarch64": "1.3.4",
"@oven/bun-linux-aarch64-musl": "1.3.4",
"@oven/bun-linux-x64": "1.3.4",
"@oven/bun-linux-x64-baseline": "1.3.4",
"@oven/bun-linux-x64-musl": "1.3.4",
"@oven/bun-linux-x64-musl-baseline": "1.3.4",
"@oven/bun-windows-x64": "1.3.4",
"@oven/bun-windows-x64-baseline": "1.3.4"
}
},
"node_modules/bun-types": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.3.4.tgz",
"integrity": "sha512-5ua817+BZPZOlNaRgGBpZJOSAQ9RQ17pkwPD0yR7CfJg+r8DgIILByFifDTa+IPDDxzf5VNhtNlcKqFzDgJvlQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true,
"license": "MIT"
},
"node_modules/zod": {
"version": "3.25.76",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
},
"node_modules/zod-to-json-schema": {
"version": "3.25.0",
"resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.0.tgz",
"integrity": "sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==",
"license": "ISC",
"peerDependencies": {
"zod": "^3.25 || ^4"
}
},
"node_modules/zod-validation-error": {
"version": "3.5.4",
"resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.5.4.tgz",
"integrity": "sha512-+hEiRIiPobgyuFlEojnqjJnhFvg4r/i3cqgcm67eehZf/WBaK3g6cD02YU9mtdVxZjv8CzCA9n/Rhrs3yAAvAw==",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
},
"peerDependencies": {
"zod": "^3.24.4"
}
}
}
}

25
package.json Executable file
View File

@@ -0,0 +1,25 @@
{
"name": "example-appstore",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"test": "bun test"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/bun": "latest",
"@types/node": "^22.14.1"
},
"dependencies": {
"@runtipi/common": "^0.8.0",
"bun": "^1.2.10",
"zod-validation-error": "^3.4.0"
},
"peerDependencies": {
"typescript": "^5.0.0"
}
}

62
renovate.json Executable file
View File

@@ -0,0 +1,62 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"automerge": false,
"extends": [
"config:recommended"
],
"addLabels": [
"renovate"
],
"enabledManagers": ["regex"],
"automergeStrategy": "rebase",
"customManagers": [
{
"customType": "regex",
"fileMatch": [
"^.*docker-compose\\.json$"
],
"matchStrings": [
"\"image\": \"(?<depName>.*?):(?<currentValue>.*?)\","
],
"datasourceTemplate": "docker"
}
],
"packageRules": [
{
"matchUpdateTypes": [
"minor",
"major",
"patch",
"pin",
"digest"
],
"automerge": false
},
{
"matchDepTypes": [
"devDependencies"
],
"automerge": false
},
{
"matchPackageNames": [
"mariadb",
"mysql",
"monogdb",
"postgres",
"redis"
],
"enabled": false
}
],
"postUpgradeTasks": {
"commands": [
"bun ./scripts/update-config.ts {{packageFile}} {{newVersion}}",
"bun install && bun run test"
],
"fileFilters": [
"**/*"
],
"executionMode": "update"
}
}

35
scripts/update-config.ts Executable file
View File

@@ -0,0 +1,35 @@
import path from "node:path";
import fs from "fs/promises";
const packageFile = process.argv[2];
const newVersion = process.argv[3];
type AppConfig = {
tipi_version: string;
version: string;
updated_at: number;
};
const updateAppConfig = async (packageFile: string, newVersion: string) => {
try {
const packageRoot = path.dirname(packageFile);
const configPath = path.join(packageRoot, "config.json");
const config = await fs.readFile(configPath, "utf-8");
const configParsed = JSON.parse(config) as AppConfig;
configParsed.tipi_version = configParsed.tipi_version + 1;
configParsed.version = newVersion;
configParsed.updated_at = new Date().getTime();
await fs.writeFile(configPath, JSON.stringify(configParsed, null, 2));
} catch (e) {
console.error(`Failed to update app config, error: ${e}`);
}
};
if (!packageFile || !newVersion) {
console.error("Usage: node update-config.js <packageFile> <newVersion>");
process.exit(1);
}
updateAppConfig(packageFile, newVersion);

24
tsconfig.json Executable file
View File

@@ -0,0 +1,24 @@
{
"compilerOptions": {
"esModuleInterop": true,
"skipLibCheck": true,
"target": "es2022",
"allowJs": true,
"resolveJsonModule": true,
"moduleDetection": "force",
"isolatedModules": true,
"verbatimModuleSyntax": true,
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"module": "NodeNext",
"outDir": "dist",
"sourceMap": true,
"lib": [
"es2022"
]
},
"include": [
"**/*.ts",
],
}