极空间获取 SSH 权限

极空间 SSH 开启及相关使用示例。

一、极空间 SSH

1.1 开启 SSH

极空间终于开放了 SSH 权限,真是来之不易。此前的限制简直像是在防“家贼”,让人颇感无奈。现在可以在「设置 → 系统设置 → 远程协助 → SSH」中开启 SSH 访问权限,同时默认的 Docker 应用也支持设置为 Privileged Mode,算是一次不小的进步。不过话说回来,它仍然对端口(仅允许 10000 以上)和账户做了不少限制。既然都已经开放权限了,这种“半放半收”的做法就显得有些矫情了。

关于安全方面的提醒:建议禁用密码登录,仅允许使用密钥登录

1.2 安装 1Panel 面板

话说回来,各位吴彦祖们,不考虑安装个 1Panel 面板,用以辅助管理系统吗?

bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)"
  • 使用面板肯定比面对黑乎乎的终端窗口方便,放着好好的 GUI 界面不用,岂不成了墨守成规之人。
  • 像宝塔面板这种广告多、强制绑定手机号的工具,并不适合在家用环境中使用(确信

注意事项:在安装 1Panel 时,其安装脚本会提示覆盖 Docker 的 daemon.json 文件,并将原始内容备份为同目录下的daemon.json.1panel_bak文件。从该备份文件中可以看出,极空间将 Docker 的数据目录设置在路径/data_n002/data/udata/real/zdocker下。因此,当 1Panel 覆盖该配置并重启 Docker 后,极空间自带的容器管理应用将无法识别原有的容器部署。解决方法是:将备份文件中的内容恢复覆盖回 daemon.json,然后重新启动 Docker 引擎,即可恢复极空间的容器管理功能。

二、使用教程

在获得 SSH 权限后,可以对极空间系统进行一定程度的修改和功能补全。

2.1 极空间登录页

极空间的登录页面存在一个令人困扰的跳转问题:当使用移动端 UA 访问网页时,页面会自动跳转到极空间的下载页面。为了解决这个问题,我们可以直接移除相关的跳转逻辑。具体操作如下:进入 /zspace/applications/services/pcweb/home 目录,找到并编辑 index.html 文件。

删除这个判断函数(点击展开)
<script>var j = function(url) {
window.stop && window.stop()
document.execCommand && document.execCommand("Stop", false)
window.location = url
}
function getCookie(key) {
var cookies = document.cookie.split("; ");
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i]
if (cookie.indexOf(key + "=") === 0) {
return decodeURIComponent(cookie.substring((key + "=").length, cookie.length))
}
}
return ""
}
if (getCookie('token') != '' && getCookie('nas_id') == '') {
j('/home/error/504.html?clear')
}
var ua = navigator.userAgent.toLowerCase()
var isMobile = !!ua.match(/iOS|iPhone|Android|windows Phone|BB\d+/i)
var isIPad = !!ua.match(/ipad/i)
var href = window.location.href
if(!Object.defineProperty||!Array.prototype.forEach) j("/home/error/browser.html")
else if (/^http:\/\/(\w+\.)?zconnect.cn((?!login\/jump).)*$/.test(href)) j('https' + href.substr(4))</script>

2.1.1 极空间样式修饰

和前文提到的修改index.html文件类似,我们可以手动插入自定义样式,这里是我目前做的修改:①修饰一下登录页面;②内部窗口最大化时隐藏顶部和左侧的菜单栏,完全最大化显示。

自定义样式
// SCSS TO CSS: https://www.dute.org/sass-to-css

@charset "UTF-8";

.copyright,
.loginFooter>.tc,
.login>.titleText div:not(:first-child) {
display: none;
}

$input-text: #fbf1f1;
$box-shadow: #0000001a;
$boder-color: #feffff59;
$background-color_0: #ffffff1a;
$background-color_1: #f4d2d280;
$background-color_2: #feffff59;

body.normal {
#app {
&:has(.login) {

.contain {
background-image: url(https://bu.dusays.com/2024/03/26/660293ff8fe00.jpg);
position: relative;
display: flex;
justify-content: center;
align-items: center;

.login {
background: #ffffff1a;
box-shadow: 0 25px 45px #0000001a;
transition: 0.5s;
border-radius: 2px;

&:hover,
&:has(input:focus) {
border-radius: 30px;
backdrop-filter: blur(10px);
}

.titleText {
&:hover {
&::before {
width: 60px;
}
}

&::before {
content: "";
position: relative;
display: block;
bottom: -40px;
width: 0px;
height: 3px;
background: white;
transition: 0.5s;
border-radius: 2px;
}
}

.el-button {
width: inherit;
background-color: $background-color_1;
transition: 0.5s;

&:hover {
transform: scale(0.98);
}
}

.loginFooter {
.el-checkbox {
transition: 0.5s;

&:hover {
transform: scale(1.1);
}

.el-checkbox__inner {
border: 1px solid $boder-color;
background-color: $background-color_2 !important;
}
}
}

.el-input {

&:hover,
&:has(input:focus) {
&::after {
width: 450px;
}
}

&::after {
width: 0;
transition: 0.5s;
}

input {
&::placeholder {
color: $input-text;
}
}
}
}
}
}

&:has(.home) {
.windows {
.devName.bold {
width: 40px;
overflow: hidden;

img {
display: none;
}
}
}

.desktop .widget {
&:hover {
.actIcon {
opacity: 1;
}
}

.actIcon {
opacity: 0;
}
}
}
}

.setup-popper .userInfo {
.nickname {
display: flex;
flex-direction: column;

&::after {
content: '言语道断,非物所拘。';
font-weight: 500;
font-size: 13px;
line-height: 15px;
color: #666;
white-space: nowrap;
margin-top: 4px;
}
}

.username {
display: none;
}

.userInfoBottom {
.userInfoBottomItem:has(.nasName) {
display: none;
}
}
}

}

桌面

最大化窗口

2.2 镜像同步

众所周知,极空间备份中心的存储池之间只能进行增量备份,无法实现镜像同步。全面开放 SSH 后,我们可以编写一个脚本自行解决这个问题。

rsync 脚本
根据个人情况自行替换脚本内容
#!/bin/bash

# 定义需要同步的目录对
declare -a directories=(
"/tmp/zfsv3/nvme12/XXXX/data/相册存储:/tmp/zfsv3/sata1/XXXX/data/备份中心/相册存储"
"/tmp/zfsv3/nvme12/XXXX/data/文档同步/手机备份:/tmp/zfsv3/sata1/XXXX/data/备份中心/手机备份"
# more...
)

# 获取当前时间并格式化
log() {
echo "$(date "+[%Y-%m-%d %H:%M:%S]") $1"
}

# 记录开始时间
log "同步开始"

# 同步函数
sync_directories() {
local source_dir="$1"
local target_dir="$2"

# 检查源目录是否存在
if [ ! -d "$source_dir" ]; then
log "源目录 $source_dir 不存在。"
exit 1
fi

# 检查目标目录是否存在,如果不存在则创建
if [ ! -d "$target_dir" ]; then
log "警告:目标目录 $target_dir 不存在,正在创建..."
mkdir -p "$target_dir"
if [ $? -ne 0 ]; then
log "创建目标目录 $target_dir 失败。"
exit 1
fi
fi

log "同步 $source$target..."
# 使用 rsync 进行同步,并记录详细日志
rsync -av --delete "$source_dir/" "$target_dir/" | while read line; do
log "$line"
done

# 检查 rsync 命令是否成功
if [ $? -eq 0 ]; then
log "同步成功!已将 $source_dir 下的文件同步到 $target_dir。"
else
log "同步失败!请检查问题并重新尝试。"
exit 1
fi
}



# 遍历数组并调用同步函数
for pair in "${directories[@]}"; do
IFS=":" read -r source target <<< "$pair"
sync_directories "$source" "$target"
done

log "同步完成"

2.3 云端备份

极空间备份中心虽然自带云备功能,但不知从何时起,OneDrive 备份功能在上传文件时会修改文件的时间属性,导致图片类文件失去文件属性而无法使用。为了解决这个问题,我们可以使用 rclone 程序自行实现到 OneDrive 的备份。

sudo -v ; curl https://rclone.org/install.sh | sudo bash

最后我们编写个脚本,方便在计划任务中调用:

rclone 脚本
根据个人情况自行替换脚本内容
#!/bin/bash

# rclone 密码
export RCLONE_CONFIG_PASS="XXXXXX"

# 定义本地和远程目录数组
declare -A directories=(
["/tmp/zfsv3/sata1/XXXX/data/备份中心/相册存储"]="<远端名称>:/备份/异地云备/相册存储"
["/tmp/zfsv3/sata1/XXXX/data/备份中心/手机备份"]="<远端名称>:/备份/异地云备/手机备份"
# 添加更多的目录对
)

# 获取当前时间并格式化
current_time() {
date "+[%Y-%m-%d %H:%M:%S]"
}

# 记录开始时间
echo "$(current_time) 备份开始"

# 循环同步每个目录对
for local_dir in "${!directories[@]}"; do
remote_dir=${directories[$local_dir]}
echo "$(current_time) 同步 $local_dir$remote_dir..."

# 同步操作,并捕获错误
if rclone sync "$local_dir" "$remote_dir" --progress; then
echo "$(current_time) 完成 $local_dir 同步"
else
echo "$(current_time) 失败 $local_dir 同步"
exit 1
fi
done

# 输出备份完成消息并记录结束时间
echo "$(current_time) 所有备份已完成!"
echo "$(current_time) 备份结束"

# 取消设置环境变量
unset RCLONE_CONFIG_PASS

2.4 极影视合集时间

在极影视中按时间排序时,合集会被排到最后,因为数据库中的 release_yearrelease_date 为空。要避免这种情况,可以在数据库中填补这两个字段的值。

zvideo

极影视的数据库文件位于 /zspace/zsrp/sqlite/zvideo/zvideo.db,修改前请记得备份该文件。

SQL 脚本
-- 开始事务以确保数据更新的原子性
BEGIN;

-- 确保临时表不存在
DROP TABLE IF EXISTS temp_zvideo;

-- 步骤1:创建临时表
CREATE TEMPORARY TABLE temp_zvideo (
id INTEGER,
title VARCHAR(250),
auto_series_id VARCHAR(64),
user_name VARCHAR(50),
release_year VARCHAR(16),
release_date INTEGER,
release TEXT
);

-- 插入数据到临时表,移除LIMIT 1以处理所有符合条件的记录
INSERT INTO temp_zvideo
SELECT DISTINCT zc.id, zc.title, zc.auto_series_id, zc.user_name,
COALESCE(zc2.release_year, zc.release_year) AS release_year,
COALESCE(zc2.release_date, zc.release_date) AS release_date,
COALESCE(zc2.release, zc.release) AS release
FROM zvideo_collection zc
LEFT JOIN (
SELECT auto_series_id, user_name, release_year, release_date, release
FROM zvideo_collection zc2
WHERE extend_type != 7
AND release_date = (
SELECT MAX(release_date)
FROM zvideo_collection zc3
WHERE zc3.auto_series_id = zc2.auto_series_id
AND zc3.user_name = zc2.user_name
AND zc3.extend_type != 7
AND zc3.release_date IS NOT NULL
)
) zc2 ON zc.auto_series_id = zc2.auto_series_id AND zc.user_name = zc2.user_name
WHERE zc.extend_type = 7;

-- 步骤2:更新原表
UPDATE zvideo_collection
SET
release_year = COALESCE((
SELECT release_year
FROM temp_zvideo
WHERE temp_zvideo.id = zvideo_collection.id
), release_year),
release_date = COALESCE((
SELECT release_date
FROM temp_zvideo
WHERE temp_zvideo.id = zvideo_collection.id
), release_date),
release = COALESCE((
SELECT release
FROM temp_zvideo
WHERE temp_zvideo.id = zvideo_collection.id
), release)
WHERE id IN (SELECT id FROM temp_zvideo);

-- 步骤3:删除临时表
DROP TABLE temp_zvideo;

-- 提交事务
COMMIT;

-- 检查更新行数
SELECT changes() AS rows_updated;
执行脚本
#!/bin/bash

# 定义常量
DB_PATH="/zspace/zsrp/sqlite/zvideo/zvideo.db" # SQLite 数据库文件路径
SQL_FILE="/opt/credentials/sql/update_zvideo.sql" # SQL 脚本文件路径
MAX_RETRIES=10 # 最大重试次数
RETRY_INTERVAL=5 # 重试间隔时间(秒)

# 日志函数,记录带时间戳的消息
log() {
echo "$(date "+[%Y-%m-%d %H:%M:%S]") $1"
}

# 检查 sqlite3 命令是否可用
if ! command -v sqlite3 &> /dev/null; then
log "错误:sqlite3 未安装,请先安装 sqlite3。"
exit 1
fi

# 检查文件是否存在,提升脚本鲁棒性
if [ ! -f "$DB_PATH" ]; then
log "错误:数据库文件 $DB_PATH 不存在。"
exit 1
fi
if [ ! -f "$SQL_FILE" ]; then
log "错误:SQL 文件 $SQL_FILE 不存在。"
exit 1
fi

log "开始更新数据库..."

# 初始化重试计数器
retry_count=0

# 使用循环处理数据库锁定情况
while [ $retry_count -lt $MAX_RETRIES ]; do
# 执行 SQL 脚本,捕获输出和状态码
output=$(sqlite3 "$DB_PATH" < "$SQL_FILE" 2>&1)
status=$?

# 检查执行结果
if [ $status -eq 0 ]; then
log "数据库更新成功完成。更新行数:$output"
break # 成功后退出循环
else
# 检查是否因数据库锁定失败
if echo "$output" | grep -q "database is locked"; then
retry_count=$((retry_count + 1))
log "数据库被锁定,等待 $RETRY_INTERVAL 秒后重试... (尝试 $retry_count/$MAX_RETRIES)"
sleep $RETRY_INTERVAL
else
log "数据库更新失败,错误信息如下:"
log "$output" # 直接打印错误信息
exit 1 # 非锁定错误,直接退出
fi
fi
done

# 检查是否达到最大重试次数
if [ $retry_count -eq $MAX_RETRIES ]; then
log "错误:达到最大重试次数 $MAX_RETRIES,数据库仍被锁定,更新失败。"
exit 1
fi

log "数据库更新过程结束。"

三、历史内容

历史内容:以下为极空间未主动开放 SSH 权限时的操作方法。

SSH 获取

可以参考下面视频完成操作,视频中前半段着墨于 Ubuntu 镜像的制作[1],在制作完后就是关闭极空间,插 U 盘开机启动[2]。在修改文件方面,UP 主采用了修改 /etc/shadow, /etc/passwd 文件的方法,手动添加了一个已知密码的新用户。除此之外,还可以采用对 root 用户添加公钥的方式 /root/.ssh/authorized_keys,两种方法都可行,具体取决于个人喜好。

完成修改并重启后,不出意外,您就可以在终端下登录系统了。

SSH 维护

一般情形下,极空间系统更新时会重置关键目录,无论是后加的新用户还是公钥文件均会被清空,导致失去 SSH 访问权,这里提供一个相对讨巧的方案。

首先,将极空间应用目录软链接到你的存储区:

ln -s /zspace/applications/services /tmp/zfsv3/nvme12/XXXXXXXXXXX/data/应用程序/System-link/
  • /zspace/applications/services:该目录为极空间应用所在目录;
  • /tmp/zfsv3/nvme12/…:该目录为个人硬盘的实际挂载目录,可利用df命令查找挂载地址;

软链的目录在极空间 APP 查看会提示没有权限,但可以利用 SMB 查看到这些文件。接着我们只需要随便找一个能被极空间调用的 Shell 脚本,在脚本中追加一些私货,就能搭个顺风车利用极空间实现我们的目标啦,这里推荐修改 SMB 的启动脚本:

/zspace/applications/services/samba/start.sh

在该文件中追加导入公钥的命令:

mkdir /root/.ssh
touch /root/.ssh/authorized_keys
echo '你的公钥' > /root/.ssh/authorized_keys
chmod 700 /root/.ssh
chmod 600 /root/.ssh/authorized_keys

最后在极空间 设置 - 文件及共享服务 开关一次 Samba 服务就搞定啦~


  1. 个人更推荐给 U 盘刷 Ventoy,把 Ubuntu 镜像放到 U 盘根目录。 ↩︎

  2. 我这里默认就是 U 盘优先启动,如果没进 PE 按照视频提示进 BIOS 修改。 ↩︎

评论