mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
feat: add WireGuard VPS setup automation script (#2810)
* feat: add WireGuard VPS setup automation script Adds a comprehensive bash script that automates: - SSH key setup and authentication - WireGuard installation on remote VPS - Configuration download and import to NetworkManager - User-friendly CLI interface with validation - Detailed status messages and error handling - Instructions for exposing services via ACME/Let's Encrypt * use cat heredoc for issue files to fix formatting Replaces echo with cat heredoc when writing to /etc/issue and /etc/issue.net to properly preserve escape sequences and prevent unwanted newlines in login prompts. * add convent `wg-vps-setup` symlink to PATH * sync ssh privkey on init * Update default ssh key location * simplify to use existing StartOS SSH keys and fix .ssh permission * finetune * Switch to start9labs repo * rename some files * set correct ownership --------- Co-authored-by: Aiden McClelland <me@drbonez.dev>
This commit is contained in:
323
build/lib/scripts/wg-vps-setup
Executable file
323
build/lib/scripts/wg-vps-setup
Executable file
@@ -0,0 +1,323 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Colors for better output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[1;34m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# --- Constants ---
|
||||
readonly WIREGUARD_INSTALL_URL="https://raw.githubusercontent.com/start9labs/wg-vps-setup/master/wireguard-install.sh"
|
||||
readonly SSH_KEY_DIR="/home/start9/.ssh"
|
||||
readonly SSH_KEY_NAME="id_ed25519"
|
||||
readonly SSH_PRIVATE_KEY="$SSH_KEY_DIR/$SSH_KEY_NAME"
|
||||
readonly SSH_PUBLIC_KEY="$SSH_PRIVATE_KEY.pub"
|
||||
|
||||
# Store original arguments
|
||||
SCRIPT_ARGS=("$@")
|
||||
|
||||
# --- Functions ---
|
||||
|
||||
# Function to ensure script runs with root privileges by auto-elevating if needed
|
||||
check_root() {
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
exec sudo "$0" "${SCRIPT_ARGS[@]}"
|
||||
fi
|
||||
sudo chown -R start9:start9 "$SSH_KEY_DIR"
|
||||
}
|
||||
|
||||
# Function to print banner
|
||||
print_banner() {
|
||||
echo -e "${BLUE}"
|
||||
echo "================================================"
|
||||
echo -e " ${NC}StartOS WireGuard VPS Setup Tool${BLUE} "
|
||||
echo "================================================"
|
||||
echo -e "${NC}"
|
||||
}
|
||||
|
||||
# Function to print usage
|
||||
print_usage() {
|
||||
echo -e "Usage: $0 [-h] [-i IP] [-u USERNAME] [-p PORT] [-k SSH_KEY]"
|
||||
echo "Options:"
|
||||
echo " -h Show this help message"
|
||||
echo " -i VPS IP address"
|
||||
echo " -u SSH username (default: root)"
|
||||
echo " -p SSH port (default: 22)"
|
||||
echo " -k Path to the custom SSH private key (optional)"
|
||||
echo " If no key is provided, the default key '$SSH_PRIVATE_KEY' will be used."
|
||||
}
|
||||
|
||||
# Function to display end message
|
||||
display_end_message() {
|
||||
echo -e "\n${BLUE}------------------------------------------------------------------${NC}"
|
||||
echo -e "${NC}WireGuard server setup complete!"
|
||||
echo -e "${BLUE}------------------------------------------------------------------${NC}"
|
||||
echo -e "\n${YELLOW}To expose your services to the Clearnet, use the following commands on your StartOS system (replace placeholders):${NC}"
|
||||
echo -e "\n ${YELLOW}1. Initialize ACME (This only needs to be done once):${NC}"
|
||||
echo " start-cli net acme init --provider=letsencrypt --contact=mailto:your-email@example.com"
|
||||
echo -e "\n ${YELLOW}2. Expose 'hello-world' on port 80 through VPS:${NC}"
|
||||
echo " start-cli package host hello-world binding ui-multi set-public 80"
|
||||
echo -e "\n ${YELLOW}3. Add a domain to your 'hello-world' service:${NC}"
|
||||
echo " start-cli package host hello-world address ui-multi domain add your-domain.example.com --acme=letsencrypt"
|
||||
echo -e "\n ${YELLOW}Replace '${NC}your-email@example.com${YELLOW}' with your actual email address, '${NC}your-domain.example.com${YELLOW}' with your actual domain and '${NC}hello-world${YELLOW}' with your actual service id.${NC}"
|
||||
echo -e "${BLUE}------------------------------------------------------------------${NC}"
|
||||
}
|
||||
|
||||
# Function to validate IP address
|
||||
validate_ip() {
|
||||
local ip=$1
|
||||
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to handle StartOS connection (download only)
|
||||
handle_startos_connection() {
|
||||
echo -e "${BLUE}Fetching the WireGuard configuration file...${NC}"
|
||||
|
||||
# Fetch the client configuration file
|
||||
config_file=$(ssh -i "$SSH_PRIVATE_KEY" -o StrictHostKeyChecking=no -p "$SSH_PORT" "$SSH_USER@$VPS_IP" 'ls -t ~/*.conf 2>/dev/null | head -n 1')
|
||||
if [ -z "$config_file" ]; then
|
||||
echo -e "${RED}Error: No WireGuard configuration file found on the remote server.${NC}"
|
||||
return 1 # Exit with error
|
||||
fi
|
||||
CONFIG_NAME=$(basename "$config_file")
|
||||
|
||||
# Download the configuration file
|
||||
if ! scp -i "$SSH_PRIVATE_KEY" -o StrictHostKeyChecking=no -P "$SSH_PORT" "$SSH_USER@$VPS_IP":~/"$CONFIG_NAME" ./; then
|
||||
echo -e "${RED}Error: Failed to download the WireGuard configuration file.${NC}"
|
||||
return 1 # Exit with error
|
||||
fi
|
||||
echo -e "${GREEN}WireGuard configuration file '$CONFIG_NAME' downloaded successfully.${NC}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to import WireGuard configuration
|
||||
import_wireguard_config() {
|
||||
local config_name="$1"
|
||||
if [ -z "$config_name" ]; then
|
||||
echo -e "${RED}Error: Configuration file name is missing.${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local connection_name=$(basename "$config_name" .conf) #Extract base name without extension
|
||||
|
||||
# Check if the connection with same name already exists
|
||||
if nmcli connection show --active | grep -q "^${connection_name}\s"; then
|
||||
read -r -p "A connection with the name '$connection_name' already exists. Do you want to override it? (y/N): " answer
|
||||
if [[ "$answer" =~ ^[Yy]$ ]]; then
|
||||
nmcli connection delete "$connection_name"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}Error: Failed to delete existing connection '$connection_name'.${NC}"
|
||||
return 1
|
||||
fi
|
||||
# Import if user chose to override or if connection did not exist
|
||||
if ! nmcli connection import type wireguard file "$config_name"; then
|
||||
echo -e "${RED}Error: Failed to import the WireGuard configuration using NetworkManager.${NC}"
|
||||
rm -f "$config_name"
|
||||
return 1
|
||||
fi
|
||||
echo -e "${GREEN}WireGuard configuration '$config_name' has been imported to NetworkManager.${NC}"
|
||||
rm -f "$config_name"
|
||||
display_end_message
|
||||
else
|
||||
echo -e "${BLUE}Skipping import of the WireGuard configuration.${NC}"
|
||||
rm -f "$config_name"
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
# Import if connection did not exist
|
||||
if command -v nmcli &>/dev/null; then
|
||||
if ! nmcli connection import type wireguard file "$config_name"; then
|
||||
echo -e "${RED}Error: Failed to import the WireGuard configuration using NetworkManager.${NC}"
|
||||
rm -f "$config_name"
|
||||
return 1
|
||||
fi
|
||||
echo -e "${GREEN}WireGuard configuration '$config_name' has been imported to NetworkManager.${NC}"
|
||||
rm -f "$config_name"
|
||||
display_end_message
|
||||
else
|
||||
echo -e "${YELLOW}Warning: NetworkManager 'nmcli' not found. Configuration file '$config_name' saved in current directory.${NC}"
|
||||
echo -e "${YELLOW}Import the configuration to your StartOS manually by going to NetworkManager or using wg-quick up <config> command${NC}"
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to download the install script
|
||||
download_install_script() {
|
||||
echo -e "${BLUE}Downloading latest WireGuard install script...${NC}"
|
||||
# Download the script
|
||||
if ! curl -sSf "$WIREGUARD_INSTALL_URL" -o wireguard-install.sh; then
|
||||
echo -e "${RED}Failed to download WireGuard installation script.${NC}"
|
||||
return 1
|
||||
fi
|
||||
chmod +x wireguard-install.sh
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}Failed to chmod +x wireguard install script.${NC}"
|
||||
return 1
|
||||
fi
|
||||
echo -e "${GREEN}WireGuard install script downloaded successfully!${NC}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to install WireGuard
|
||||
install_wireguard() {
|
||||
echo -e "\n${BLUE}Installing WireGuard...${NC}"
|
||||
|
||||
# Check if install script exist
|
||||
if [ ! -f "wireguard-install.sh" ]; then
|
||||
echo -e "${RED}WireGuard install script is missing. Did it failed to download?${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Run the remote install script and let it complete
|
||||
if ! ssh -o ConnectTimeout=60 -i "$SSH_PRIVATE_KEY" -o StrictHostKeyChecking=no -p "$SSH_PORT" -t "$SSH_USER@$VPS_IP" "bash -c 'export TERM=xterm-256color; export STARTOS_HOSTNAME=$(hostname); bash ~/wireguard-install.sh'"; then
|
||||
echo -e "${RED}WireGuard installation failed on remote server.${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Test if wireguard installed
|
||||
if ! ssh -q -o BatchMode=yes -o ConnectTimeout=5 -i "$SSH_PRIVATE_KEY" -o StrictHostKeyChecking=no -p "$SSH_PORT" "$SSH_USER@$VPS_IP" "test -f /etc/wireguard/wg0.conf"; then
|
||||
echo -e "\n${RED}WireGuard installation failed because /etc/wireguard/wg0.conf is missing, which means the script removed it.${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e "\n${GREEN}WireGuard installation completed successfully!${NC}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# --- Main Script ---
|
||||
# Initialize variables
|
||||
VPS_IP=""
|
||||
SSH_USER="root"
|
||||
SSH_PORT="22"
|
||||
CUSTOM_SSH_KEY=""
|
||||
CONFIG_NAME=""
|
||||
|
||||
# Check if the script is run as root before anything else
|
||||
check_root
|
||||
|
||||
# Print banner
|
||||
print_banner
|
||||
|
||||
# Parse command line arguments
|
||||
while getopts "hi:u:p:k:" opt; do
|
||||
case $opt in
|
||||
h)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
i)
|
||||
VPS_IP=$OPTARG
|
||||
;;
|
||||
u)
|
||||
SSH_USER=$OPTARG
|
||||
;;
|
||||
p)
|
||||
SSH_PORT=$OPTARG
|
||||
;;
|
||||
k)
|
||||
CUSTOM_SSH_KEY=$OPTARG
|
||||
;;
|
||||
\?)
|
||||
echo "Invalid option: -$OPTARG" >&2
|
||||
print_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Check if custom SSH key is passed and update the private key variable
|
||||
if [ -n "$CUSTOM_SSH_KEY" ]; then
|
||||
if [ ! -f "$CUSTOM_SSH_KEY" ]; then
|
||||
echo -e "${RED}Custom SSH key '$CUSTOM_SSH_KEY' not found.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
SSH_PRIVATE_KEY="$CUSTOM_SSH_KEY"
|
||||
SSH_PUBLIC_KEY="$CUSTOM_SSH_KEY.pub"
|
||||
else
|
||||
# Use default StartOS SSH key
|
||||
if [ ! -f "$SSH_PRIVATE_KEY" ]; then
|
||||
echo -e "${RED}No SSH key found at default location '$SSH_PRIVATE_KEY'. Please ensure StartOS SSH keys are properly configured.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -f "$SSH_PUBLIC_KEY" ]; then
|
||||
echo -e "${RED}Public key '$SSH_PUBLIC_KEY' not found. Please ensure both private and public keys exist.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If VPS_IP is not provided via command line, ask for it
|
||||
if [ -z "$VPS_IP" ]; then
|
||||
while true; do
|
||||
echo -n "Please enter your VPS IP address: "
|
||||
read VPS_IP
|
||||
if validate_ip "$VPS_IP"; then
|
||||
break
|
||||
else
|
||||
echo -e "${RED}Invalid IP address format. Please try again.${NC}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Confirm SSH connection details
|
||||
echo -e "\n${GREEN}Connection details:${NC}"
|
||||
echo "VPS IP: $VPS_IP"
|
||||
echo "SSH User: $SSH_USER"
|
||||
echo "SSH Port: $SSH_PORT"
|
||||
|
||||
echo -e "\n${GREEN}Proceeding with SSH key-based authentication...${NC}\n"
|
||||
|
||||
# Copy SSH public key to the remote server
|
||||
if ! ssh-copy-id -i "$SSH_PUBLIC_KEY" -o StrictHostKeyChecking=no -p "$SSH_PORT" "$SSH_USER@$VPS_IP" >/dev/null 2>&1; then
|
||||
echo -e "${RED}Failed to copy SSH key to the remote server. Please ensure you have correct credentials.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}SSH key-based authentication configured successfully!${NC}"
|
||||
|
||||
# Test SSH connection using key-based authentication
|
||||
echo -e "\nTesting SSH connection with key-based authentication..."
|
||||
if ! ssh -q -o BatchMode=yes -o ConnectTimeout=5 -i "$SSH_PRIVATE_KEY" -o StrictHostKeyChecking=no -p "$SSH_PORT" "$SSH_USER@$VPS_IP" exit; then
|
||||
echo -e "${RED}SSH connection with key-based authentication failed. Please check your configuration.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}SSH connection successful with key-based authentication!${NC}"
|
||||
|
||||
# Download the WireGuard install script locally
|
||||
if ! download_install_script; then
|
||||
echo -e "${RED}Failed to download the latest install script. Exiting...${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Upload the install script to the remote server
|
||||
if ! scp -i "$SSH_PRIVATE_KEY" -o StrictHostKeyChecking=no -P "$SSH_PORT" wireguard-install.sh "$SSH_USER@$VPS_IP":~/; then
|
||||
echo -e "${RED}Failed to upload WireGuard install script to the remote server.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install WireGuard on remote server using the downloaded script
|
||||
if ! install_wireguard; then
|
||||
echo -e "${RED}WireGuard installation failed.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Remove the local install script
|
||||
rm wireguard-install.sh >/dev/null 2>&1
|
||||
|
||||
# Handle the StartOS config (download)
|
||||
if ! handle_startos_connection; then
|
||||
echo -e "${RED}StartOS configuration download failed!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Import the configuration
|
||||
if ! import_wireguard_config "$CONFIG_NAME"; then
|
||||
echo -e "${RED}StartOS configuration import failed or skipped!${NC}"
|
||||
fi
|
||||
@@ -25,6 +25,7 @@ use crate::context::{CliContext, InitContext};
|
||||
use crate::db::model::public::ServerStatus;
|
||||
use crate::db::model::Database;
|
||||
use crate::disk::mount::util::unmount;
|
||||
use crate::hostname::Hostname;
|
||||
use crate::middleware::auth::LOCAL_AUTH_COOKIE_PATH;
|
||||
use crate::net::net_controller::{NetController, NetService};
|
||||
use crate::net::utils::find_wifi_iface;
|
||||
@@ -35,7 +36,7 @@ use crate::progress::{
|
||||
};
|
||||
use crate::rpc_continuations::{Guid, RpcContinuation};
|
||||
use crate::s9pk::v2::pack::{CONTAINER_DATADIR, CONTAINER_TOOL};
|
||||
use crate::ssh::SSH_AUTHORIZED_KEYS_FILE;
|
||||
use crate::ssh::SSH_DIR;
|
||||
use crate::system::get_mem_info;
|
||||
use crate::util::io::{create_file, IOHook};
|
||||
use crate::util::lshw::lshw;
|
||||
@@ -340,8 +341,10 @@ pub async fn init(
|
||||
|
||||
load_ssh_keys.start();
|
||||
crate::ssh::sync_keys(
|
||||
&Hostname(peek.as_public().as_server_info().as_hostname().de()?),
|
||||
&peek.as_private().as_ssh_privkey().de()?,
|
||||
&peek.as_private().as_ssh_pubkeys().de()?,
|
||||
SSH_AUTHORIZED_KEYS_FILE,
|
||||
SSH_DIR,
|
||||
)
|
||||
.await?;
|
||||
load_ssh_keys.complete();
|
||||
|
||||
@@ -3,20 +3,23 @@ use std::path::Path;
|
||||
|
||||
use clap::builder::ValueParserFactory;
|
||||
use clap::Parser;
|
||||
use color_eyre::eyre::eyre;
|
||||
use imbl_value::InternedString;
|
||||
use models::FromStrParser;
|
||||
use rpc_toolkit::{from_fn_async, Context, Empty, HandlerExt, ParentHandler};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::fs::OpenOptions;
|
||||
use tokio::process::Command;
|
||||
use tracing::instrument;
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::context::{CliContext, RpcContext};
|
||||
use crate::hostname::Hostname;
|
||||
use crate::prelude::*;
|
||||
use crate::util::io::create_file;
|
||||
use crate::util::serde::{display_serializable, HandlerExtSerde, WithIoFormat};
|
||||
use crate::util::serde::{display_serializable, HandlerExtSerde, Pem, WithIoFormat};
|
||||
use crate::util::Invoke;
|
||||
|
||||
pub const SSH_AUTHORIZED_KEYS_FILE: &str = "/home/start9/.ssh/authorized_keys";
|
||||
pub const SSH_DIR: &str = "/home/start9/.ssh";
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct SshKeys(BTreeMap<InternedString, WithTimeData<SshPubKey>>);
|
||||
@@ -143,7 +146,7 @@ pub async fn add(ctx: RpcContext, AddParams { key }: AddParams) -> Result<SshKey
|
||||
))
|
||||
})
|
||||
.await?;
|
||||
sync_keys(&keys, SSH_AUTHORIZED_KEYS_FILE).await?;
|
||||
sync_pubkeys(&keys, SSH_DIR).await?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
@@ -175,7 +178,7 @@ pub async fn delete(
|
||||
}
|
||||
})
|
||||
.await?;
|
||||
sync_keys(&keys, SSH_AUTHORIZED_KEYS_FILE).await
|
||||
sync_pubkeys(&keys, SSH_DIR).await
|
||||
}
|
||||
|
||||
fn display_all_ssh_keys(params: WithIoFormat<Empty>, result: Vec<SshKeyResponse>) {
|
||||
@@ -226,23 +229,90 @@ pub async fn list(ctx: RpcContext) -> Result<Vec<SshKeyResponse>, Error> {
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn sync_keys<P: AsRef<Path>>(keys: &SshKeys, dest: P) -> Result<(), Error> {
|
||||
pub async fn sync_keys<P: AsRef<Path>>(
|
||||
hostname: &Hostname,
|
||||
privkey: &Pem<ssh_key::PrivateKey>,
|
||||
pubkeys: &SshKeys,
|
||||
ssh_dir: P,
|
||||
) -> Result<(), Error> {
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
let dest = dest.as_ref();
|
||||
let ssh_dir = dest.parent().ok_or_else(|| {
|
||||
Error::new(
|
||||
eyre!("SSH Key File cannot be \"/\""),
|
||||
crate::ErrorKind::Filesystem,
|
||||
)
|
||||
})?;
|
||||
let ssh_dir = ssh_dir.as_ref();
|
||||
if tokio::fs::metadata(ssh_dir).await.is_err() {
|
||||
tokio::fs::create_dir_all(ssh_dir).await?;
|
||||
}
|
||||
let mut f = create_file(dest).await?;
|
||||
for key in keys.0.values() {
|
||||
|
||||
let id_alg = if privkey.0.algorithm().is_ed25519() {
|
||||
"id_ed25519"
|
||||
} else if privkey.0.algorithm().is_ecdsa() {
|
||||
"id_ecdsa"
|
||||
} else if privkey.0.algorithm().is_rsa() {
|
||||
"id_rsa"
|
||||
} else {
|
||||
"id_unknown"
|
||||
};
|
||||
|
||||
let privkey_path = ssh_dir.join(id_alg);
|
||||
let mut f = OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.mode(0o600)
|
||||
.open(&privkey_path)
|
||||
.await
|
||||
.with_ctx(|_| {
|
||||
(
|
||||
ErrorKind::Filesystem,
|
||||
lazy_format!("create {privkey_path:?}"),
|
||||
)
|
||||
})?;
|
||||
f.write_all(privkey.to_string().as_bytes()).await?;
|
||||
f.write_all(b"\n").await?;
|
||||
f.sync_all().await?;
|
||||
let mut f = create_file(ssh_dir.join(id_alg).with_extension("pub")).await?;
|
||||
f.write_all(
|
||||
(privkey
|
||||
.0
|
||||
.public_key()
|
||||
.to_openssh()
|
||||
.with_kind(ErrorKind::OpenSsh)?
|
||||
+ " start9@"
|
||||
+ &*hostname.0)
|
||||
.as_bytes(),
|
||||
)
|
||||
.await?;
|
||||
f.write_all(b"\n").await?;
|
||||
f.sync_all().await?;
|
||||
|
||||
let mut f = create_file(ssh_dir.join("authorized_keys")).await?;
|
||||
for key in pubkeys.0.values() {
|
||||
f.write_all(key.0.to_key_format().as_bytes()).await?;
|
||||
f.write_all(b"\n").await?;
|
||||
}
|
||||
|
||||
Command::new("chown")
|
||||
.arg("-R")
|
||||
.arg("start9:startos")
|
||||
.arg(ssh_dir)
|
||||
.invoke(ErrorKind::Filesystem)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn sync_pubkeys<P: AsRef<Path>>(pubkeys: &SshKeys, ssh_dir: P) -> Result<(), Error> {
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
let ssh_dir = ssh_dir.as_ref();
|
||||
if tokio::fs::metadata(ssh_dir).await.is_err() {
|
||||
tokio::fs::create_dir_all(ssh_dir).await?;
|
||||
}
|
||||
|
||||
let mut f = create_file(ssh_dir.join("authorized_keys")).await?;
|
||||
for key in pubkeys.0.values() {
|
||||
f.write_all(key.0.to_key_format().as_bytes()).await?;
|
||||
f.write_all(b"\n").await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
14
debian/postinst
vendored
14
debian/postinst
vendored
@@ -26,8 +26,12 @@ if [ -f /etc/default/grub ]; then
|
||||
fi
|
||||
|
||||
# set local and remote login prompt
|
||||
echo "StartOS v$(cat /usr/lib/startos/VERSION.txt) [\\m] on \\n.local (\\l)" > /etc/issue
|
||||
echo "StartOS v$(cat /usr/lib/startos/VERSION.txt)" > /etc/issue.net
|
||||
cat << EOF > /etc/issue
|
||||
StartOS v$(cat /usr/lib/startos/VERSION.txt) [\\m] on \\n.local (\\l)
|
||||
EOF
|
||||
cat << EOF > /etc/issue.net
|
||||
StartOS v$(cat /usr/lib/startos/VERSION.txt)
|
||||
EOF
|
||||
|
||||
# change timezone
|
||||
rm -f /etc/localtime
|
||||
@@ -102,8 +106,10 @@ CookieAuthentication 1
|
||||
EOF
|
||||
|
||||
rm -rf /var/lib/tor/*
|
||||
ln -sf /usr/lib/startos/scripts/tor-check.sh /usr/bin/tor-check
|
||||
ln -sf /usr/lib/startos/scripts/gather_debug_info.sh /usr/bin/gather-debug
|
||||
ln -sf /usr/lib/startos/scripts/chroot-and-upgrade /usr/bin/chroot-and-upgrade
|
||||
ln -sf /usr/lib/startos/scripts/tor-check /usr/bin/tor-check
|
||||
ln -sf /usr/lib/startos/scripts/gather-debug-info /usr/bin/gather-debug-info
|
||||
ln -sf /usr/lib/startos/scripts/wg-vps-setup /usr/bin/wg-vps-setup
|
||||
|
||||
echo "fs.inotify.max_user_watches=1048576" > /etc/sysctl.d/97-startos.conf
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ export { AcmeSettings } from "./AcmeSettings"
|
||||
export { ActionId } from "./ActionId"
|
||||
export { ActionInput } from "./ActionInput"
|
||||
export { ActionMetadata } from "./ActionMetadata"
|
||||
export { ActionRequest } from "./ActionRequest"
|
||||
export { ActionRequestCondition } from "./ActionRequestCondition"
|
||||
export { ActionRequestEntry } from "./ActionRequestEntry"
|
||||
export { ActionRequestInput } from "./ActionRequestInput"
|
||||
export { ActionRequestTrigger } from "./ActionRequestTrigger"
|
||||
export { ActionResult } from "./ActionResult"
|
||||
export { ActionRequest } from "./ActionRequest"
|
||||
export { ActionResultMember } from "./ActionResultMember"
|
||||
export { ActionResult } from "./ActionResult"
|
||||
export { ActionResultV0 } from "./ActionResultV0"
|
||||
export { ActionResultV1 } from "./ActionResultV1"
|
||||
export { ActionResultValue } from "./ActionResultValue"
|
||||
@@ -20,13 +20,13 @@ export { AddAdminParams } from "./AddAdminParams"
|
||||
export { AddAssetParams } from "./AddAssetParams"
|
||||
export { AddCategoryParams } from "./AddCategoryParams"
|
||||
export { AddPackageParams } from "./AddPackageParams"
|
||||
export { AddressInfo } from "./AddressInfo"
|
||||
export { AddSslOptions } from "./AddSslOptions"
|
||||
export { AddVersionParams } from "./AddVersionParams"
|
||||
export { AddressInfo } from "./AddressInfo"
|
||||
export { Alerts } from "./Alerts"
|
||||
export { Algorithm } from "./Algorithm"
|
||||
export { AllPackageData } from "./AllPackageData"
|
||||
export { AllowedStatuses } from "./AllowedStatuses"
|
||||
export { AllPackageData } from "./AllPackageData"
|
||||
export { AlpnInfo } from "./AlpnInfo"
|
||||
export { AnySignature } from "./AnySignature"
|
||||
export { AnySigningKey } from "./AnySigningKey"
|
||||
@@ -38,9 +38,9 @@ export { BackupTargetFS } from "./BackupTargetFS"
|
||||
export { Base64 } from "./Base64"
|
||||
export { BindId } from "./BindId"
|
||||
export { BindInfo } from "./BindInfo"
|
||||
export { BindingSetPublicParams } from "./BindingSetPublicParams"
|
||||
export { BindOptions } from "./BindOptions"
|
||||
export { BindParams } from "./BindParams"
|
||||
export { BindingSetPublicParams } from "./BindingSetPublicParams"
|
||||
export { Blake3Commitment } from "./Blake3Commitment"
|
||||
export { BlockDev } from "./BlockDev"
|
||||
export { BuildArg } from "./BuildArg"
|
||||
@@ -60,11 +60,11 @@ export { CreateSubcontainerFsParams } from "./CreateSubcontainerFsParams"
|
||||
export { CurrentDependencies } from "./CurrentDependencies"
|
||||
export { CurrentDependencyInfo } from "./CurrentDependencyInfo"
|
||||
export { DataUrl } from "./DataUrl"
|
||||
export { DepInfo } from "./DepInfo"
|
||||
export { Dependencies } from "./Dependencies"
|
||||
export { DependencyKind } from "./DependencyKind"
|
||||
export { DependencyMetadata } from "./DependencyMetadata"
|
||||
export { DependencyRequirement } from "./DependencyRequirement"
|
||||
export { DepInfo } from "./DepInfo"
|
||||
export { Description } from "./Description"
|
||||
export { DestroySubcontainerFsParams } from "./DestroySubcontainerFsParams"
|
||||
export { DeviceFilter } from "./DeviceFilter"
|
||||
@@ -84,8 +84,8 @@ export { GetHostInfoParams } from "./GetHostInfoParams"
|
||||
export { GetOsAssetParams } from "./GetOsAssetParams"
|
||||
export { GetOsVersionParams } from "./GetOsVersionParams"
|
||||
export { GetPackageParams } from "./GetPackageParams"
|
||||
export { GetPackageResponse } from "./GetPackageResponse"
|
||||
export { GetPackageResponseFull } from "./GetPackageResponseFull"
|
||||
export { GetPackageResponse } from "./GetPackageResponse"
|
||||
export { GetServiceInterfaceParams } from "./GetServiceInterfaceParams"
|
||||
export { GetServicePortForwardParams } from "./GetServicePortForwardParams"
|
||||
export { GetSslCertificateParams } from "./GetSslCertificateParams"
|
||||
@@ -98,21 +98,21 @@ export { Governor } from "./Governor"
|
||||
export { Guid } from "./Guid"
|
||||
export { HardwareRequirements } from "./HardwareRequirements"
|
||||
export { HealthCheckId } from "./HealthCheckId"
|
||||
export { Host } from "./Host"
|
||||
export { HostAddress } from "./HostAddress"
|
||||
export { HostId } from "./HostId"
|
||||
export { HostnameInfo } from "./HostnameInfo"
|
||||
export { Hosts } from "./Hosts"
|
||||
export { Host } from "./Host"
|
||||
export { ImageConfig } from "./ImageConfig"
|
||||
export { ImageId } from "./ImageId"
|
||||
export { ImageMetadata } from "./ImageMetadata"
|
||||
export { ImageSource } from "./ImageSource"
|
||||
export { InitProgressRes } from "./InitProgressRes"
|
||||
export { InstallParams } from "./InstallParams"
|
||||
export { InstalledState } from "./InstalledState"
|
||||
export { InstalledVersionParams } from "./InstalledVersionParams"
|
||||
export { InstallingInfo } from "./InstallingInfo"
|
||||
export { InstallingState } from "./InstallingState"
|
||||
export { InstallParams } from "./InstallParams"
|
||||
export { IpHostname } from "./IpHostname"
|
||||
export { IpInfo } from "./IpInfo"
|
||||
export { ListPackageSignersParams } from "./ListPackageSignersParams"
|
||||
@@ -136,14 +136,14 @@ export { NetworkInterfaceSetPublicParams } from "./NetworkInterfaceSetPublicPara
|
||||
export { NetworkInterfaceType } from "./NetworkInterfaceType"
|
||||
export { OnionHostname } from "./OnionHostname"
|
||||
export { OsIndex } from "./OsIndex"
|
||||
export { OsVersionInfo } from "./OsVersionInfo"
|
||||
export { OsVersionInfoMap } from "./OsVersionInfoMap"
|
||||
export { OsVersionInfo } from "./OsVersionInfo"
|
||||
export { PackageDataEntry } from "./PackageDataEntry"
|
||||
export { PackageDetailLevel } from "./PackageDetailLevel"
|
||||
export { PackageId } from "./PackageId"
|
||||
export { PackageIndex } from "./PackageIndex"
|
||||
export { PackageInfo } from "./PackageInfo"
|
||||
export { PackageInfoShort } from "./PackageInfoShort"
|
||||
export { PackageInfo } from "./PackageInfo"
|
||||
export { PackageSignerParams } from "./PackageSignerParams"
|
||||
export { PackageState } from "./PackageState"
|
||||
export { PackageVersionInfo } from "./PackageVersionInfo"
|
||||
@@ -165,18 +165,18 @@ export { Security } from "./Security"
|
||||
export { ServerInfo } from "./ServerInfo"
|
||||
export { ServerSpecs } from "./ServerSpecs"
|
||||
export { ServerStatus } from "./ServerStatus"
|
||||
export { ServiceInterface } from "./ServiceInterface"
|
||||
export { ServiceInterfaceId } from "./ServiceInterfaceId"
|
||||
export { ServiceInterface } from "./ServiceInterface"
|
||||
export { ServiceInterfaceType } from "./ServiceInterfaceType"
|
||||
export { Session } from "./Session"
|
||||
export { SessionList } from "./SessionList"
|
||||
export { Sessions } from "./Sessions"
|
||||
export { Session } from "./Session"
|
||||
export { SetDataVersionParams } from "./SetDataVersionParams"
|
||||
export { SetDependenciesParams } from "./SetDependenciesParams"
|
||||
export { SetHealth } from "./SetHealth"
|
||||
export { SetIconParams } from "./SetIconParams"
|
||||
export { SetMainStatus } from "./SetMainStatus"
|
||||
export { SetMainStatusStatus } from "./SetMainStatusStatus"
|
||||
export { SetMainStatus } from "./SetMainStatus"
|
||||
export { SetNameParams } from "./SetNameParams"
|
||||
export { SetStoreParams } from "./SetStoreParams"
|
||||
export { SetupExecuteParams } from "./SetupExecuteParams"
|
||||
@@ -191,7 +191,7 @@ export { TestSmtpParams } from "./TestSmtpParams"
|
||||
export { UnsetPublicParams } from "./UnsetPublicParams"
|
||||
export { UpdatingState } from "./UpdatingState"
|
||||
export { VerifyCifsParams } from "./VerifyCifsParams"
|
||||
export { Version } from "./Version"
|
||||
export { VersionSignerParams } from "./VersionSignerParams"
|
||||
export { Version } from "./Version"
|
||||
export { VolumeId } from "./VolumeId"
|
||||
export { WifiInfo } from "./WifiInfo"
|
||||
|
||||
Reference in New Issue
Block a user