commit
aeda39b516
@ -122,7 +122,24 @@
|
|||||||
"Bash(gh run:*)",
|
"Bash(gh run:*)",
|
||||||
"Bash(dig:*)",
|
"Bash(dig:*)",
|
||||||
"Bash(nslookup:*)",
|
"Bash(nslookup:*)",
|
||||||
"Bash(host:*)"
|
"Bash(host:*)",
|
||||||
|
"Bash(git fetch:*)",
|
||||||
|
"Bash(/home/reepost/CyberMindStudio/secubox-openwrt/secubox-tools/deploy-remote.sh:*)",
|
||||||
|
"Bash(for i in 1 2 3 4 5)",
|
||||||
|
"Bash(do echo \"Attempt $i...\")",
|
||||||
|
"Bash(if ssh -o ConnectTimeout=10 root@192.168.255.1 'echo \"\"Connected\"\"; df -h /')",
|
||||||
|
"Bash(then break)",
|
||||||
|
"Bash(fi)",
|
||||||
|
"Bash(done)",
|
||||||
|
"Bash(for i in 1 2 3 4 5 6)",
|
||||||
|
"Bash(do echo \"Checking... \\($i\\)\")",
|
||||||
|
"Bash(if ssh -o ConnectTimeout=10 root@192.168.255.1 'df -h / /overlay 2>/dev/null')",
|
||||||
|
"Bash(./secubox-tools/deploy-remote.sh:*)",
|
||||||
|
"Bash(do)",
|
||||||
|
"Bash(if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@192.168.255.1 \"echo ''Router is back!''\")",
|
||||||
|
"Bash(then)",
|
||||||
|
"Bash(exit 0)",
|
||||||
|
"Bash(if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@192.168.255.1 \"echo ''Router online!''\")"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=luci-app-crowdsec-dashboard
|
PKG_NAME:=luci-app-crowdsec-dashboard
|
||||||
PKG_VERSION:=0.7.0
|
PKG_VERSION:=0.7.0
|
||||||
PKG_RELEASE:=28
|
PKG_RELEASE:=29
|
||||||
PKG_ARCH:=all
|
PKG_ARCH:=all
|
||||||
|
|
||||||
PKG_LICENSE:=Apache-2.0
|
PKG_LICENSE:=Apache-2.0
|
||||||
|
|||||||
@ -181,14 +181,14 @@ get_status() {
|
|||||||
elif ! grep -q "password:" "$creds_file" 2>/dev/null; then
|
elif ! grep -q "password:" "$creds_file" 2>/dev/null; then
|
||||||
lapi_reason="credentials incomplete"
|
lapi_reason="credentials incomplete"
|
||||||
else
|
else
|
||||||
# Check if LAPI port is listening (8080 hex = 1F90)
|
# Check if LAPI port is listening (8180 hex = 1FF4)
|
||||||
local port_up=0
|
local port_up=0
|
||||||
if grep -qi ":1F90 " /proc/net/tcp 2>/dev/null; then
|
if grep -qi ":1FF4 " /proc/net/tcp 2>/dev/null; then
|
||||||
port_up=1
|
port_up=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$port_up" = "0" ]; then
|
if [ "$port_up" = "0" ]; then
|
||||||
lapi_reason="port 8080 not listening"
|
lapi_reason="port 8180 not listening"
|
||||||
else
|
else
|
||||||
# Try actual LAPI status check
|
# Try actual LAPI status check
|
||||||
if run_cscli lapi status >/dev/null 2>&1; then
|
if run_cscli lapi status >/dev/null 2>&1; then
|
||||||
@ -746,7 +746,7 @@ get_firewall_bouncer_config() {
|
|||||||
val=$(uci -q get crowdsec.bouncer.ipv6 || echo "1")
|
val=$(uci -q get crowdsec.bouncer.ipv6 || echo "1")
|
||||||
json_add_string "ipv6" "$val"
|
json_add_string "ipv6" "$val"
|
||||||
|
|
||||||
val=$(uci -q get crowdsec.bouncer.api_url || echo "http://127.0.0.1:8080/")
|
val=$(uci -q get crowdsec.bouncer.api_url || echo "http://127.0.0.1:8180/")
|
||||||
json_add_string "api_url" "$val"
|
json_add_string "api_url" "$val"
|
||||||
|
|
||||||
val=$(uci -q get crowdsec.bouncer.update_frequency || echo "10s")
|
val=$(uci -q get crowdsec.bouncer.update_frequency || echo "10s")
|
||||||
@ -1822,7 +1822,7 @@ get_health_check() {
|
|||||||
|
|
||||||
# LAPI status
|
# LAPI status
|
||||||
local lapi_status="unavailable"
|
local lapi_status="unavailable"
|
||||||
local lapi_url="http://127.0.0.1:8080"
|
local lapi_url="http://127.0.0.1:8180"
|
||||||
if [ -x "$CSCLI" ]; then
|
if [ -x "$CSCLI" ]; then
|
||||||
if run_with_timeout 5 "$CSCLI" lapi status >/dev/null 2>&1; then
|
if run_with_timeout 5 "$CSCLI" lapi status >/dev/null 2>&1; then
|
||||||
lapi_status="available"
|
lapi_status="available"
|
||||||
|
|||||||
0
package/secubox/luci-app-cyberfeed/root/usr/libexec/rpcd/luci.cyberfeed
Normal file → Executable file
0
package/secubox/luci-app-cyberfeed/root/usr/libexec/rpcd/luci.cyberfeed
Normal file → Executable file
0
package/secubox/luci-app-gitea/root/usr/libexec/rpcd/luci.gitea
Normal file → Executable file
0
package/secubox/luci-app-gitea/root/usr/libexec/rpcd/luci.gitea
Normal file → Executable file
0
package/secubox/luci-app-glances/root/usr/libexec/rpcd/luci.glances
Normal file → Executable file
0
package/secubox/luci-app-glances/root/usr/libexec/rpcd/luci.glances
Normal file → Executable file
0
package/secubox/luci-app-haproxy/root/usr/libexec/rpcd/luci.haproxy
Normal file → Executable file
0
package/secubox/luci-app-haproxy/root/usr/libexec/rpcd/luci.haproxy
Normal file → Executable file
@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=luci-app-hexojs
|
PKG_NAME:=luci-app-hexojs
|
||||||
PKG_VERSION:=1.0.0
|
PKG_VERSION:=1.0.0
|
||||||
PKG_RELEASE:=2
|
PKG_RELEASE:=3
|
||||||
PKG_ARCH:=all
|
PKG_ARCH:=all
|
||||||
|
|
||||||
PKG_LICENSE:=MIT
|
PKG_LICENSE:=MIT
|
||||||
|
|||||||
@ -154,6 +154,13 @@ var callDeployStatus = rpc.declare({
|
|||||||
expect: {}
|
expect: {}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var callPublishToWww = rpc.declare({
|
||||||
|
object: 'luci.hexojs',
|
||||||
|
method: 'publish_to_www',
|
||||||
|
params: ['path'],
|
||||||
|
expect: {}
|
||||||
|
});
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// Preview
|
// Preview
|
||||||
// ============================================
|
// ============================================
|
||||||
@ -478,6 +485,7 @@ return baseclass.extend({
|
|||||||
clean: callClean,
|
clean: callClean,
|
||||||
deploy: callDeploy,
|
deploy: callDeploy,
|
||||||
getDeployStatus: callDeployStatus,
|
getDeployStatus: callDeployStatus,
|
||||||
|
publishToWww: callPublishToWww,
|
||||||
|
|
||||||
// Preview
|
// Preview
|
||||||
previewStart: callPreviewStart,
|
previewStart: callPreviewStart,
|
||||||
|
|||||||
@ -28,6 +28,19 @@ var callGiteaSaveConfig = rpc.declare({
|
|||||||
params: ['enabled', 'gitea_url', 'gitea_user', 'gitea_token', 'content_repo', 'content_branch', 'auto_sync']
|
params: ['enabled', 'gitea_url', 'gitea_user', 'gitea_token', 'content_repo', 'content_branch', 'auto_sync']
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var callBuild = rpc.declare({
|
||||||
|
object: 'luci.hexojs',
|
||||||
|
method: 'generate',
|
||||||
|
expect: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
var callPublishToWww = rpc.declare({
|
||||||
|
object: 'luci.hexojs',
|
||||||
|
method: 'publish_to_www',
|
||||||
|
params: ['path'],
|
||||||
|
expect: {}
|
||||||
|
});
|
||||||
|
|
||||||
return view.extend({
|
return view.extend({
|
||||||
title: _('Content Sync'),
|
title: _('Content Sync'),
|
||||||
wizardStep: 0,
|
wizardStep: 0,
|
||||||
@ -210,6 +223,50 @@ return view.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// Build & Publish Actions
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
handleBuild: function() {
|
||||||
|
ui.showModal(_('Building Site'), [
|
||||||
|
E('p', { 'class': 'spinning' }, _('Generating static files...'))
|
||||||
|
]);
|
||||||
|
|
||||||
|
callBuild().then(function(result) {
|
||||||
|
ui.hideModal();
|
||||||
|
if (result.success) {
|
||||||
|
ui.addNotification(null, E('p', _('Site built successfully!')), 'info');
|
||||||
|
} else {
|
||||||
|
ui.addNotification(null, E('p', result.error || _('Build failed')), 'error');
|
||||||
|
}
|
||||||
|
}).catch(function(err) {
|
||||||
|
ui.hideModal();
|
||||||
|
ui.addNotification(null, E('p', _('Error: %s').format(err.message || err)), 'error');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
handlePublish: function() {
|
||||||
|
var self = this;
|
||||||
|
var path = document.querySelector('#publish-path');
|
||||||
|
var publishPath = path ? path.value : '/www/blog';
|
||||||
|
|
||||||
|
ui.showModal(_('Publishing Site'), [
|
||||||
|
E('p', { 'class': 'spinning' }, _('Building and publishing to %s...').format(publishPath))
|
||||||
|
]);
|
||||||
|
|
||||||
|
callPublishToWww(publishPath).then(function(result) {
|
||||||
|
ui.hideModal();
|
||||||
|
if (result.success) {
|
||||||
|
ui.addNotification(null, E('p', _('Published to %s!').format(result.path || publishPath)), 'info');
|
||||||
|
} else {
|
||||||
|
ui.addNotification(null, E('p', result.error || _('Publish failed')), 'error');
|
||||||
|
}
|
||||||
|
}).catch(function(err) {
|
||||||
|
ui.hideModal();
|
||||||
|
ui.addNotification(null, E('p', _('Error: %s').format(err.message || err)), 'error');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// Gitea Actions
|
// Gitea Actions
|
||||||
// ============================================
|
// ============================================
|
||||||
@ -297,6 +354,49 @@ return view.extend({
|
|||||||
]) : ''
|
]) : ''
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
// Build & Publish Card
|
||||||
|
E('div', { 'class': 'hexo-card' }, [
|
||||||
|
E('div', { 'class': 'hexo-card-header' }, [
|
||||||
|
E('div', { 'class': 'hexo-card-title' }, [
|
||||||
|
E('span', { 'style': 'margin-right: 8px;' }, '\uD83D\uDE80'),
|
||||||
|
_('Build & Publish')
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
E('p', { 'style': 'margin-bottom: 16px; color: var(--hexo-text-muted);' },
|
||||||
|
_('Build static files and publish to web server.')),
|
||||||
|
E('div', { 'style': 'display: grid; grid-template-columns: 1fr 1fr; gap: 16px;' }, [
|
||||||
|
// Build Section
|
||||||
|
E('div', { 'class': 'hexo-card', 'style': 'background: var(--hexo-bg-input);' }, [
|
||||||
|
E('h4', { 'style': 'margin-bottom: 8px;' }, ['\uD83D\uDD28 ', _('Build')]),
|
||||||
|
E('p', { 'style': 'font-size: 13px; color: var(--hexo-text-muted); margin-bottom: 12px;' },
|
||||||
|
_('Generate static HTML files from your content.')),
|
||||||
|
E('button', {
|
||||||
|
'class': 'hexo-btn hexo-btn-primary',
|
||||||
|
'click': function() { self.handleBuild(); }
|
||||||
|
}, _('Build Site'))
|
||||||
|
]),
|
||||||
|
// Publish Section
|
||||||
|
E('div', { 'class': 'hexo-card', 'style': 'background: var(--hexo-bg-input);' }, [
|
||||||
|
E('h4', { 'style': 'margin-bottom: 8px;' }, ['\uD83C\uDF10 ', _('Publish')]),
|
||||||
|
E('p', { 'style': 'font-size: 13px; color: var(--hexo-text-muted); margin-bottom: 12px;' },
|
||||||
|
_('Copy built files to web server directory.')),
|
||||||
|
E('div', { 'class': 'hexo-form-group', 'style': 'margin-bottom: 8px;' }, [
|
||||||
|
E('input', {
|
||||||
|
'type': 'text',
|
||||||
|
'id': 'publish-path',
|
||||||
|
'class': 'hexo-input',
|
||||||
|
'value': '/www/blog',
|
||||||
|
'placeholder': '/www/blog'
|
||||||
|
})
|
||||||
|
]),
|
||||||
|
E('button', {
|
||||||
|
'class': 'hexo-btn hexo-btn-success',
|
||||||
|
'click': function() { self.handlePublish(); }
|
||||||
|
}, _('Publish to Web'))
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
|
||||||
// Gitea Integration Card
|
// Gitea Integration Card
|
||||||
E('div', { 'class': 'hexo-card' }, [
|
E('div', { 'class': 'hexo-card' }, [
|
||||||
E('div', { 'class': 'hexo-card-header' }, [
|
E('div', { 'class': 'hexo-card-header' }, [
|
||||||
|
|||||||
43
package/secubox/luci-app-hexojs/root/usr/libexec/rpcd/luci.hexojs
Normal file → Executable file
43
package/secubox/luci-app-hexojs/root/usr/libexec/rpcd/luci.hexojs
Normal file → Executable file
@ -1544,6 +1544,45 @@ gitea_save_config() {
|
|||||||
json_dump
|
json_dump
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Publish to /www (portal)
|
||||||
|
publish_to_www() {
|
||||||
|
read input
|
||||||
|
json_load "$input"
|
||||||
|
json_get_var path path
|
||||||
|
|
||||||
|
json_init
|
||||||
|
|
||||||
|
if ! is_running; then
|
||||||
|
json_add_boolean "success" 0
|
||||||
|
json_add_string "error" "Container not running"
|
||||||
|
json_dump
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Default path is /www/blog
|
||||||
|
[ -z "$path" ] && path="/www/blog"
|
||||||
|
|
||||||
|
# Set portal path in UCI for hexoctl
|
||||||
|
uci set hexojs.portal=hexojs
|
||||||
|
uci set hexojs.portal.path="$path"
|
||||||
|
uci commit hexojs
|
||||||
|
|
||||||
|
# Run publish command
|
||||||
|
local output=$("$HEXOCTL" publish 2>&1)
|
||||||
|
local result=$?
|
||||||
|
|
||||||
|
if [ "$result" -eq 0 ]; then
|
||||||
|
json_add_boolean "success" 1
|
||||||
|
json_add_string "message" "Published to $path"
|
||||||
|
json_add_string "path" "$path"
|
||||||
|
else
|
||||||
|
json_add_boolean "success" 0
|
||||||
|
json_add_string "error" "$output"
|
||||||
|
fi
|
||||||
|
|
||||||
|
json_dump
|
||||||
|
}
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# Service Control
|
# Service Control
|
||||||
# ============================================
|
# ============================================
|
||||||
@ -1634,7 +1673,8 @@ case "$1" in
|
|||||||
"gitea_setup": {},
|
"gitea_setup": {},
|
||||||
"gitea_clone": {},
|
"gitea_clone": {},
|
||||||
"gitea_sync": {},
|
"gitea_sync": {},
|
||||||
"gitea_save_config": {"enabled": "bool", "gitea_url": "str", "gitea_user": "str", "gitea_token": "str", "content_repo": "str", "content_branch": "str", "auto_sync": "bool"}
|
"gitea_save_config": {"enabled": "bool", "gitea_url": "str", "gitea_user": "str", "gitea_token": "str", "content_repo": "str", "content_branch": "str", "auto_sync": "bool"},
|
||||||
|
"publish_to_www": {"path": "str"}
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
;;
|
;;
|
||||||
@ -1686,6 +1726,7 @@ EOF
|
|||||||
gitea_clone) gitea_clone ;;
|
gitea_clone) gitea_clone ;;
|
||||||
gitea_sync) gitea_sync ;;
|
gitea_sync) gitea_sync ;;
|
||||||
gitea_save_config) gitea_save_config ;;
|
gitea_save_config) gitea_save_config ;;
|
||||||
|
publish_to_www) publish_to_www ;;
|
||||||
*) echo '{"error": "Unknown method"}' ;;
|
*) echo '{"error": "Unknown method"}' ;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
|||||||
@ -56,7 +56,8 @@
|
|||||||
"gitea_setup",
|
"gitea_setup",
|
||||||
"gitea_clone",
|
"gitea_clone",
|
||||||
"gitea_sync",
|
"gitea_sync",
|
||||||
"gitea_save_config"
|
"gitea_save_config",
|
||||||
|
"publish_to_www"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"uci": ["hexojs"]
|
"uci": ["hexojs"]
|
||||||
|
|||||||
0
package/secubox/luci-app-localai/root/usr/libexec/rpcd/luci.localai
Normal file → Executable file
0
package/secubox/luci-app-localai/root/usr/libexec/rpcd/luci.localai
Normal file → Executable file
0
package/secubox/luci-app-magicmirror2/root/usr/libexec/rpcd/luci.magicmirror2
Normal file → Executable file
0
package/secubox/luci-app-magicmirror2/root/usr/libexec/rpcd/luci.magicmirror2
Normal file → Executable file
0
package/secubox/luci-app-metabolizer/root/usr/libexec/rpcd/luci.metabolizer
Normal file → Executable file
0
package/secubox/luci-app-metabolizer/root/usr/libexec/rpcd/luci.metabolizer
Normal file → Executable file
0
package/secubox/luci-app-mmpm/root/usr/libexec/rpcd/luci.mmpm
Normal file → Executable file
0
package/secubox/luci-app-mmpm/root/usr/libexec/rpcd/luci.mmpm
Normal file → Executable file
0
package/secubox/luci-app-ollama/root/usr/libexec/rpcd/luci.ollama
Normal file → Executable file
0
package/secubox/luci-app-ollama/root/usr/libexec/rpcd/luci.ollama
Normal file → Executable file
0
package/secubox/luci-app-picobrew/root/usr/libexec/rpcd/luci.picobrew
Normal file → Executable file
0
package/secubox/luci-app-picobrew/root/usr/libexec/rpcd/luci.picobrew
Normal file → Executable file
0
package/secubox/luci-app-streamlit/root/usr/libexec/rpcd/luci.streamlit
Normal file → Executable file
0
package/secubox/luci-app-streamlit/root/usr/libexec/rpcd/luci.streamlit
Normal file → Executable file
0
package/secubox/luci-app-tor-shield/root/usr/libexec/rpcd/luci.tor-shield
Normal file → Executable file
0
package/secubox/luci-app-tor-shield/root/usr/libexec/rpcd/luci.tor-shield
Normal file → Executable file
@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=secubox-app-cs-firewall-bouncer
|
PKG_NAME:=secubox-app-cs-firewall-bouncer
|
||||||
PKG_VERSION:=0.0.31
|
PKG_VERSION:=0.0.31
|
||||||
PKG_RELEASE:=3
|
PKG_RELEASE:=4
|
||||||
|
|
||||||
# Source from upstream CrowdSec
|
# Source from upstream CrowdSec
|
||||||
# Note: v0.0.31 is the last version compatible with Go 1.23 (OpenWrt 24.10 SDK)
|
# Note: v0.0.31 is the last version compatible with Go 1.23 (OpenWrt 24.10 SDK)
|
||||||
|
|||||||
@ -88,7 +88,7 @@ merge_config() {
|
|||||||
uci set crowdsec.bouncer.enabled='0'
|
uci set crowdsec.bouncer.enabled='0'
|
||||||
uci set crowdsec.bouncer.ipv4='1'
|
uci set crowdsec.bouncer.ipv4='1'
|
||||||
uci set crowdsec.bouncer.ipv6='1'
|
uci set crowdsec.bouncer.ipv6='1'
|
||||||
uci set crowdsec.bouncer.api_url='http://127.0.0.1:8080/'
|
uci set crowdsec.bouncer.api_url='http://127.0.0.1:8180/'
|
||||||
uci set crowdsec.bouncer.update_frequency='10s'
|
uci set crowdsec.bouncer.update_frequency='10s'
|
||||||
uci set crowdsec.bouncer.deny_action='drop'
|
uci set crowdsec.bouncer.deny_action='drop'
|
||||||
uci set crowdsec.bouncer.deny_log='1'
|
uci set crowdsec.bouncer.deny_log='1'
|
||||||
|
|||||||
@ -50,7 +50,7 @@ init_yaml() {
|
|||||||
config_get hook_priority $section priority "4"
|
config_get hook_priority $section priority "4"
|
||||||
config_get update_frequency $section update_frequency '10s'
|
config_get update_frequency $section update_frequency '10s'
|
||||||
config_get log_level $section log_level 'info'
|
config_get log_level $section log_level 'info'
|
||||||
config_get api_url $section api_url "http://127.0.0.1:8080"
|
config_get api_url $section api_url "http://127.0.0.1:8180"
|
||||||
config_get api_key $section api_key "API_KEY"
|
config_get api_key $section api_key "API_KEY"
|
||||||
config_get_bool ipv6 $section ipv6 '1'
|
config_get_bool ipv6 $section ipv6 '1'
|
||||||
config_get deny_action $section deny_action "drop"
|
config_get deny_action $section deny_action "drop"
|
||||||
|
|||||||
@ -8,7 +8,7 @@ config bouncer
|
|||||||
option enabled '0'
|
option enabled '0'
|
||||||
option ipv4 '1'
|
option ipv4 '1'
|
||||||
option ipv6 '1'
|
option ipv6 '1'
|
||||||
option api_url 'http://127.0.0.1:8080/'
|
option api_url 'http://127.0.0.1:8180/'
|
||||||
option api_key ''
|
option api_key ''
|
||||||
option update_frequency '10s'
|
option update_frequency '10s'
|
||||||
option priority '4'
|
option priority '4'
|
||||||
|
|||||||
0
package/secubox/secubox-app-cyberfeed/files/etc/init.d/cyberfeed
Normal file → Executable file
0
package/secubox/secubox-app-cyberfeed/files/etc/init.d/cyberfeed
Normal file → Executable file
0
package/secubox/secubox-app-gitea/files/etc/init.d/gitea
Normal file → Executable file
0
package/secubox/secubox-app-gitea/files/etc/init.d/gitea
Normal file → Executable file
0
package/secubox/secubox-app-glances/files/etc/init.d/glances
Normal file → Executable file
0
package/secubox/secubox-app-glances/files/etc/init.d/glances
Normal file → Executable file
@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=secubox-app-haproxy
|
PKG_NAME:=secubox-app-haproxy
|
||||||
PKG_VERSION:=1.0.0
|
PKG_VERSION:=1.0.0
|
||||||
PKG_RELEASE:=19
|
PKG_RELEASE:=21
|
||||||
|
|
||||||
PKG_MAINTAINER:=CyberMind <contact@cybermind.fr>
|
PKG_MAINTAINER:=CyberMind <contact@cybermind.fr>
|
||||||
PKG_LICENSE:=MIT
|
PKG_LICENSE:=MIT
|
||||||
|
|||||||
0
package/secubox/secubox-app-haproxy/files/etc/init.d/haproxy
Normal file → Executable file
0
package/secubox/secubox-app-haproxy/files/etc/init.d/haproxy
Normal file → Executable file
@ -19,6 +19,7 @@ CONFIG_PATH="$DATA_PATH/config"
|
|||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
log_info() { echo "[INFO] $*"; logger -t haproxy "$*"; }
|
log_info() { echo "[INFO] $*"; logger -t haproxy "$*"; }
|
||||||
|
log_warn() { echo "[WARN] $*" >&2; logger -t haproxy -p warning "$*"; }
|
||||||
log_error() { echo "[ERROR] $*" >&2; logger -t haproxy -p err "$*"; }
|
log_error() { echo "[ERROR] $*" >&2; logger -t haproxy -p err "$*"; }
|
||||||
log_debug() { [ "$DEBUG" = "1" ] && echo "[DEBUG] $*"; }
|
log_debug() { [ "$DEBUG" = "1" ] && echo "[DEBUG] $*"; }
|
||||||
|
|
||||||
@ -44,6 +45,7 @@ load_config() {
|
|||||||
memory_limit="$(uci_get main.memory_limit)" || memory_limit="256M"
|
memory_limit="$(uci_get main.memory_limit)" || memory_limit="256M"
|
||||||
maxconn="$(uci_get main.maxconn)" || maxconn="4096"
|
maxconn="$(uci_get main.maxconn)" || maxconn="4096"
|
||||||
log_level="$(uci_get main.log_level)" || log_level="warning"
|
log_level="$(uci_get main.log_level)" || log_level="warning"
|
||||||
|
default_backend="$(uci_get main.default_backend)" || default_backend="default_luci"
|
||||||
|
|
||||||
CERTS_PATH="$data_path/certs"
|
CERTS_PATH="$data_path/certs"
|
||||||
CONFIG_PATH="$data_path/config"
|
CONFIG_PATH="$data_path/config"
|
||||||
@ -288,11 +290,12 @@ frontend stats
|
|||||||
frontend http-in
|
frontend http-in
|
||||||
bind *:80
|
bind *:80
|
||||||
mode http
|
mode http
|
||||||
default_backend fallback
|
default_backend default_luci
|
||||||
|
|
||||||
backend fallback
|
backend default_luci
|
||||||
mode http
|
mode http
|
||||||
server local 127.0.0.1:8080 check
|
balance roundrobin
|
||||||
|
server luci 192.168.255.1:8081 check
|
||||||
CFGEOF
|
CFGEOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -415,7 +418,7 @@ EOF
|
|||||||
# Add vhost ACLs for HTTP
|
# Add vhost ACLs for HTTP
|
||||||
config_foreach _add_vhost_acl vhost "http"
|
config_foreach _add_vhost_acl vhost "http"
|
||||||
|
|
||||||
echo " default_backend fallback"
|
echo " default_backend $default_backend"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# HTTPS Frontend (if certificates exist)
|
# HTTPS Frontend (if certificates exist)
|
||||||
@ -432,7 +435,7 @@ EOF
|
|||||||
# Add vhost ACLs for HTTPS
|
# Add vhost ACLs for HTTPS
|
||||||
config_foreach _add_vhost_acl vhost "https"
|
config_foreach _add_vhost_acl vhost "https"
|
||||||
|
|
||||||
echo " default_backend fallback"
|
echo " default_backend $default_backend"
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@ -481,18 +484,43 @@ _add_vhost_acl() {
|
|||||||
_generate_backends() {
|
_generate_backends() {
|
||||||
config_load haproxy
|
config_load haproxy
|
||||||
|
|
||||||
|
# Track which backends are generated
|
||||||
|
_generated_backends=""
|
||||||
|
|
||||||
# Generate each backend from UCI
|
# Generate each backend from UCI
|
||||||
config_foreach _generate_backend backend
|
config_foreach _generate_backend backend
|
||||||
|
|
||||||
# Only add default fallback if no "fallback" backend exists in UCI
|
# Collect all backends referenced by vhosts
|
||||||
if ! uci -q get haproxy.fallback >/dev/null 2>&1; then
|
_referenced_backends=""
|
||||||
|
_collect_vhost_backend() {
|
||||||
|
local section="$1"
|
||||||
|
local enabled backend
|
||||||
|
config_get enabled "$section" enabled "0"
|
||||||
|
[ "$enabled" = "1" ] || return
|
||||||
|
config_get backend "$section" backend
|
||||||
|
[ -n "$backend" ] && _referenced_backends="$_referenced_backends $backend"
|
||||||
|
}
|
||||||
|
config_foreach _collect_vhost_backend vhost
|
||||||
|
|
||||||
|
# Add default_backend to referenced list
|
||||||
|
_referenced_backends="$_referenced_backends $default_backend"
|
||||||
|
|
||||||
|
# Generate fallback backends for any referenced but not generated
|
||||||
|
# These common backends route to uhttpd on the host
|
||||||
|
for backend_name in default_luci luci apps; do
|
||||||
|
# Check if this backend is referenced
|
||||||
|
echo "$_referenced_backends" | grep -qw "$backend_name" || continue
|
||||||
|
# Check if already generated
|
||||||
|
echo "$_generated_backends" | grep -qw "$backend_name" && continue
|
||||||
|
# Generate fallback
|
||||||
cat << EOF
|
cat << EOF
|
||||||
|
|
||||||
backend fallback
|
backend $backend_name
|
||||||
mode http
|
mode http
|
||||||
http-request deny deny_status 503
|
balance roundrobin
|
||||||
|
server $backend_name 192.168.255.1:8081 check
|
||||||
EOF
|
EOF
|
||||||
fi
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
_generate_backend() {
|
_generate_backend() {
|
||||||
@ -507,6 +535,9 @@ _generate_backend() {
|
|||||||
config_get balance "$section" balance "roundrobin"
|
config_get balance "$section" balance "roundrobin"
|
||||||
config_get health_check "$section" health_check ""
|
config_get health_check "$section" health_check ""
|
||||||
|
|
||||||
|
# Track generated backend
|
||||||
|
_generated_backends="$_generated_backends $name"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "backend $name"
|
echo "backend $name"
|
||||||
echo " mode $mode"
|
echo " mode $mode"
|
||||||
@ -759,7 +790,7 @@ cmd_cert_add() {
|
|||||||
# Register account if needed
|
# Register account if needed
|
||||||
if [ ! -f "$LE_WORKING_DIR/account.conf" ]; then
|
if [ ! -f "$LE_WORKING_DIR/account.conf" ]; then
|
||||||
log_info "Registering ACME account..."
|
log_info "Registering ACME account..."
|
||||||
"$ACME_SH" --register-account -m "$email" $staging_flag --home "$LE_WORKING_DIR" || true
|
"$ACME_SH" --register-account -m "$email" --server letsencrypt $staging_flag --home "$LE_WORKING_DIR" || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if HAProxy is using the port
|
# Check if HAProxy is using the port
|
||||||
@ -775,6 +806,7 @@ cmd_cert_add() {
|
|||||||
log_info "Issuing certificate (standalone mode on port $http_port)..."
|
log_info "Issuing certificate (standalone mode on port $http_port)..."
|
||||||
local acme_result=0
|
local acme_result=0
|
||||||
"$ACME_SH" --issue -d "$domain" \
|
"$ACME_SH" --issue -d "$domain" \
|
||||||
|
--server letsencrypt \
|
||||||
--standalone --httpport "$http_port" \
|
--standalone --httpport "$http_port" \
|
||||||
--keylength "$key_type" \
|
--keylength "$key_type" \
|
||||||
$staging_flag \
|
$staging_flag \
|
||||||
|
|||||||
@ -45,7 +45,7 @@ frontend http-in
|
|||||||
|
|
||||||
# Default: redirect to HTTPS
|
# Default: redirect to HTTPS
|
||||||
http-request redirect scheme https code 301 unless is_acme
|
http-request redirect scheme https code 301 unless is_acme
|
||||||
default_backend fallback
|
default_backend default_luci
|
||||||
|
|
||||||
# HTTPS frontend - SSL termination
|
# HTTPS frontend - SSL termination
|
||||||
frontend https-in
|
frontend https-in
|
||||||
@ -62,14 +62,15 @@ frontend https-in
|
|||||||
http-request set-header X-Real-IP %[src]
|
http-request set-header X-Real-IP %[src]
|
||||||
http-request set-header X-Forwarded-For %[src]
|
http-request set-header X-Forwarded-For %[src]
|
||||||
|
|
||||||
default_backend fallback
|
default_backend default_luci
|
||||||
|
|
||||||
# ACME challenge backend
|
# ACME challenge backend
|
||||||
backend acme
|
backend acme
|
||||||
mode http
|
mode http
|
||||||
server acme 127.0.0.1:8080 check
|
server acme 127.0.0.1:8080 check
|
||||||
|
|
||||||
# Fallback backend
|
# Default LuCI backend - routes to uhttpd
|
||||||
backend fallback
|
backend default_luci
|
||||||
mode http
|
mode http
|
||||||
http-request deny deny_status 503
|
balance roundrobin
|
||||||
|
server luci 192.168.255.1:8081 check
|
||||||
|
|||||||
@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=secubox-app-hexojs
|
PKG_NAME:=secubox-app-hexojs
|
||||||
PKG_VERSION:=1.0.0
|
PKG_VERSION:=1.0.0
|
||||||
PKG_RELEASE:=6
|
PKG_RELEASE:=8
|
||||||
PKG_ARCH:=all
|
PKG_ARCH:=all
|
||||||
|
|
||||||
PKG_MAINTAINER:=CyberMind Studio <contact@cybermind.fr>
|
PKG_MAINTAINER:=CyberMind Studio <contact@cybermind.fr>
|
||||||
|
|||||||
0
package/secubox/secubox-app-hexojs/files/etc/init.d/hexojs
Normal file → Executable file
0
package/secubox/secubox-app-hexojs/files/etc/init.d/hexojs
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
0
package/secubox/secubox-app-localai/files/etc/init.d/localai
Normal file → Executable file
0
package/secubox/secubox-app-localai/files/etc/init.d/localai
Normal file → Executable file
0
package/secubox/secubox-app-magicmirror2/files/etc/init.d/magicmirror2
Normal file → Executable file
0
package/secubox/secubox-app-magicmirror2/files/etc/init.d/magicmirror2
Normal file → Executable file
0
package/secubox/secubox-app-metabolizer/files/etc/init.d/metabolizer
Normal file → Executable file
0
package/secubox/secubox-app-metabolizer/files/etc/init.d/metabolizer
Normal file → Executable file
0
package/secubox/secubox-app-mmpm/files/etc/init.d/mmpm
Normal file → Executable file
0
package/secubox/secubox-app-mmpm/files/etc/init.d/mmpm
Normal file → Executable file
0
package/secubox/secubox-app-ollama/files/etc/init.d/ollama
Normal file → Executable file
0
package/secubox/secubox-app-ollama/files/etc/init.d/ollama
Normal file → Executable file
0
package/secubox/secubox-app-picobrew/files/etc/init.d/picobrew
Normal file → Executable file
0
package/secubox/secubox-app-picobrew/files/etc/init.d/picobrew
Normal file → Executable file
@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=secubox-app-streamlit
|
PKG_NAME:=secubox-app-streamlit
|
||||||
PKG_VERSION:=1.0.0
|
PKG_VERSION:=1.0.0
|
||||||
PKG_RELEASE:=4
|
PKG_RELEASE:=5
|
||||||
PKG_ARCH:=all
|
PKG_ARCH:=all
|
||||||
|
|
||||||
PKG_MAINTAINER:=CyberMind Studio <contact@cybermind.fr>
|
PKG_MAINTAINER:=CyberMind Studio <contact@cybermind.fr>
|
||||||
@ -22,22 +22,25 @@ define Package/secubox-app-streamlit
|
|||||||
PKGARCH:=all
|
PKGARCH:=all
|
||||||
SUBMENU:=SecuBox Apps
|
SUBMENU:=SecuBox Apps
|
||||||
TITLE:=SecuBox Streamlit Platform
|
TITLE:=SecuBox Streamlit Platform
|
||||||
DEPENDS:=+uci +libuci +jsonfilter +wget-ssl +tar +lxc +lxc-common
|
DEPENDS:=+uci +libuci +jsonfilter +wget-ssl +tar +lxc +lxc-common +git
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define Package/secubox-app-streamlit/description
|
define Package/secubox-app-streamlit/description
|
||||||
Streamlit App Platform - Self-hosted Python data app platform
|
Streamlit App Platform - Self-hosted Python data app platform
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
- Run Streamlit apps in LXC container
|
- Folder-based app structure (app.py, requirements.txt, .streamlit/)
|
||||||
- Multi-instance support (multiple apps on different ports)
|
- Multi-instance support (multiple apps on different ports)
|
||||||
- Python 3.12 with Streamlit 1.53.x
|
- Gitea integration for app deployment and updates
|
||||||
- Auto-install requirements.txt dependencies
|
- Python 3.12 with Streamlit in LXC container
|
||||||
|
- Auto-install requirements.txt with hash-based caching
|
||||||
- HAProxy publish wizard for vhost routing
|
- HAProxy publish wizard for vhost routing
|
||||||
- Web dashboard integration
|
- Web dashboard integration
|
||||||
- Configurable port and memory limits
|
|
||||||
|
|
||||||
Runs in LXC container with Alpine Linux.
|
App folder structure:
|
||||||
|
/srv/streamlit/apps/<appname>/
|
||||||
|
app.py, requirements.txt, .streamlit/
|
||||||
|
|
||||||
Configure in /etc/config/streamlit.
|
Configure in /etc/config/streamlit.
|
||||||
endef
|
endef
|
||||||
|
|
||||||
@ -74,7 +77,9 @@ define Package/secubox-app-streamlit/postinst
|
|||||||
echo ""
|
echo ""
|
||||||
echo "Web interface: http://<router-ip>:8501"
|
echo "Web interface: http://<router-ip>:8501"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Deploy your apps with: streamlitctl app add <name> /path/to/app.py"
|
echo "Create apps: streamlitctl app create myapp"
|
||||||
|
echo "Add instance: streamlitctl instance add myapp 8502"
|
||||||
|
echo "Gitea clone: streamlitctl gitea clone myapp user/repo"
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
0
package/secubox/secubox-app-streamlit/files/etc/init.d/streamlit
Normal file → Executable file
0
package/secubox/secubox-app-streamlit/files/etc/init.d/streamlit
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
0
package/secubox/secubox-app-tor/files/etc/init.d/tor-shield
Normal file → Executable file
0
package/secubox/secubox-app-tor/files/etc/init.d/tor-shield
Normal file → Executable file
235
package/secubox/secubox-core/files/etc/init.d/secubox-extroot
Executable file
235
package/secubox/secubox-core/files/etc/init.d/secubox-extroot
Executable file
@ -0,0 +1,235 @@
|
|||||||
|
#!/bin/sh /etc/rc.common
|
||||||
|
# SecuBox Extroot Auto-Setup
|
||||||
|
# Automatically configures overlay on mmcblk0p3 after fresh install/upgrade
|
||||||
|
# Copyright (C) 2025 CyberMind.fr
|
||||||
|
|
||||||
|
START=10
|
||||||
|
STOP=90
|
||||||
|
|
||||||
|
EXTRA_COMMANDS="status setup"
|
||||||
|
EXTRA_HELP=" status Show extroot status
|
||||||
|
setup Configure extroot on mmcblk0p3"
|
||||||
|
|
||||||
|
OVERLAY_DEV="/dev/mmcblk0p3"
|
||||||
|
OVERLAY_LABEL="rootfs_data"
|
||||||
|
LOG_TAG="secubox-extroot"
|
||||||
|
|
||||||
|
log() { logger -t "$LOG_TAG" "$*"; echo "$*"; }
|
||||||
|
|
||||||
|
# Check if extroot is already active
|
||||||
|
is_extroot_active() {
|
||||||
|
mount | grep -q "on /overlay type" && [ -d /overlay/upper ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if overlay partition exists
|
||||||
|
has_overlay_partition() {
|
||||||
|
[ -b "$OVERLAY_DEV" ] || return 1
|
||||||
|
blkid "$OVERLAY_DEV" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get filesystem type of overlay partition
|
||||||
|
get_overlay_fstype() {
|
||||||
|
blkid "$OVERLAY_DEV" -s TYPE -o value 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get UUID of overlay partition
|
||||||
|
get_overlay_uuid() {
|
||||||
|
blkid "$OVERLAY_DEV" -s UUID -o value 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install required filesystem support
|
||||||
|
install_fs_support() {
|
||||||
|
local fstype="$1"
|
||||||
|
|
||||||
|
case "$fstype" in
|
||||||
|
f2fs)
|
||||||
|
if ! opkg list-installed 2>/dev/null | grep -q "^kmod-fs-f2fs"; then
|
||||||
|
log "Installing f2fs support..."
|
||||||
|
opkg update >/dev/null 2>&1
|
||||||
|
opkg install kmod-fs-f2fs f2fs-tools 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
ext4)
|
||||||
|
if ! opkg list-installed 2>/dev/null | grep -q "^kmod-fs-ext4"; then
|
||||||
|
log "Installing ext4 support..."
|
||||||
|
opkg update >/dev/null 2>&1
|
||||||
|
opkg install kmod-fs-ext4 e2fsprogs 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Always ensure block-mount is available
|
||||||
|
if ! opkg list-installed 2>/dev/null | grep -q "^block-mount"; then
|
||||||
|
log "Installing block-mount..."
|
||||||
|
opkg install block-mount 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Prepare overlay partition structure
|
||||||
|
prepare_overlay() {
|
||||||
|
local fstype="$1"
|
||||||
|
local mount_point="/tmp/extroot_setup"
|
||||||
|
|
||||||
|
mkdir -p "$mount_point"
|
||||||
|
|
||||||
|
# Mount the partition
|
||||||
|
if ! mount -t "$fstype" "$OVERLAY_DEV" "$mount_point" 2>/dev/null; then
|
||||||
|
log "Failed to mount $OVERLAY_DEV"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create overlay directories
|
||||||
|
mkdir -p "$mount_point/upper"
|
||||||
|
mkdir -p "$mount_point/work"
|
||||||
|
|
||||||
|
# Copy existing data if overlay was previously active
|
||||||
|
if [ -d /overlay/upper ] && [ "$(ls -A /overlay/upper 2>/dev/null)" ]; then
|
||||||
|
log "Migrating existing overlay data..."
|
||||||
|
cp -a /overlay/upper/* "$mount_point/upper/" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
sync
|
||||||
|
umount "$mount_point"
|
||||||
|
rmdir "$mount_point"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Configure fstab for extroot
|
||||||
|
configure_fstab() {
|
||||||
|
local uuid="$1"
|
||||||
|
local fstype="$2"
|
||||||
|
|
||||||
|
# Check if already configured
|
||||||
|
if uci -q get fstab.extroot >/dev/null 2>&1; then
|
||||||
|
local current_uuid=$(uci -q get fstab.extroot.uuid)
|
||||||
|
if [ "$current_uuid" = "$uuid" ]; then
|
||||||
|
log "Extroot already configured"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Configuring fstab for extroot..."
|
||||||
|
|
||||||
|
# Remove old extroot config if exists
|
||||||
|
uci -q delete fstab.extroot 2>/dev/null || true
|
||||||
|
|
||||||
|
# Add new extroot configuration
|
||||||
|
uci set fstab.extroot=mount
|
||||||
|
uci set fstab.extroot.target="/overlay"
|
||||||
|
uci set fstab.extroot.uuid="$uuid"
|
||||||
|
uci set fstab.extroot.enabled="1"
|
||||||
|
|
||||||
|
if [ "$fstype" = "f2fs" ]; then
|
||||||
|
uci set fstab.extroot.fstype="f2fs"
|
||||||
|
uci set fstab.extroot.options="rw,noatime"
|
||||||
|
fi
|
||||||
|
|
||||||
|
uci commit fstab
|
||||||
|
|
||||||
|
log "Fstab configured - reboot required to activate"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main setup function
|
||||||
|
setup_extroot() {
|
||||||
|
log "SecuBox Extroot Setup starting..."
|
||||||
|
|
||||||
|
# Check if already active
|
||||||
|
if is_extroot_active; then
|
||||||
|
log "Extroot already active on /overlay"
|
||||||
|
df -h /overlay | tail -1
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for overlay partition
|
||||||
|
if ! has_overlay_partition; then
|
||||||
|
log "No overlay partition found at $OVERLAY_DEV"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get filesystem info
|
||||||
|
local fstype=$(get_overlay_fstype)
|
||||||
|
local uuid=$(get_overlay_uuid)
|
||||||
|
|
||||||
|
if [ -z "$fstype" ] || [ -z "$uuid" ]; then
|
||||||
|
log "Cannot determine filesystem type or UUID"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Found overlay partition: $OVERLAY_DEV ($fstype, UUID=$uuid)"
|
||||||
|
|
||||||
|
# Install filesystem support
|
||||||
|
install_fs_support "$fstype"
|
||||||
|
|
||||||
|
# Prepare the partition
|
||||||
|
if ! prepare_overlay "$fstype"; then
|
||||||
|
log "Failed to prepare overlay partition"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Configure fstab
|
||||||
|
if ! configure_fstab "$uuid" "$fstype"; then
|
||||||
|
log "Failed to configure fstab"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Extroot setup complete - REBOOT REQUIRED"
|
||||||
|
|
||||||
|
# Create flag file to indicate reboot needed
|
||||||
|
touch /tmp/extroot-reboot-required
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
# Only run setup if not already configured or after upgrade
|
||||||
|
if is_extroot_active; then
|
||||||
|
log "Extroot active"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if has_overlay_partition; then
|
||||||
|
setup_extroot
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
boot() {
|
||||||
|
start
|
||||||
|
}
|
||||||
|
|
||||||
|
# Manual commands
|
||||||
|
status() {
|
||||||
|
echo "=== SecuBox Extroot Status ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if is_extroot_active; then
|
||||||
|
echo "Status: ACTIVE"
|
||||||
|
echo ""
|
||||||
|
echo "Overlay mount:"
|
||||||
|
mount | grep overlay
|
||||||
|
echo ""
|
||||||
|
echo "Storage:"
|
||||||
|
df -h /overlay
|
||||||
|
else
|
||||||
|
echo "Status: NOT ACTIVE"
|
||||||
|
echo ""
|
||||||
|
if has_overlay_partition; then
|
||||||
|
echo "Overlay partition available: $OVERLAY_DEV"
|
||||||
|
echo "Filesystem: $(get_overlay_fstype)"
|
||||||
|
echo "UUID: $(get_overlay_uuid)"
|
||||||
|
echo ""
|
||||||
|
echo "Run '/etc/init.d/secubox-extroot setup' to configure"
|
||||||
|
else
|
||||||
|
echo "No overlay partition found"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
setup_extroot
|
||||||
|
}
|
||||||
23
secubox-tools/deploy-extroot-init.sh
Executable file
23
secubox-tools/deploy-extroot-init.sh
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Deploy SecuBox Extroot init.d script to router
|
||||||
|
# Usage: ./deploy-extroot-init.sh [ROUTER_IP]
|
||||||
|
|
||||||
|
ROUTER_IP="${1:-192.168.255.1}"
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
echo "Deploying secubox-extroot to $ROUTER_IP..."
|
||||||
|
|
||||||
|
# Deploy the init script
|
||||||
|
cat "$SCRIPT_DIR/../package/secubox/secubox-core/files/etc/init.d/secubox-extroot" | \
|
||||||
|
ssh root@$ROUTER_IP 'cat > /etc/init.d/secubox-extroot && chmod 755 /etc/init.d/secubox-extroot'
|
||||||
|
|
||||||
|
# Enable and run setup
|
||||||
|
ssh root@$ROUTER_IP '
|
||||||
|
/etc/init.d/secubox-extroot enable
|
||||||
|
/etc/init.d/secubox-extroot setup
|
||||||
|
/etc/init.d/secubox-extroot status
|
||||||
|
'
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done! If setup was successful, reboot to activate extroot:"
|
||||||
|
echo " ssh root@$ROUTER_IP reboot"
|
||||||
226
secubox-tools/deploy-remote.sh
Executable file
226
secubox-tools/deploy-remote.sh
Executable file
@ -0,0 +1,226 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# SecuBox Remote Deployment Script
|
||||||
|
# Deploys all SecuBox packages to a remote OpenWrt router
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
BUILD_DIR="$SCRIPT_DIR/sdk/bin/packages/aarch64_cortex-a72/secubox"
|
||||||
|
ROUTER_IP="${1:-192.168.255.1}"
|
||||||
|
ROUTER_USER="${2:-root}"
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
info() { echo -e "${BLUE}ℹ️ $*${NC}"; }
|
||||||
|
success() { echo -e "${GREEN}✅ $*${NC}"; }
|
||||||
|
warn() { echo -e "${YELLOW}⚠️ $*${NC}"; }
|
||||||
|
error() { echo -e "${RED}❌ $*${NC}"; exit 1; }
|
||||||
|
|
||||||
|
# Check SSH connectivity
|
||||||
|
check_ssh() {
|
||||||
|
info "Checking SSH connectivity to $ROUTER_IP..."
|
||||||
|
if ! ssh -o ConnectTimeout=10 "$ROUTER_USER@$ROUTER_IP" "echo ok" 2>/dev/null; then
|
||||||
|
error "Cannot connect to $ROUTER_IP via SSH"
|
||||||
|
fi
|
||||||
|
success "SSH connection OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup local feed on router
|
||||||
|
setup_feed() {
|
||||||
|
info "Setting up local package feed on router..."
|
||||||
|
|
||||||
|
ssh "$ROUTER_USER@$ROUTER_IP" 'mkdir -p /www/secubox-feed /tmp/secubox-install'
|
||||||
|
|
||||||
|
# Copy packages
|
||||||
|
info "Copying packages to router (this may take a while)..."
|
||||||
|
scp -q "$BUILD_DIR"/*.ipk "$ROUTER_USER@$ROUTER_IP:/www/secubox-feed/" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Generate Packages index
|
||||||
|
info "Generating package index..."
|
||||||
|
ssh "$ROUTER_USER@$ROUTER_IP" 'cd /www/secubox-feed && {
|
||||||
|
rm -f Packages Packages.gz
|
||||||
|
for ipk in *.ipk; do
|
||||||
|
[ -f "$ipk" ] || continue
|
||||||
|
tar -xOzf "$ipk" ./control.tar.gz 2>/dev/null | tar -xOz ./control 2>/dev/null >> Packages
|
||||||
|
echo "Filename: $ipk" >> Packages
|
||||||
|
echo "" >> Packages
|
||||||
|
done
|
||||||
|
gzip -k Packages
|
||||||
|
}'
|
||||||
|
|
||||||
|
# Configure opkg
|
||||||
|
ssh "$ROUTER_USER@$ROUTER_IP" 'grep -q "secubox-feed" /etc/opkg/customfeeds.conf 2>/dev/null || {
|
||||||
|
echo "src/gz secubox file:///www/secubox-feed" >> /etc/opkg/customfeeds.conf
|
||||||
|
}'
|
||||||
|
|
||||||
|
success "Local feed configured"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install core packages first
|
||||||
|
install_core() {
|
||||||
|
info "Installing core SecuBox packages..."
|
||||||
|
|
||||||
|
ssh "$ROUTER_USER@$ROUTER_IP" 'opkg update 2>/dev/null
|
||||||
|
|
||||||
|
# Core packages (order matters)
|
||||||
|
for pkg in secubox-core; do
|
||||||
|
if [ -f "/www/secubox-feed/${pkg}_"*.ipk ]; then
|
||||||
|
echo "Installing $pkg..."
|
||||||
|
opkg install --force-reinstall /www/secubox-feed/${pkg}_*.ipk 2>&1 || true
|
||||||
|
fi
|
||||||
|
done'
|
||||||
|
|
||||||
|
success "Core packages installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install LuCI apps
|
||||||
|
install_luci_apps() {
|
||||||
|
info "Installing LuCI applications..."
|
||||||
|
|
||||||
|
ssh "$ROUTER_USER@$ROUTER_IP" '
|
||||||
|
cd /www/secubox-feed
|
||||||
|
|
||||||
|
# Skip large bonus package and packages with missing deps
|
||||||
|
SKIP="secubox-bonus|auth-guardian|ksm-manager|vhost-manager|zigbee"
|
||||||
|
|
||||||
|
for ipk in luci-app-*.ipk; do
|
||||||
|
[ -f "$ipk" ] || continue
|
||||||
|
|
||||||
|
# Skip excluded packages
|
||||||
|
if echo "$ipk" | grep -qE "$SKIP"; then
|
||||||
|
echo "Skipping: $ipk (excluded)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
pkg_name=$(echo "$ipk" | sed "s/_[0-9].*//")
|
||||||
|
echo "Installing: $pkg_name"
|
||||||
|
opkg install --force-reinstall "/www/secubox-feed/$ipk" 2>&1 | grep -v "^Collected" || true
|
||||||
|
done'
|
||||||
|
|
||||||
|
success "LuCI apps installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install service packages
|
||||||
|
install_services() {
|
||||||
|
info "Installing service packages..."
|
||||||
|
|
||||||
|
ssh "$ROUTER_USER@$ROUTER_IP" '
|
||||||
|
cd /www/secubox-feed
|
||||||
|
|
||||||
|
for ipk in secubox-app-*.ipk; do
|
||||||
|
[ -f "$ipk" ] || continue
|
||||||
|
|
||||||
|
pkg_name=$(echo "$ipk" | sed "s/_[0-9].*//")
|
||||||
|
echo "Installing: $pkg_name"
|
||||||
|
opkg install --force-reinstall "/www/secubox-feed/$ipk" 2>&1 | grep -v "^Collected" || true
|
||||||
|
done'
|
||||||
|
|
||||||
|
success "Service packages installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fix permissions and restart services
|
||||||
|
finalize() {
|
||||||
|
info "Finalizing installation..."
|
||||||
|
|
||||||
|
ssh "$ROUTER_USER@$ROUTER_IP" '
|
||||||
|
# Fix RPCD script permissions
|
||||||
|
chmod 755 /usr/libexec/rpcd/luci.* 2>/dev/null || true
|
||||||
|
|
||||||
|
# Restart rpcd
|
||||||
|
/etc/init.d/rpcd restart
|
||||||
|
|
||||||
|
# Clear LuCI cache
|
||||||
|
rm -rf /tmp/luci-modulecache /tmp/luci-indexcache 2>/dev/null
|
||||||
|
|
||||||
|
# Show installed packages
|
||||||
|
echo ""
|
||||||
|
echo "=== Installed SecuBox packages ==="
|
||||||
|
opkg list-installed | grep -E "^(luci-app-|secubox-)" | wc -l
|
||||||
|
echo "packages installed"
|
||||||
|
'
|
||||||
|
|
||||||
|
success "Installation complete!"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate apps-local.json for store UI
|
||||||
|
generate_apps_json() {
|
||||||
|
info "Generating apps manifest..."
|
||||||
|
|
||||||
|
ssh "$ROUTER_USER@$ROUTER_IP" 'cd /www/secubox-feed && {
|
||||||
|
cat > apps-local.json << "HEADER"
|
||||||
|
{
|
||||||
|
"feed_url": "/secubox-feed",
|
||||||
|
"generated": "TIMESTAMP",
|
||||||
|
"packages": [
|
||||||
|
HEADER
|
||||||
|
sed -i "s/TIMESTAMP/$(date -Iseconds)/" apps-local.json
|
||||||
|
|
||||||
|
first=true
|
||||||
|
for pkg in *.ipk; do
|
||||||
|
[ -f "$pkg" ] || continue
|
||||||
|
filename="$pkg"
|
||||||
|
name=$(echo "$filename" | sed "s/_[0-9].*$//")
|
||||||
|
version=$(echo "$filename" | sed "s/^[^_]*_//; s/_[^_]*$//")
|
||||||
|
size=$(stat -c%s "$pkg" 2>/dev/null || ls -l "$pkg" | awk "{print \$5}")
|
||||||
|
|
||||||
|
# Category based on name
|
||||||
|
category="utility"
|
||||||
|
case "$name" in
|
||||||
|
*crowdsec*|*mitmproxy*|*tor*) category="security";;
|
||||||
|
*bandwidth*|*traffic*|*network*|*wireguard*) category="network";;
|
||||||
|
*hexojs*|*gitea*|*streamlit*) category="apps";;
|
||||||
|
*secubox*) category="system";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
[ "$first" = "true" ] || echo "," >> apps-local.json
|
||||||
|
first=false
|
||||||
|
|
||||||
|
cat >> apps-local.json << ENTRY
|
||||||
|
{
|
||||||
|
"name": "$name",
|
||||||
|
"version": "$version",
|
||||||
|
"filename": "$filename",
|
||||||
|
"size": $size,
|
||||||
|
"category": "$category"
|
||||||
|
}
|
||||||
|
ENTRY
|
||||||
|
done
|
||||||
|
|
||||||
|
echo " ]" >> apps-local.json
|
||||||
|
echo "}" >> apps-local.json
|
||||||
|
}'
|
||||||
|
|
||||||
|
success "Apps manifest generated"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main
|
||||||
|
main() {
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo " SecuBox Remote Deployment"
|
||||||
|
echo " Target: $ROUTER_USER@$ROUTER_IP"
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
check_ssh
|
||||||
|
setup_feed
|
||||||
|
install_core
|
||||||
|
install_services
|
||||||
|
install_luci_apps
|
||||||
|
generate_apps_json
|
||||||
|
finalize
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
success "Deployment complete!"
|
||||||
|
echo " Access LuCI at: http://$ROUTER_IP"
|
||||||
|
echo " Local feed at: http://$ROUTER_IP/secubox-feed/"
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
85
secubox-tools/fix-extroot.sh
Executable file
85
secubox-tools/fix-extroot.sh
Executable file
@ -0,0 +1,85 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Fix extroot by formatting mmcblk0p3 fresh
|
||||||
|
# Run this from console or SSH after failsafe boot
|
||||||
|
|
||||||
|
OVERLAY_DEV="/dev/mmcblk0p3"
|
||||||
|
|
||||||
|
echo "=== SecuBox Extroot Fix ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Stop services using overlay
|
||||||
|
echo "Stopping services..."
|
||||||
|
for svc in /etc/init.d/*; do
|
||||||
|
[ -x "$svc" ] && "$svc" stop 2>/dev/null &
|
||||||
|
done
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
# Kill processes using overlay
|
||||||
|
echo "Killing processes using overlay..."
|
||||||
|
fuser -km /overlay 2>/dev/null || true
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# Unmount everything
|
||||||
|
echo "Unmounting filesystems..."
|
||||||
|
umount -l /overlay 2>/dev/null || true
|
||||||
|
umount -l /mnt/extroot 2>/dev/null || true
|
||||||
|
umount -l "$OVERLAY_DEV" 2>/dev/null || true
|
||||||
|
sync
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# Verify unmounted
|
||||||
|
if mount | grep -q "$OVERLAY_DEV"; then
|
||||||
|
echo "ERROR: Cannot unmount $OVERLAY_DEV"
|
||||||
|
echo "Try: reboot into failsafe mode and run this script"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Formatting $OVERLAY_DEV as f2fs..."
|
||||||
|
mkfs.f2fs -f -l rootfs_data "$OVERLAY_DEV" || {
|
||||||
|
echo "Format failed! Try: mkfs.ext4 -L rootfs_data $OVERLAY_DEV"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Preparing overlay structure..."
|
||||||
|
mkdir -p /mnt/extroot
|
||||||
|
mount -t f2fs "$OVERLAY_DEV" /mnt/extroot
|
||||||
|
mkdir -p /mnt/extroot/upper /mnt/extroot/work
|
||||||
|
sync
|
||||||
|
umount /mnt/extroot
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Configuring fstab..."
|
||||||
|
UUID=$(blkid "$OVERLAY_DEV" -s UUID -o value)
|
||||||
|
echo "UUID: $UUID"
|
||||||
|
|
||||||
|
# Write fstab config
|
||||||
|
cat > /etc/config/fstab << EOF
|
||||||
|
config global
|
||||||
|
option anon_swap '0'
|
||||||
|
option anon_mount '0'
|
||||||
|
option auto_swap '0'
|
||||||
|
option auto_mount '1'
|
||||||
|
option delay_root '5'
|
||||||
|
option check_fs '1'
|
||||||
|
|
||||||
|
config mount 'extroot'
|
||||||
|
option target '/overlay'
|
||||||
|
option uuid '$UUID'
|
||||||
|
option enabled '1'
|
||||||
|
option fstype 'f2fs'
|
||||||
|
option options 'rw,noatime'
|
||||||
|
|
||||||
|
config mount 'srv'
|
||||||
|
option target '/srv'
|
||||||
|
option uuid '443e8304-4d3b-4fd0-9f26-74c50ba64113'
|
||||||
|
option enabled '1'
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Setup complete ==="
|
||||||
|
echo ""
|
||||||
|
cat /etc/config/fstab
|
||||||
|
echo ""
|
||||||
|
echo "Now reboot: reboot"
|
||||||
176
secubox-tools/setup-extroot.sh
Executable file
176
secubox-tools/setup-extroot.sh
Executable file
@ -0,0 +1,176 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# SecuBox Extroot Setup Script
|
||||||
|
# Configures overlay on mmcblk0p3 for expanded storage
|
||||||
|
# Run after fresh install or upgrade
|
||||||
|
|
||||||
|
ROUTER_IP="${1:-192.168.255.1}"
|
||||||
|
ROUTER_USER="${2:-root}"
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
info() { echo -e "${BLUE}ℹ️ $*${NC}"; }
|
||||||
|
success() { echo -e "${GREEN}✅ $*${NC}"; }
|
||||||
|
warn() { echo -e "${YELLOW}⚠️ $*${NC}"; }
|
||||||
|
error() { echo -e "${RED}❌ $*${NC}"; }
|
||||||
|
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo " SecuBox Extroot Setup"
|
||||||
|
echo " Target: $ROUTER_USER@$ROUTER_IP"
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
info "Connecting to router..."
|
||||||
|
|
||||||
|
ssh "$ROUTER_USER@$ROUTER_IP" '
|
||||||
|
#!/bin/sh
|
||||||
|
# Extroot setup script - runs on router
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
OVERLAY_DEV="/dev/mmcblk0p3"
|
||||||
|
OVERLAY_MOUNT="/mnt/extroot"
|
||||||
|
|
||||||
|
echo "=== Checking current setup ==="
|
||||||
|
echo "Root filesystem:"
|
||||||
|
df -h /
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if overlay already mounted
|
||||||
|
if mount | grep -q "overlay on / "; then
|
||||||
|
echo "Overlay already active!"
|
||||||
|
df -h /overlay
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if partition exists
|
||||||
|
if [ ! -b "$OVERLAY_DEV" ]; then
|
||||||
|
echo "ERROR: Partition $OVERLAY_DEV not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get partition info
|
||||||
|
FSTYPE=$(blkid "$OVERLAY_DEV" -s TYPE -o value 2>/dev/null || echo "unknown")
|
||||||
|
echo "Partition: $OVERLAY_DEV"
|
||||||
|
echo "Filesystem: $FSTYPE"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Install required packages if not present
|
||||||
|
echo "=== Checking required packages ==="
|
||||||
|
opkg update 2>/dev/null || true
|
||||||
|
|
||||||
|
if [ "$FSTYPE" = "f2fs" ]; then
|
||||||
|
if ! opkg list-installed | grep -q "^kmod-fs-f2fs"; then
|
||||||
|
echo "Installing f2fs support..."
|
||||||
|
opkg install kmod-fs-f2fs f2fs-tools 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
elif [ "$FSTYPE" = "ext4" ]; then
|
||||||
|
if ! opkg list-installed | grep -q "^kmod-fs-ext4"; then
|
||||||
|
echo "Installing ext4 support..."
|
||||||
|
opkg install kmod-fs-ext4 e2fsprogs 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure block-mount is installed
|
||||||
|
if ! opkg list-installed | grep -q "^block-mount"; then
|
||||||
|
echo "Installing block-mount..."
|
||||||
|
opkg install block-mount 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Preparing overlay partition ==="
|
||||||
|
|
||||||
|
# Mount partition temporarily
|
||||||
|
mkdir -p "$OVERLAY_MOUNT"
|
||||||
|
mount -t "$FSTYPE" "$OVERLAY_DEV" "$OVERLAY_MOUNT" || {
|
||||||
|
echo "ERROR: Cannot mount $OVERLAY_DEV"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create overlay directories
|
||||||
|
mkdir -p "$OVERLAY_MOUNT/upper"
|
||||||
|
mkdir -p "$OVERLAY_MOUNT/work"
|
||||||
|
|
||||||
|
# Copy existing overlay data if any
|
||||||
|
if [ -d /overlay/upper ]; then
|
||||||
|
echo "Copying existing overlay data..."
|
||||||
|
cp -a /overlay/upper/* "$OVERLAY_MOUNT/upper/" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Sync
|
||||||
|
sync
|
||||||
|
|
||||||
|
# Unmount
|
||||||
|
umount "$OVERLAY_MOUNT"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Configuring fstab ==="
|
||||||
|
|
||||||
|
# Get block info
|
||||||
|
eval $(block info "$OVERLAY_DEV" | grep -o "UUID=\S*")
|
||||||
|
echo "UUID: $UUID"
|
||||||
|
|
||||||
|
# Configure fstab using UCI
|
||||||
|
uci -q delete fstab.extroot 2>/dev/null || true
|
||||||
|
uci set fstab.extroot=mount
|
||||||
|
uci set fstab.extroot.target="/overlay"
|
||||||
|
uci set fstab.extroot.uuid="$UUID"
|
||||||
|
uci set fstab.extroot.enabled="1"
|
||||||
|
if [ "$FSTYPE" = "f2fs" ]; then
|
||||||
|
uci set fstab.extroot.fstype="f2fs"
|
||||||
|
uci set fstab.extroot.options="rw,noatime"
|
||||||
|
fi
|
||||||
|
uci commit fstab
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Updated fstab ==="
|
||||||
|
cat /etc/config/fstab
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Setup complete! ==="
|
||||||
|
echo ""
|
||||||
|
echo "IMPORTANT: Reboot to activate the overlay"
|
||||||
|
echo "After reboot, /overlay will be mounted on the 14GB partition"
|
||||||
|
echo ""
|
||||||
|
echo "Run: reboot"
|
||||||
|
'
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
success "Extroot configuration complete!"
|
||||||
|
echo ""
|
||||||
|
warn "REBOOT REQUIRED to activate overlay"
|
||||||
|
echo ""
|
||||||
|
read -p "Reboot router now? [y/N] " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
info "Rebooting router..."
|
||||||
|
ssh "$ROUTER_USER@$ROUTER_IP" "reboot" 2>/dev/null || true
|
||||||
|
echo ""
|
||||||
|
info "Waiting for router to come back online..."
|
||||||
|
sleep 60
|
||||||
|
|
||||||
|
# Wait for router to come back
|
||||||
|
for i in {1..30}; do
|
||||||
|
if ssh -o ConnectTimeout=5 "$ROUTER_USER@$ROUTER_IP" "echo ok" 2>/dev/null; then
|
||||||
|
success "Router is back online!"
|
||||||
|
echo ""
|
||||||
|
ssh "$ROUTER_USER@$ROUTER_IP" '
|
||||||
|
echo "=== Overlay status ==="
|
||||||
|
mount | grep overlay || echo "No overlay (yet)"
|
||||||
|
echo ""
|
||||||
|
echo "=== Disk usage ==="
|
||||||
|
df -h / /overlay 2>/dev/null
|
||||||
|
'
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo "Waiting... ($i/30)"
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
error "Setup failed"
|
||||||
|
fi
|
||||||
Loading…
Reference in New Issue
Block a user