Skip to content

Commit ecb332c

Browse files
authored
feat: add extension templates for gotify, n8n, netdata, qdrant, and more (#545)
1 parent 1c41294 commit ecb332c

File tree

12 files changed

+1158
-1
lines changed

12 files changed

+1158
-1
lines changed

api/api/versions.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{
44
"version": "v1",
55
"status": "active",
6-
"release_date": "2025-10-29T22:13:12.29304044+05:30",
6+
"release_date": "2025-10-30T23:05:56.030438+05:30",
77
"end_of_life": "0001-01-01T00:00:00Z",
88
"changes": [
99
"Initial API version"

api/internal/features/dashboard/system_stats.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ func formatBytes(bytes uint64, unit string) string {
3535
// TODO: Add support for multi server management
3636
// solution: create a bridge between the gopsutil and the ssh client
3737
func (m *DashboardMonitor) GetSystemStats() {
38+
// Check if context is cancelled before proceeding
39+
select {
40+
case <-m.ctx.Done():
41+
return
42+
default:
43+
}
44+
3845
osType, err := m.getCommandOutput("uname -s")
3946
if err != nil {
4047
m.BroadcastError(err.Error(), GetSystemStats)
@@ -225,6 +232,10 @@ func (m *DashboardMonitor) getNetworkStats() NetworkStats {
225232
}
226233

227234
func (m *DashboardMonitor) getCommandOutput(cmd string) (string, error) {
235+
if m.client == nil {
236+
return "", fmt.Errorf("SSH client is not connected")
237+
}
238+
228239
session, err := m.client.NewSession()
229240
if err != nil {
230241
m.log.Log(logger.Error, "Failed to create new session", err.Error())

api/templates/deploy-alist.yaml

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
metadata:
2+
id: "deploy-alist"
3+
name: "AList"
4+
description: "AList is a file list/WebDAV program that supports multiple storage providers and provides a self-hosted file sharing/indexing solution."
5+
author: "Nixopus Team"
6+
icon: "📁"
7+
category: "Containers"
8+
type: "install"
9+
version: "1.0.0"
10+
isVerified: false
11+
12+
variables:
13+
image:
14+
type: "string"
15+
description: "Docker image for AList"
16+
default: "xhofe/alist"
17+
is_required: true
18+
tag:
19+
type: "string"
20+
description: "Docker image tag for AList"
21+
default: "latest"
22+
is_required: true
23+
container_name:
24+
type: "string"
25+
description: "Name of the AList container"
26+
default: "alist"
27+
is_required: true
28+
host_port:
29+
type: "integer"
30+
description: "Host port to expose for AList"
31+
default: 5244
32+
is_required: true
33+
container_port:
34+
type: "integer"
35+
description: "Container port AList listens on"
36+
default: 5244
37+
is_required: true
38+
data_volume:
39+
type: "string"
40+
description: "Docker volume name for AList persistent data"
41+
default: "alist_data"
42+
is_required: true
43+
PUID:
44+
type: "integer"
45+
description: "Host user ID to run container"
46+
default: 0
47+
is_required: false
48+
PGID:
49+
type: "integer"
50+
description: "Host group ID to run container"
51+
default: 0
52+
is_required: false
53+
UMASK:
54+
type: "string"
55+
description: "Umask for container file permissions"
56+
default: "022"
57+
is_required: false
58+
admin_username:
59+
type: "string"
60+
description: "Admin username for AList"
61+
default: "admin"
62+
is_required: true
63+
admin_password:
64+
type: "string"
65+
description: "Admin password for AList"
66+
default: "admin"
67+
is_required: true
68+
69+
proxy_domain:
70+
type: "string"
71+
description: "Domain name for AList (optional)"
72+
default: ""
73+
is_required: false
74+
75+
execution:
76+
run:
77+
- name: "Pull AList image"
78+
type: "docker"
79+
properties:
80+
action: "pull"
81+
image: "{{ image }}"
82+
tag: "{{ tag }}"
83+
timeout: 300
84+
85+
- name: "Run AList container"
86+
type: "docker"
87+
properties:
88+
action: "run"
89+
name: "{{ container_name }}"
90+
image: "{{ image }}"
91+
tag: "{{ tag }}"
92+
ports: "{{ host_port }}:{{ container_port }}"
93+
volumes:
94+
- "{{ data_volume }}:/opt/alist/data"
95+
environment:
96+
- "PUID={{ PUID }}"
97+
- "PGID={{ PGID }}"
98+
- "UMASK={{ UMASK }}"
99+
restart: "unless-stopped"
100+
timeout: 180
101+
102+
- name: "Set admin credentials"
103+
type: "command"
104+
properties:
105+
cmd: "docker exec {{ container_name }} ./alist admin set {{ admin_password }}"
106+
timeout: 30
107+
108+
- name: "Add proxy for AList"
109+
type: "proxy"
110+
properties:
111+
action: "add"
112+
domain: "{{ proxy_domain }}"
113+
port: "{{ host_port }}"
114+
timeout: 30

api/templates/deploy-gotify.yaml

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
metadata:
2+
id: "deploy-gotify"
3+
name: "Gotify"
4+
description: "Gotify is a simple server for sending and receiving messages in real-time, perfect for push notifications and alerts."
5+
author: "Nixopus Team"
6+
icon: "📨"
7+
category: "Containers"
8+
type: "install"
9+
version: "1.0.0"
10+
isVerified: false
11+
12+
variables:
13+
image:
14+
type: "string"
15+
description: "Docker image for Gotify"
16+
default: "ghcr.io/gotify/server"
17+
is_required: true
18+
19+
tag:
20+
type: "string"
21+
description: "Docker image tag"
22+
default: "latest"
23+
is_required: true
24+
25+
container_name:
26+
type: "string"
27+
description: "Name of the container"
28+
default: "gotify"
29+
is_required: true
30+
31+
host_port:
32+
type: "integer"
33+
description: "Host port to expose"
34+
default: 80
35+
is_required: true
36+
37+
container_port:
38+
type: "integer"
39+
description: "Container port to map"
40+
default: 80
41+
is_required: true
42+
43+
data_volume:
44+
type: "string"
45+
description: "Docker volume name for Gotify persistent data"
46+
default: "gotify_data"
47+
is_required: true
48+
49+
timezone:
50+
type: "string"
51+
description: "Timezone (TZ) environment variable"
52+
default: "UTC"
53+
is_required: false
54+
55+
default_user:
56+
type: "string"
57+
description: "Default admin username"
58+
default: "admin"
59+
is_required: false
60+
61+
default_password:
62+
type: "string"
63+
description: "Default admin password"
64+
default: "admin"
65+
is_required: false
66+
67+
proxy_domain:
68+
type: "string"
69+
description: "Domain name for Gotify (optional)"
70+
default: ""
71+
is_required: false
72+
73+
execution:
74+
run:
75+
- name: "Remove existing Gotify container if present"
76+
type: "command"
77+
properties:
78+
cmd: "docker rm -f {{ container_name }} || true"
79+
timeout: 30
80+
81+
- name: "Pull Gotify image"
82+
type: "docker"
83+
properties:
84+
action: "pull"
85+
image: "{{ image }}"
86+
tag: "{{ tag }}"
87+
timeout: 300
88+
89+
- name: "Run Gotify container"
90+
type: "docker"
91+
properties:
92+
action: "run"
93+
name: "{{ container_name }}"
94+
image: "{{ image }}"
95+
tag: "{{ tag }}"
96+
ports: "{{ host_port }}:{{ container_port }}"
97+
volumes:
98+
- "{{ data_volume }}:/app/data"
99+
environment:
100+
- "TZ={{ timezone }}"
101+
- "GOTIFY_DEFAULTUSER_NAME={{ default_user }}"
102+
- "GOTIFY_DEFAULTUSER_PASS={{ default_password }}"
103+
restart: "unless-stopped"
104+
timeout: 120
105+
106+
- name: "Add proxy for Gotify"
107+
type: "proxy"
108+
properties:
109+
action: "add"
110+
domain: "{{ proxy_domain }}"
111+
port: "{{ host_port }}"
112+
timeout: 30
113+
114+
validate:
115+
- name: "Check Gotify web interface is accessible"
116+
type: "command"
117+
properties:
118+
cmd: "sh -c 'for i in $(seq 1 30); do code=$(curl -fsS -o /dev/null -w \"%{http_code}\\n\" http://localhost:{{ host_port }} || true); echo \"HTTP $code\"; echo $code | grep -E \"^(200|301|302)$\" && exit 0; sleep 2; done; exit 1'"
119+
timeout: 60

api/templates/deploy-n8n.yaml

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
metadata:
2+
id: "deploy-n8n"
3+
name: "n8n"
4+
description: "n8n is a workflow automation tool that lets you connect applications and automate tasks easily."
5+
author: "Nixopus Team"
6+
icon: "🔄"
7+
category: "Containers"
8+
type: "install"
9+
version: "1.0.0"
10+
isVerified: false
11+
12+
variables:
13+
image:
14+
type: "string"
15+
description: "Docker image for n8n"
16+
default: "docker.n8n.io/n8nio/n8n"
17+
is_required: true
18+
19+
tag:
20+
type: "string"
21+
description: "Docker image tag"
22+
default: "latest"
23+
is_required: true
24+
25+
container_name:
26+
type: "string"
27+
description: "Name of the container"
28+
default: "n8n"
29+
is_required: true
30+
31+
host_port:
32+
type: "integer"
33+
description: "Host port to expose"
34+
default: 5678
35+
is_required: true
36+
37+
container_port:
38+
type: "integer"
39+
description: "Container port to map"
40+
default: 5678
41+
is_required: true
42+
43+
data_volume:
44+
type: "string"
45+
description: "Volume or host path to persist n8n data"
46+
default: "n8n_data:/home/node/.n8n"
47+
is_required: true
48+
49+
timezone:
50+
type: "string"
51+
description: "Timezone (TZ) environment variable"
52+
default: "UTC"
53+
is_required: false
54+
55+
proxy_domain:
56+
type: "string"
57+
description: "Domain name for n8n (optional)"
58+
default: ""
59+
is_required: false
60+
61+
execution:
62+
run:
63+
- name: "Remove existing n8n container if present"
64+
type: "command"
65+
properties:
66+
cmd: "docker rm -f {{ container_name }} || true"
67+
timeout: 30
68+
69+
- name: "Pull n8n image"
70+
type: "docker"
71+
properties:
72+
action: "pull"
73+
image: "{{ image }}"
74+
tag: "{{ tag }}"
75+
timeout: 300
76+
77+
- name: "Run n8n container"
78+
type: "docker"
79+
properties:
80+
action: "run"
81+
name: "{{ container_name }}"
82+
image: "{{ image }}"
83+
tag: "{{ tag }}"
84+
ports: "{{ host_port }}:{{ container_port }}"
85+
volumes: "{{ data_volume }}"
86+
environment:
87+
- "N8N_PORT={{ container_port }}"
88+
- "N8N_HOST=0.0.0.0"
89+
- "WEBHOOK_URL=http://localhost:{{ host_port }}"
90+
- "TZ={{ timezone }}"
91+
restart: "unless-stopped"
92+
timeout: 120
93+
94+
- name: "Add proxy for n8n"
95+
type: "proxy"
96+
properties:
97+
action: "add"
98+
domain: "{{ proxy_domain }}"
99+
port: "{{ host_port }}"
100+
timeout: 30
101+
102+
validate:
103+
- name: "Check n8n web interface is accessible"
104+
type: "command"
105+
properties:
106+
cmd: "sh -c 'for i in $(seq 1 30); do code=$(curl -fsS -o /dev/null -w \"%{http_code}\\n\" http://localhost:{{ host_port }} || true); echo \"HTTP $code\"; echo $code | grep -E \"^(200|301|302)$\" && exit 0; sleep 2; done; exit 1'"
107+
timeout: 60

0 commit comments

Comments
 (0)