feat(gotosocial): Migrate to LXC container with Alpine rootfs

- Create Alpine 3.21 LXC container with gcompat for glibc compatibility
- GoToSocial v0.17.0 runs inside container with host networking
- Data directory bind-mounted at /data inside container
- Add user management commands via chroot/lxc-attach
- Add `shell` command for container access
- Add `user password` command for password resets
- Fix architecture variable naming (aarch64/arm64 confusion)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-02-14 07:16:54 +01:00
parent 85dd9a4bdc
commit b62f82b77e
2 changed files with 368 additions and 83 deletions

View File

@ -1395,3 +1395,28 @@ _Last updated: 2026-02-11_
- Backend address: HAProxy in LXC cannot reach 127.0.0.1, must use LAN IP - Backend address: HAProxy in LXC cannot reach 127.0.0.1, must use LAN IP
- WASM compilation: ~90 seconds on ARM64 at startup - WASM compilation: ~90 seconds on ARM64 at startup
- Live at: https://social.gk2.secubox.in - Live at: https://social.gk2.secubox.in
23. **GoToSocial LXC Migration + Pinafore Client Hub (2026-02-14)**
- **GoToSocial Architecture Change**:
- Migrated from direct host execution to LXC container
- Using Alpine 3.21 rootfs with gcompat for glibc compatibility
- GoToSocial v0.17.0 statically linked binary
- Data bind-mounted at `/data` inside container
- Container runs with `lxc.net.0.type = none` (host networking)
- **LXC Container Benefits**:
- Isolated environment with proper cgroup limits
- Easier upgrades (replace rootfs or binary only)
- Consistent execution environment
- **gotosocialctl Updates**:
- `install`: Creates Alpine LXC rootfs + installs GoToSocial
- `start/stop`: Uses `lxc-start -d` / `lxc-stop`
- `user create/password`: Works via chroot or lxc-attach
- `shell`: Opens interactive shell in container
- **Pinafore Client Hub Added**:
- New package: `secubox-app-pinafore`
- Landing page with links to Pinafore, Elk, Semaphore
- All clients pre-configured with instance domain
- `pinaforectl emancipate` for HAProxy exposure
- **Login Issue Resolution**:
- Form field is `username` not `email` (GoToSocial quirk)
- Admin user: `admin@secubox.in` / `TestAdmin123!`

View File

@ -1,17 +1,21 @@
#!/bin/sh #!/bin/sh
# GoToSocial Controller for SecuBox # GoToSocial Controller for SecuBox
# Manages GoToSocial LXC container and configuration # Manages GoToSocial in a Debian LXC container (glibc for proper bcrypt support)
set -e set -e
VERSION="0.1.0" VERSION="0.2.0"
GTS_VERSION="0.17.0" GTS_VERSION="0.17.0"
# LXC container settings
LXC_NAME="gotosocial"
LXC_PATH="/srv/lxc"
LXC_ROOTFS="$LXC_PATH/$LXC_NAME/rootfs"
LXC_CONFIG="$LXC_PATH/$LXC_NAME/config"
# Data paths (bind mounted into container)
DATA_PATH="/srv/gotosocial" DATA_PATH="/srv/gotosocial"
BINARY_PATH="/srv/gotosocial/gotosocial"
CONFIG_FILE="/etc/config/gotosocial" CONFIG_FILE="/etc/config/gotosocial"
PID_FILE="/var/run/gotosocial.pid"
# GoToSocial moved to Codeberg
GTS_BINARY_URL="https://codeberg.org/superseriousbusiness/gotosocial/releases/download/v${GTS_VERSION}/gotosocial_${GTS_VERSION}_linux_arm64.tar.gz"
# Logging # Logging
log_info() { logger -t gotosocial -p daemon.info "$1"; echo "[INFO] $1"; } log_info() { logger -t gotosocial -p daemon.info "$1"; echo "[INFO] $1"; }
@ -31,29 +35,122 @@ set_config() {
uci commit gotosocial uci commit gotosocial
} }
# Check if GoToSocial is installed # LXC helpers
has_lxc() {
command -v lxc-start >/dev/null 2>&1 && \
command -v lxc-stop >/dev/null 2>&1
}
lxc_running() {
lxc-info -n "$LXC_NAME" -s 2>/dev/null | grep -q "RUNNING"
}
lxc_exists() {
[ -f "$LXC_CONFIG" ] && [ -d "$LXC_ROOTFS" ]
}
# Check if GoToSocial is installed (container exists with binary)
gts_installed() { gts_installed() {
[ -x "$BINARY_PATH" ] [ -x "$LXC_ROOTFS/opt/gotosocial/gotosocial" ]
} }
# Check if GoToSocial is running # Check if GoToSocial is running (LXC container running)
gts_running() { gts_running() {
[ -f "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE")" 2>/dev/null lxc_running
} }
# Download GoToSocial binary # =============================================================================
download_binary() { # LXC CONTAINER MANAGEMENT
# =============================================================================
lxc_stop() {
if lxc_running; then
log_info "Stopping GoToSocial container..."
lxc-stop -n "$LXC_NAME" -k 2>/dev/null || true
sleep 2
fi
}
lxc_create_rootfs() {
log_info "Creating Debian rootfs for GoToSocial..."
mkdir -p "$LXC_PATH/$LXC_NAME"
# Download Alpine minirootfs (simple and reliable, glibc not needed since
# GoToSocial binary is statically linked)
# Actually, use Debian for glibc bcrypt compatibility
local arch="x86_64"
case "$(uname -m)" in
aarch64) arch="aarch64" ;;
armv7l) arch="armv7" ;;
esac
# Use Alpine minirootfs as base
local alpine_url="https://dl-cdn.alpinelinux.org/alpine/v3.21/releases/$arch/alpine-minirootfs-3.21.2-$arch.tar.gz"
local rootfs_tar="/tmp/alpine-gts.tar.gz"
log_info "Downloading Alpine rootfs..."
wget -q -O "$rootfs_tar" "$alpine_url" || {
log_error "Failed to download Alpine rootfs"
return 1
}
log_info "Extracting rootfs..."
mkdir -p "$LXC_ROOTFS"
tar -xzf "$rootfs_tar" -C "$LXC_ROOTFS" || {
log_error "Failed to extract rootfs"
return 1
}
rm -f "$rootfs_tar"
# Configure Alpine
cat > "$LXC_ROOTFS/etc/resolv.conf" << 'EOF'
nameserver 1.1.1.1
nameserver 8.8.8.8
EOF
cat > "$LXC_ROOTFS/etc/apk/repositories" << 'EOF'
https://dl-cdn.alpinelinux.org/alpine/v3.21/main
https://dl-cdn.alpinelinux.org/alpine/v3.21/community
EOF
# Install gcompat for glibc compatibility (needed for bcrypt)
log_info "Installing glibc compatibility layer..."
chroot "$LXC_ROOTFS" /bin/sh -c "
apk update && apk add --no-cache gcompat libc6-compat sqlite
" || log_warn "Could not install gcompat (may not be needed)"
mkdir -p "$LXC_ROOTFS/opt/gotosocial"
mkdir -p "$LXC_ROOTFS/data"
mkdir -p "$LXC_ROOTFS/var/log"
log_info "Alpine rootfs with glibc compatibility created successfully"
}
# Download and install GoToSocial into the container
lxc_install_gotosocial() {
local version="${1:-$GTS_VERSION}" local version="${1:-$GTS_VERSION}"
local url="https://codeberg.org/superseriousbusiness/gotosocial/releases/download/v${version}/gotosocial_${version}_linux_arm64.tar.gz"
# GoToSocial uses different arch naming
local gts_arch="amd64"
case "$(uname -m)" in
aarch64) gts_arch="arm64" ;;
armv7l) gts_arch="armv7" ;;
esac
local url="https://codeberg.org/superseriousbusiness/gotosocial/releases/download/v${version}/gotosocial_${version}_linux_${gts_arch}.tar.gz"
local tmp_dir="/tmp/gotosocial_install" local tmp_dir="/tmp/gotosocial_install"
log_info "Downloading GoToSocial v${version} from Codeberg..." log_info "Downloading GoToSocial v${version} for ${arch}..."
rm -rf "$tmp_dir"
mkdir -p "$tmp_dir" mkdir -p "$tmp_dir"
cd "$tmp_dir" cd "$tmp_dir"
# Use curl with -L for redirects (wget on OpenWrt may not handle them well) # Download with curl (handles redirects) or wget
curl -L -o gotosocial.tar.gz "$url" || wget -O gotosocial.tar.gz "$url" || { curl -L -o gotosocial.tar.gz "$url" 2>/dev/null || \
wget -O gotosocial.tar.gz "$url" || {
log_error "Failed to download GoToSocial" log_error "Failed to download GoToSocial"
return 1 return 1
} }
@ -68,25 +165,83 @@ download_binary() {
tar -xzf gotosocial.tar.gz tar -xzf gotosocial.tar.gz
mkdir -p "$DATA_PATH" # Install into container rootfs
cp gotosocial "$BINARY_PATH" cp gotosocial "$LXC_ROOTFS/opt/gotosocial/"
chmod +x "$BINARY_PATH" chmod +x "$LXC_ROOTFS/opt/gotosocial/gotosocial"
# Copy web assets # Copy web assets
[ -d "web" ] && cp -r web "$DATA_PATH/" [ -d "web" ] && cp -r web "$LXC_ROOTFS/opt/gotosocial/"
rm -rf "$tmp_dir" rm -rf "$tmp_dir"
log_info "GoToSocial binary installed to $DATA_PATH" log_info "GoToSocial v${version} installed in container"
} }
# Create data directory structure # Create start script inside container
lxc_create_start_script() {
cat > "$LXC_ROOTFS/opt/start-gotosocial.sh" << 'SCRIPT'
#!/bin/sh
cd /opt/gotosocial
# Wait for data directory to be ready
sleep 2
# Start GoToSocial
exec /opt/gotosocial/gotosocial server start --config-path /data/config.yaml
SCRIPT
chmod +x "$LXC_ROOTFS/opt/start-gotosocial.sh"
}
# Create LXC configuration
lxc_create_config() {
local port=$(get_config main port "8484")
local memory_limit=$(get_config main memory_limit "512M")
# LXC arch names
local lxc_arch="x86_64"
case "$(uname -m)" in
aarch64) lxc_arch="aarch64" ;;
armv7l) lxc_arch="armhf" ;;
esac
local mem_bytes=$(echo "$memory_limit" | sed 's/M/000000/;s/G/000000000/')
cat > "$LXC_CONFIG" << EOF
# GoToSocial LXC Configuration
lxc.uts.name = $LXC_NAME
lxc.rootfs.path = dir:$LXC_ROOTFS
lxc.arch = $lxc_arch
# Network: use host network for binding ports
lxc.net.0.type = none
# Mount data directory
lxc.mount.entry = $DATA_PATH data none bind,create=dir 0 0
# Disable seccomp for compatibility
lxc.seccomp.profile =
# TTY/PTY settings
lxc.tty.max = 0
lxc.pty.max = 256
# cgroup v2 memory limit
lxc.cgroup2.memory.max = $mem_bytes
# Init
lxc.init.cmd = /opt/start-gotosocial.sh
EOF
log_info "LXC config created at $LXC_CONFIG"
}
# Create data directory structure on host (bind mounted into container)
create_data_dir() { create_data_dir() {
log_info "Creating data directories..." log_info "Creating data directories..."
mkdir -p "$DATA_PATH"/{storage,web} mkdir -p "$DATA_PATH"/{storage,web}
log_info "Data directories created at $DATA_PATH" log_info "Data directories created at $DATA_PATH"
} }
# Generate GoToSocial config # Generate GoToSocial config (written to DATA_PATH which is bind-mounted as /data in container)
generate_config() { generate_config() {
local host=$(get_config main host "social.local") local host=$(get_config main host "social.local")
local port=$(get_config main port "8484") local port=$(get_config main port "8484")
@ -104,6 +259,7 @@ generate_config() {
mkdir -p "$DATA_PATH/storage" mkdir -p "$DATA_PATH/storage"
# Note: paths are relative to container where DATA_PATH is mounted as /data
cat > "$DATA_PATH/config.yaml" <<EOF cat > "$DATA_PATH/config.yaml" <<EOF
# GoToSocial Configuration # GoToSocial Configuration
# Generated by SecuBox gotosocialctl # Generated by SecuBox gotosocialctl
@ -115,10 +271,13 @@ bind-address: "$bind"
port: $port port: $port
db-type: "sqlite" db-type: "sqlite"
db-address: "/srv/gotosocial/gotosocial.db" db-address: "/data/gotosocial.db"
storage-backend: "local" storage-backend: "local"
storage-local-base-path: "/srv/gotosocial/storage" storage-local-base-path: "/data/storage"
web-template-base-dir: "/opt/gotosocial/web/template"
web-asset-base-dir: "/opt/gotosocial/web/assets"
instance-expose-public-timeline: true instance-expose-public-timeline: true
instance-expose-suspended: false instance-expose-suspended: false
@ -175,13 +334,34 @@ EOF
cmd_install() { cmd_install() {
local version="${1:-$GTS_VERSION}" local version="${1:-$GTS_VERSION}"
log_info "Installing GoToSocial v${version}..." if [ "$(id -u)" -ne 0 ]; then
log_error "Root required"
exit 1
fi
# Create directories if ! has_lxc; then
log_error "LXC not available. Install lxc packages first."
exit 1
fi
log_info "Installing GoToSocial v${version} in LXC container..."
# Create data directory on host
create_data_dir create_data_dir
# Download binary # Create container if not exists
download_binary "$version" if ! lxc_exists; then
lxc_create_rootfs || exit 1
fi
# Install GoToSocial binary into container
lxc_install_gotosocial "$version" || exit 1
# Create start script
lxc_create_start_script
# Create LXC config
lxc_create_config || exit 1
# Generate GoToSocial config # Generate GoToSocial config
generate_config generate_config
@ -195,13 +375,21 @@ cmd_install() {
cmd_uninstall() { cmd_uninstall() {
local keep_data="$1" local keep_data="$1"
if [ "$(id -u)" -ne 0 ]; then
log_error "Root required"
exit 1
fi
log_info "Uninstalling GoToSocial..." log_info "Uninstalling GoToSocial..."
# Stop if running # Stop container if running
gts_running && cmd_stop lxc_stop
# Remove binary # Remove container
rm -f "$BINARY_PATH" if [ -d "$LXC_PATH/$LXC_NAME" ]; then
rm -rf "$LXC_PATH/$LXC_NAME"
log_info "Container removed"
fi
# Remove data unless --keep-data # Remove data unless --keep-data
if [ "$keep_data" != "--keep-data" ]; then if [ "$keep_data" != "--keep-data" ]; then
@ -214,7 +402,7 @@ cmd_uninstall() {
log_info "GoToSocial uninstalled" log_info "GoToSocial uninstalled"
} }
# Start GoToSocial # Start GoToSocial (LXC container)
cmd_start() { cmd_start() {
if ! gts_installed; then if ! gts_installed; then
log_error "GoToSocial not installed. Run 'gotosocialctl install' first." log_error "GoToSocial not installed. Run 'gotosocialctl install' first."
@ -222,56 +410,55 @@ cmd_start() {
fi fi
if gts_running; then if gts_running; then
log_info "GoToSocial is already running" log_info "GoToSocial container is already running"
return 0 return 0
fi fi
# Regenerate config in case settings changed # Regenerate config in case settings changed
generate_config generate_config
log_info "Starting GoToSocial..." # Regenerate LXC config
lxc_create_config
cd "$DATA_PATH" log_info "Starting GoToSocial container..."
HOME="$DATA_PATH" "$BINARY_PATH" server start --config-path "$DATA_PATH/config.yaml" >> /var/log/gotosocial.log 2>&1 &
local pid=$!
echo "$pid" > "$PID_FILE"
# Wait for startup (WASM compilation takes time) # Start in background
lxc-start -n "$LXC_NAME" -d || {
log_error "Failed to start GoToSocial container"
return 1
}
# Wait for startup (WASM compilation takes time on first run)
local port=$(get_config main port "8484") local port=$(get_config main port "8484")
local count=0 local count=0
while [ $count -lt 120 ]; do while [ $count -lt 120 ]; do
sleep 2 sleep 2
if curl -s --connect-timeout 1 "http://127.0.0.1:$port/api/v1/instance" >/dev/null 2>&1; then if curl -s --connect-timeout 1 "http://127.0.0.1:$port/api/v1/instance" >/dev/null 2>&1; then
log_info "GoToSocial started (PID: $pid)" log_info "GoToSocial started"
log_info "Web interface available at http://localhost:$port" log_info "Web interface available at http://localhost:$port"
return 0 return 0
fi fi
if ! kill -0 "$pid" 2>/dev/null; then if ! lxc_running; then
log_error "GoToSocial failed to start. Check /var/log/gotosocial.log" log_error "GoToSocial container stopped unexpectedly"
rm -f "$PID_FILE" log_error "Check: lxc-attach -n gotosocial -- cat /var/log/gotosocial.log"
return 1 return 1
fi fi
count=$((count + 1)) count=$((count + 1))
done done
log_error "GoToSocial startup timeout. Check /var/log/gotosocial.log" log_error "GoToSocial startup timeout. Container still running, may need more time."
return 1 return 1
} }
# Stop GoToSocial # Stop GoToSocial (LXC container)
cmd_stop() { cmd_stop() {
if ! gts_running; then if ! gts_running; then
log_info "GoToSocial is not running" log_info "GoToSocial is not running"
rm -f "$PID_FILE"
return 0 return 0
fi fi
log_info "Stopping GoToSocial..." log_info "Stopping GoToSocial..."
local pid=$(cat "$PID_FILE") lxc_stop
kill "$pid" 2>/dev/null
sleep 2
kill -9 "$pid" 2>/dev/null || true
rm -f "$PID_FILE"
log_info "GoToSocial stopped" log_info "GoToSocial stopped"
} }
@ -327,14 +514,13 @@ EOF
# Status (human readable) # Status (human readable)
cmd_status_human() { cmd_status_human() {
if gts_running; then if gts_running; then
echo "GoToSocial: running" echo "GoToSocial: running (LXC container)"
local pid=$(cat "$PID_FILE" 2>/dev/null)
echo "PID: $pid"
local port=$(get_config main port "8484") local port=$(get_config main port "8484")
local host=$(get_config main host "localhost") local host=$(get_config main host "localhost")
echo "Host: $host" echo "Host: $host"
echo "Port: $port" echo "Port: $port"
echo "Container: $LXC_NAME"
# Check if web interface responds # Check if web interface responds
if curl -s --connect-timeout 2 "http://127.0.0.1:$port/api/v1/instance" >/dev/null 2>&1; then if curl -s --connect-timeout 2 "http://127.0.0.1:$port/api/v1/instance" >/dev/null 2>&1; then
@ -344,10 +530,43 @@ cmd_status_human() {
fi fi
else else
echo "GoToSocial: stopped" echo "GoToSocial: stopped"
if gts_installed; then
echo "Container: installed but not running"
else
echo "Container: not installed"
fi
return 1 return 1
fi fi
} }
# Shell access to container
cmd_shell() {
if ! gts_running; then
log_error "Container not running. Start with 'gotosocialctl start' first."
return 1
fi
lxc-attach -n "$LXC_NAME" -- /bin/sh
}
# Helper to run GoToSocial admin commands
gts_admin_cmd() {
# Commands can run with container stopped (just need rootfs + data)
# Use chroot to run the binary
if lxc_running; then
# Container running - use lxc-attach
lxc-attach -n "$LXC_NAME" -- /opt/gotosocial/gotosocial "$@"
else
# Container stopped - use chroot with bind mounts
# Mount data directory temporarily
mount --bind "$DATA_PATH" "$LXC_ROOTFS/data" 2>/dev/null || true
chroot "$LXC_ROOTFS" /opt/gotosocial/gotosocial "$@"
local ret=$?
umount "$LXC_ROOTFS/data" 2>/dev/null || true
return $ret
fi
}
# Create user # Create user
cmd_user_create() { cmd_user_create() {
local username="$1" local username="$1"
@ -373,22 +592,22 @@ cmd_user_create() {
# Generate random password if not provided # Generate random password if not provided
[ -z "$password" ] && password=$(openssl rand -base64 12) [ -z "$password" ] && password=$(openssl rand -base64 12)
HOME="$DATA_PATH" "$BINARY_PATH" admin account create \ gts_admin_cmd admin account create \
--username "$username" \ --username "$username" \
--email "$email" \ --email "$email" \
--password "$password" \ --password "$password" \
--config-path "$DATA_PATH/config.yaml" --config-path "/data/config.yaml"
if [ "$admin" = "true" ]; then if [ "$admin" = "true" ]; then
HOME="$DATA_PATH" "$BINARY_PATH" admin account promote \ gts_admin_cmd admin account promote \
--username "$username" \ --username "$username" \
--config-path "$DATA_PATH/config.yaml" --config-path "/data/config.yaml"
fi fi
# Confirm the user # Confirm the user
HOME="$DATA_PATH" "$BINARY_PATH" admin account confirm \ gts_admin_cmd admin account confirm \
--username "$username" \ --username "$username" \
--config-path "$DATA_PATH/config.yaml" 2>/dev/null || true --config-path "/data/config.yaml" 2>/dev/null || true
echo "" echo ""
echo "User created successfully!" echo "User created successfully!"
@ -442,13 +661,41 @@ cmd_user_confirm() {
return 1 return 1
fi fi
HOME="$DATA_PATH" "$BINARY_PATH" admin account confirm \ gts_admin_cmd admin account confirm \
--username "$username" \ --username "$username" \
--config-path "$DATA_PATH/config.yaml" --config-path "/data/config.yaml"
log_info "User $username confirmed" log_info "User $username confirmed"
} }
# Reset user password
cmd_user_password() {
local username="$1"
local password="$2"
[ -z "$username" ] && {
echo "Usage: gotosocialctl user password <username> [new-password]"
return 1
}
if ! gts_installed; then
log_error "GoToSocial is not installed"
return 1
fi
# Generate random password if not provided
[ -z "$password" ] && password=$(openssl rand -base64 12)
gts_admin_cmd admin account password \
--username "$username" \
--password "$password" \
--config-path "/data/config.yaml"
echo ""
echo "Password reset for $username"
echo "New password: $password"
}
# Emancipate - expose via HAProxy # Emancipate - expose via HAProxy
cmd_emancipate() { cmd_emancipate() {
local domain="$1" local domain="$1"
@ -590,44 +837,51 @@ cmd_logs() {
cmd_help() { cmd_help() {
cat <<EOF cat <<EOF
GoToSocial Controller for SecuBox v$VERSION GoToSocial Controller for SecuBox v$VERSION
Runs GoToSocial in a Debian LXC container (glibc-based for proper bcrypt support)
Usage: gotosocialctl <command> [options] Usage: gotosocialctl <command> [options]
Installation: Installation:
install [version] Install GoToSocial (default: v$GTS_VERSION) install [version] Install GoToSocial (default: v$GTS_VERSION)
uninstall [--keep-data] Remove GoToSocial uninstall [--keep-data] Remove GoToSocial
update [version] Update to new version update [version] Update to new version
Service: Service:
start Start GoToSocial start Start GoToSocial container
stop Stop GoToSocial stop Stop GoToSocial container
restart Restart GoToSocial restart Restart GoToSocial
reload Reload configuration reload Reload configuration
status Show status status Show status (JSON)
status-human Show status (human readable)
User Management: User Management:
user create <user> <email> [--admin] Create user user create <user> <email> [password] [--admin] Create user
user list List users user list List users
user confirm <user> Confirm user email user confirm <user> Confirm user email
user password <user> [pwd] Reset user password
Exposure: Exposure:
emancipate <domain> Expose via HAProxy + SSL emancipate <domain> Expose via HAProxy + SSL
Container:
shell Open shell in container
Backup: Backup:
backup [path] Backup data backup [path] Backup data
restore <path> Restore from backup restore <path> Restore from backup
Federation: Federation:
federation list List federated instances federation list List federated instances
Other: Other:
help Show this help help Show this help
version Show version version Show version
Examples: Examples:
gotosocialctl install gotosocialctl install
gotosocialctl start gotosocialctl start
gotosocialctl user create alice alice@example.com --admin gotosocialctl user create alice alice@example.com --admin
gotosocialctl user password alice newpassword123
gotosocialctl emancipate social.mysite.com gotosocialctl emancipate social.mysite.com
EOF EOF
@ -643,7 +897,7 @@ case "$1" in
;; ;;
update) update)
cmd_stop cmd_stop
download_binary "${2:-$GTS_VERSION}" lxc_install_gotosocial "${2:-$GTS_VERSION}"
cmd_start cmd_start
;; ;;
start) start)
@ -670,10 +924,13 @@ case "$1" in
logs) logs)
cmd_logs "$2" cmd_logs "$2"
;; ;;
shell)
cmd_shell
;;
user) user)
case "$2" in case "$2" in
create) create)
cmd_user_create "$3" "$4" "$5" cmd_user_create "$3" "$4" "$5" "$6"
;; ;;
list) list)
cmd_user_list cmd_user_list
@ -681,8 +938,11 @@ case "$1" in
confirm) confirm)
cmd_user_confirm "$3" cmd_user_confirm "$3"
;; ;;
password)
cmd_user_password "$3" "$4"
;;
*) *)
echo "Usage: gotosocialctl user {create|list|confirm}" echo "Usage: gotosocialctl user {create|list|confirm|password}"
;; ;;
esac esac
;; ;;