Docker
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
# Log kernel iptables dropped messages to iptables.log
|
||||
$template MyTemplate,"%$day%-%timegenerated:1:3:date-rfc3164%-%$year% %timegenerated:12:19:date-rfc3339% %HOSTNAME% %syslogtag% %msg%\n"
|
||||
:msg,contains,"[IPTables-Dropped]:" /var/log/iptables.log;MyTemplate #RSYSLOG_FileFormat
|
||||
|
||||
# Uncomment the following to stop logging anything that matches the last rule.
|
||||
# Doing this will stop logging kernel generated UFW log messages to the file
|
||||
# normally containing kern.* messages (eg, /var/log/kern.log)
|
||||
#& stop
|
||||
@@ -0,0 +1,2 @@
|
||||
APT::Periodic::Update-Package-Lists "1";
|
||||
APT::Periodic::Unattended-Upgrade "1";
|
||||
@@ -0,0 +1,36 @@
|
||||
// Automatically upgrade packages from these (origin, archive) pairs
|
||||
Unattended-Upgrade::Allowed-Origins {
|
||||
// ${distro_id} and ${distro_codename} will be automatically expanded
|
||||
"${distro_id} stable";
|
||||
"${distro_id} ${distro_codename}-security";
|
||||
|
||||
// Autoupdate Nginx
|
||||
"nginx:${distro_codename}";
|
||||
|
||||
// Autoupdate WireGuard
|
||||
"LP-PPA-wireguard-wireguard:${distro_codename}";
|
||||
};
|
||||
|
||||
// List of packages to not update
|
||||
Unattended-Upgrade::Package-Blacklist {
|
||||
};
|
||||
|
||||
// Do automatic removal of new unused dependencies after the upgrade
|
||||
// (equivalent to apt-get autoremove)
|
||||
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
||||
|
||||
// Automatically reboot *WITHOUT CONFIRMATION* if a
|
||||
// the file /var/run/reboot-required is found after the upgrade
|
||||
Unattended-Upgrade::Automatic-Reboot "true";
|
||||
|
||||
// If automatic reboot is enabled and needed, reboot at the specific
|
||||
// time instead of immediately
|
||||
// Default: "now"
|
||||
Unattended-Upgrade::Automatic-Reboot-Time "00:00";
|
||||
|
||||
// Avoid conffile dpkg prompt by *always* leaving the modified configuration in
|
||||
// place and putting the new package configuration in a .dpkg-dist file
|
||||
Dpkg::Options {
|
||||
"--force-confdef";
|
||||
"--force-confold";
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
[WebService]
|
||||
ProtocolHeader = X-Forwarded-Proto
|
||||
AllowUnencrypted=true
|
||||
Executable
+238
@@ -0,0 +1,238 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
## ensure run as nonroot user
|
||||
#if [ "$EUID" -eq 0 ]; then
|
||||
MISTBORN_USER="mistborn"
|
||||
if [ $(whoami) != "$MISTBORN_USER" ]; then
|
||||
echo "Creating user: $MISTBORN_USER"
|
||||
sudo useradd -s /bin/bash -d /home/$MISTBORN_USER -m -G sudo $MISTBORN_USER 2>/dev/null || true
|
||||
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
|
||||
#echo "SCRIPTPATH: $SCRIPTPATH"
|
||||
FILENAME=$(basename -- "$0")
|
||||
#echo "FILENAME: $FILENAME"
|
||||
FULLPATH="$SCRIPTPATH/$FILENAME"
|
||||
#echo "FULLPATH: $FULLPATH"
|
||||
|
||||
# SUDO
|
||||
case `sudo grep -e "^$MISTBORN_USER.*" /etc/sudoers >/dev/null; echo $?` in
|
||||
0)
|
||||
echo "$MISTBORN_USER already in sudoers"
|
||||
;;
|
||||
1)
|
||||
echo "Adding $MISTBORN_USER to sudoers"
|
||||
sudo bash -c "echo '$MISTBORN_USER ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers"
|
||||
;;
|
||||
*)
|
||||
echo "There was a problem checking sudoers"
|
||||
;;
|
||||
esac
|
||||
|
||||
# get git branch if one exists (default to master)
|
||||
pushd .
|
||||
cd $SCRIPTPATH
|
||||
GIT_BRANCH=$(git symbolic-ref --short HEAD || echo "master")
|
||||
popd
|
||||
|
||||
sudo cp $FULLPATH /home/$MISTBORN_USER
|
||||
sudo chown $MISTBORN_USER:$MISTBORN_USER /home/$MISTBORN_USER/$FILENAME
|
||||
sudo SSH_CLIENT="$SSH_CLIENT" MISTBORN_DEFAULT_PASSWORD="$MISTBORN_DEFAULT_PASSWORD" GIT_BRANCH="$GIT_BRANCH" -i -u $MISTBORN_USER bash -c "/home/$MISTBORN_USER/$FILENAME" # self-referential call
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Running as $USER"
|
||||
|
||||
# banner
|
||||
echo -e " ____ _ ____ _ __"
|
||||
echo -e " / ___| _| |__ ___ _ __ | ___|| |/ /"
|
||||
echo -e "| | | | | | '_ \ / _ \ '__| |___ \| ' /"
|
||||
echo -e "| |__| |_| | |_) | __/ | ___) | . \ "
|
||||
echo -e " \____\__, |_.__/ \___|_| |____/|_|\_\ "
|
||||
echo -e " |___/"
|
||||
echo -e " __ __ _ _ _"
|
||||
echo -e "| \/ (_)___| |_| |__ ___ _ __ _ __"
|
||||
echo -e "| |\/| | / __| __| '_ \ / _ \| '__| '_ \ "
|
||||
echo -e "| | | | \__ \ |_| |_) | (_) | | | | | |"
|
||||
echo -e "|_| |_|_|___/\__|_.__/ \___/|_| |_| |_|"
|
||||
echo -e ""
|
||||
|
||||
# Get OS info
|
||||
# Determine OS platform
|
||||
UNAME=$(uname | tr "[:upper:]" "[:lower:]")
|
||||
DISTRO=""
|
||||
# If Linux, try to determine specific distribution
|
||||
if [ "$UNAME" == "linux" ]; then
|
||||
# use /etc/os-release to get distro
|
||||
DISTRO=$(cat /etc/os-release | awk -F= '/^ID=/{print $2}')
|
||||
fi
|
||||
|
||||
echo "UNAME: $UNAME"
|
||||
echo "DISTRO: $DISTRO"
|
||||
|
||||
# INPUT default admin password
|
||||
if [ -z "${MISTBORN_DEFAULT_PASSWORD}" ]; then
|
||||
read -p "(Mistborn) Set default admin password: " -s MISTBORN_DEFAULT_PASSWORD
|
||||
echo
|
||||
else
|
||||
echo "MISTBORN_DEFAULT_PASSWORD is already set"
|
||||
fi
|
||||
|
||||
# SSH keys
|
||||
if [ ! -f ~/.ssh/id_rsa ]; then
|
||||
echo "Generating SSH keypair for $USER"
|
||||
ssh-keygen -t rsa -b 4096 -N "" -m pem -f ~/.ssh/id_rsa -q
|
||||
|
||||
# Authorized keys
|
||||
echo "from=\"172.16.0.0/12,192.168.0.0/16,10.0.0.0/8\" $(cat ~/.ssh/id_rsa.pub)" > ~/.ssh/authorized_keys
|
||||
else
|
||||
echo "SSH key exists for $USER"
|
||||
fi
|
||||
|
||||
sudo rm -rf /opt/mistborn 2>/dev/null || true
|
||||
|
||||
# clone to /opt and change directory
|
||||
echo "Cloning $GIT_BRANCH branch from mistborn repo"
|
||||
sudo git clone https://gitlab.com/cyber5k/mistborn.git -b $GIT_BRANCH /opt/mistborn
|
||||
sudo chown -R $USER:$USER /opt/mistborn
|
||||
pushd .
|
||||
cd /opt/mistborn
|
||||
git submodule update --init --recursive
|
||||
|
||||
# iptables
|
||||
echo "Setting up firewall (iptables)"
|
||||
if [ ! -f "/etc/iptables/rules.v4" ]; then
|
||||
echo "Setting iptables rules..."
|
||||
./scripts/subinstallers/iptables.sh
|
||||
else
|
||||
echo "iptables rules exist. Leaving alone."
|
||||
fi
|
||||
|
||||
|
||||
# SSH Server
|
||||
sudo apt-get install -y openssh-server
|
||||
sudo sed -i 's/#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
|
||||
sudo sed -i 's/PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
|
||||
sudo sed -i 's/#PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
|
||||
sudo sed -i 's/PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
|
||||
sudo systemctl restart ssh
|
||||
|
||||
# Additional tools fail2ban
|
||||
sudo apt-get install -y dnsutils fail2ban
|
||||
|
||||
# Install kernel headers
|
||||
if [ "$DISTRO" == "ubuntu" ] || [ "$DISTRO" == "debian" ]; then
|
||||
sudo apt install -y linux-headers-$(uname -r)
|
||||
elif [ "$DISTRO" == "raspbian" ]; then
|
||||
sudo apt-get install -y raspberrypi-kernel-headers
|
||||
fi
|
||||
|
||||
# Wireugard
|
||||
source ./scripts/subinstallers/wireguard.sh
|
||||
|
||||
# Docker
|
||||
source ./scripts/subinstallers/docker.sh
|
||||
|
||||
# Unattended upgrades
|
||||
sudo apt-get install -y unattended-upgrades
|
||||
|
||||
# Cockpit
|
||||
source ./scripts/subinstallers/cockpit.sh
|
||||
|
||||
# Mistborn
|
||||
# final setup vars
|
||||
iface=$(ip -o -4 route show to default | egrep -o 'dev [^ ]*' | awk '{print $2}')
|
||||
IPV4_PUBLIC=$(ip -o -4 route show default | egrep -o 'dev [^ ]*' | awk '{print $2}' | xargs ip -4 addr show | grep 'inet ' | awk '{print $2}' | grep -o "^[0-9.]*" | tr -cd '\11\12\15\40-\176' | head -1) # tail -1 to get last
|
||||
|
||||
# clean
|
||||
if [ -f "/etc/systemd/system/Mistborn-base.service" ]; then
|
||||
sudo systemctl stop Mistborn*.service 2>/dev/null || true
|
||||
sudo systemctl disable Mistborn*.service 2>/dev/null || true
|
||||
fi
|
||||
|
||||
sudo docker volume rm -f mistborn_production_postgres_data 2>/dev/null || true
|
||||
sudo docker volume rm -f mistborn_production_postgres_data_backups 2>/dev/null || true
|
||||
sudo docker volume rm -f mistborn_production_traefik 2>/dev/null || true
|
||||
|
||||
# generate production .env file
|
||||
if [ ! -d ./.envs/.production ]; then
|
||||
./scripts/subinstallers/gen_prod_env.sh "$MISTBORN_DEFAULT_PASSWORD"
|
||||
fi
|
||||
|
||||
# unattended upgrades
|
||||
sudo cp ./scripts/conf/20auto-upgrades /etc/apt/apt.conf.d/
|
||||
sudo cp ./scripts/conf/50unattended-upgrades /etc/apt/apt.conf.d/
|
||||
|
||||
sudo systemctl stop unattended-upgrades
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl restart unattended-upgrades
|
||||
|
||||
# setup Mistborn services
|
||||
|
||||
# install and start base services
|
||||
# default interface
|
||||
sudo cp ./scripts/services/Mistborn* /etc/systemd/system/
|
||||
sudo find /etc/systemd/system/ -type f -name 'Mistborn*' | xargs sudo sed -i "s/User=.*/User=$USER/"
|
||||
sudo find /etc/systemd/system/ -type f -name 'Mistborn*' | xargs sudo sed -i "s/ root:root / $USER:$USER /"
|
||||
sudo find /etc/systemd/system/ -type f -name 'Mistborn*' | xargs sudo sed -i "s/DIFACE/$iface/"
|
||||
|
||||
if [ "$DISTRO" == "debian" ] || [ "$DISTRO" == "raspbian" ]; then
|
||||
# remove systemd-resolved lines
|
||||
sudo sed -i '/.*systemd-resolved/d' /etc/systemd/system/Mistborn-base.service
|
||||
fi
|
||||
|
||||
# setup local volumes for pihole
|
||||
sudo mkdir -p ../mistborn_volumes/
|
||||
sudo chown -R root:root ../mistborn_volumes/
|
||||
sudo mkdir -p ../mistborn_volumes/base/pihole/etc-pihole
|
||||
sudo mkdir -p ../mistborn_volumes/base/pihole/etc-dnsmasqd
|
||||
echo "addn-hosts=/etc/pihole/lan.list" | sudo tee ../mistborn_volumes/base/pihole/etc-dnsmasqd/02-lan.conf
|
||||
sudo touch ../mistborn_volumes/base/pihole/etc-pihole/lan.list
|
||||
sudo mkdir -p ../mistborn_volumes/extra
|
||||
|
||||
# Traefik final setup (cockpit)
|
||||
sudo sed -i "s/IPV4_PUBLIC/$IPV4_PUBLIC/" ./compose/production/traefik/traefik.toml
|
||||
|
||||
# Download docker images while DNS is operable
|
||||
sudo docker-compose -f base.yml pull || true
|
||||
sudo docker-compose -f base.yml build
|
||||
|
||||
# DNS
|
||||
sudo systemctl stop systemd-resolved 2>/dev/null || true
|
||||
sudo systemctl disable systemd-resolved 2>/dev/null || true
|
||||
|
||||
# array of dns entries to add (not not already present)
|
||||
declare -a dnslist=("pihole.mistborn" \
|
||||
"home.mistborn" \
|
||||
"hass.mistborn" \
|
||||
"syncthing.mistborn" \
|
||||
"chat.mistborn" \
|
||||
"tor.mistborn" \
|
||||
"nextcloud.mistborn" \
|
||||
"onlyoffice.mistborn" \
|
||||
"bitwarden.mistborn" \
|
||||
"jellyfin.mistborn" \
|
||||
"raspap.mistborn" \
|
||||
"cockpit.mistborn")
|
||||
|
||||
for dnsname in "${dnslist[@]}"
|
||||
do
|
||||
sudo grep -qF "$dnsname" ../mistborn_volumes/base/pihole/etc-pihole/lan.list \
|
||||
&& echo "$dnsname already in DNS" \
|
||||
|| echo "$IPV4_PUBLIC $dnsname" | sudo tee -a ../mistborn_volumes/base/pihole/etc-pihole/lan.list
|
||||
done
|
||||
|
||||
# ResolvConf (OpenResolv installed with Wireguard)
|
||||
sudo sed -i "s/#name_servers.*/name_servers=$IPV4_PUBLIC/" /etc/resolvconf.conf
|
||||
sudo sed -i "s/name_servers.*/name_servers=$IPV4_PUBLIC/" /etc/resolvconf.conf
|
||||
#sudo sed -i "s/#name_servers.*/name_servers=127.0.0.1/" /etc/resolvconf.conf
|
||||
sudo resolvconf -u 1>/dev/null 2>&1
|
||||
|
||||
echo "backup up original volumes folder"
|
||||
sudo mkdir -p ../mistborn_backup
|
||||
sudo tar -czf ../mistborn_backup/mistborn_volumes_backup.tar.gz ../mistborn_volumes 1>/dev/null 2>&1
|
||||
|
||||
# start base service
|
||||
sudo systemctl enable Mistborn-base.service
|
||||
sudo systemctl start Mistborn-base.service
|
||||
popd
|
||||
@@ -0,0 +1,37 @@
|
||||
[Unit]
|
||||
Description=Mistborn Base
|
||||
Requires=docker.service
|
||||
After=docker.service
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
User=root
|
||||
Group=docker
|
||||
PermissionsStartOnly=true
|
||||
# Shutdown container (if running) when unit is stopped
|
||||
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/base.yml down
|
||||
ExecStartPre=/bin/chown -R root:root /opt/mistborn_volumes/
|
||||
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/base.yml build
|
||||
ExecStartPre=/bin/systemctl stop systemd-resolved
|
||||
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p udp --dport 53 -j MISTBORN_LOG_DROP
|
||||
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p tcp --dport 53 -j MISTBORN_LOG_DROP
|
||||
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p tcp --dport 80 -j MISTBORN_LOG_DROP
|
||||
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p tcp --dport 5555 -j MISTBORN_LOG_DROP
|
||||
ExecStartPre=/sbin/iptables -A OUTPUT -o DIFACE -p udp --dport 53 -j MISTBORN_LOG_DROP
|
||||
ExecStartPre=/sbin/ip6tables -A OUTPUT -p udp --dport 53 -j MISTBORN_LOG_DROP
|
||||
ExecStartPre=/sbin/resolvconf -u
|
||||
# Start container when unit is started
|
||||
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/base.yml up
|
||||
# Stop container when unit is stopped
|
||||
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/base.yml down
|
||||
# Post stop
|
||||
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p udp --dport 53 -j MISTBORN_LOG_DROP
|
||||
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p tcp --dport 53 -j MISTBORN_LOG_DROP
|
||||
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p tcp --dport 80 -j MISTBORN_LOG_DROP
|
||||
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p tcp --dport 5555 -j MISTBORN_LOG_DROP
|
||||
ExecStopPost=/sbin/iptables -D OUTPUT -o DIFACE -p udp --dport 53 -j MISTBORN_LOG_DROP
|
||||
ExecStopPost=/sbin/ip6tables -D OUTPUT -p udp --dport 53 -j MISTBORN_LOG_DROP
|
||||
ExecStopPost=/bin/systemctl start systemd-resolved
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,23 @@
|
||||
[Unit]
|
||||
Description=Mistborn Bitwarden Service
|
||||
Requires=Mistborn-base.service
|
||||
After=Mistborn-base.service
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
User=root
|
||||
Group=docker
|
||||
PermissionsStartOnly=true
|
||||
# Shutdown container (if running) when unit is stopped
|
||||
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/bitwarden.yml down
|
||||
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
|
||||
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p tcp --dport 3012 -j MISTBORN_LOG_DROP
|
||||
# Start container when unit is started
|
||||
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/bitwarden.yml up --build
|
||||
# Stop container when unit is stopped
|
||||
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/bitwarden.yml down
|
||||
# Post stop
|
||||
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p tcp --dport 3012 -j MISTBORN_LOG_DROP
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,21 @@
|
||||
[Unit]
|
||||
Description=Mistborn Home Assistant
|
||||
Requires=Mistborn-base.service
|
||||
After=Mistborn-base.service
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
User=root
|
||||
Group=docker
|
||||
PermissionsStartOnly=true
|
||||
# Shutdown container (if running) when unit is stopped
|
||||
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/homeassistant.yml down
|
||||
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
|
||||
# Start container when unit is started
|
||||
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/homeassistant.yml up --build
|
||||
# Stop container when unit is stopped
|
||||
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/homeassistant.yml down
|
||||
# Post stop
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,21 @@
|
||||
[Unit]
|
||||
Description=Mistborn Jellyfin Service
|
||||
Requires=Mistborn-nextcloud.service
|
||||
After=Mistborn-nextcloud.service
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
User=root
|
||||
Group=docker
|
||||
PermissionsStartOnly=true
|
||||
# Shutdown container (if running) when unit is stopped
|
||||
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/jellyfin.yml down
|
||||
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
|
||||
# Start container when unit is started
|
||||
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/jellyfin.yml up --build
|
||||
# Stop container when unit is stopped
|
||||
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/jellyfin.yml down
|
||||
# Post stop
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,21 @@
|
||||
[Unit]
|
||||
Description=Mistborn Nextcloud Service
|
||||
Requires=Mistborn-base.service
|
||||
After=Mistborn-base.service
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
User=root
|
||||
Group=docker
|
||||
PermissionsStartOnly=true
|
||||
# Shutdown container (if running) when unit is stopped
|
||||
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/nextcloud.yml down
|
||||
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
|
||||
# Start container when unit is started
|
||||
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/nextcloud.yml up --build
|
||||
# Stop container when unit is stopped
|
||||
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/nextcloud.yml down
|
||||
# Post stop
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,21 @@
|
||||
[Unit]
|
||||
Description=Mistborn OnlyOffice Service
|
||||
Requires=Mistborn-base.service
|
||||
After=Mistborn-base.service
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
User=root
|
||||
Group=docker
|
||||
PermissionsStartOnly=true
|
||||
# Shutdown container (if running) when unit is stopped
|
||||
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/onlyoffice.yml down
|
||||
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
|
||||
# Start container when unit is started
|
||||
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/onlyoffice.yml up --build
|
||||
# Stop container when unit is stopped
|
||||
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/onlyoffice.yml down
|
||||
# Post stop
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,21 @@
|
||||
[Unit]
|
||||
Description=Mistborn RaspAP Service
|
||||
Requires=Mistborn-base.service
|
||||
After=Mistborn-base.service
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
User=root
|
||||
Group=docker
|
||||
PermissionsStartOnly=true
|
||||
# Shutdown container (if running) when unit is stopped
|
||||
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/raspap.yml down
|
||||
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
|
||||
# Start container when unit is started
|
||||
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/raspap.yml up --build
|
||||
# Stop container when unit is stopped
|
||||
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/raspap.yml down
|
||||
# Post stop
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,23 @@
|
||||
[Unit]
|
||||
Description=Mistborn Rocket Chat Service
|
||||
Requires=Mistborn-base.service
|
||||
After=Mistborn-base.service
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
User=root
|
||||
Group=docker
|
||||
PermissionsStartOnly=true
|
||||
# Shutdown container (if running) when unit is stopped
|
||||
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/rocketchat.yml down
|
||||
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
|
||||
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p tcp --dport 3001 -j MISTBORN_LOG_DROP
|
||||
# Start container when unit is started
|
||||
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/rocketchat.yml up --build
|
||||
# Stop container when unit is stopped
|
||||
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/rocketchat.yml down
|
||||
# Post stop
|
||||
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p tcp --dport 3001 -j MISTBORN_LOG_DROP
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,25 @@
|
||||
[Unit]
|
||||
Description=Mistborn Syncthing Service
|
||||
Requires=Mistborn-base.service
|
||||
After=Mistborn-base.service
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
User=root
|
||||
Group=docker
|
||||
PermissionsStartOnly=true
|
||||
# Shutdown container (if running) when unit is stopped
|
||||
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/syncthing.yml down
|
||||
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
|
||||
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p udp --dport 21027 -j MISTBORN_LOG_DROP
|
||||
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p tcp --dport 22000 -j MISTBORN_LOG_DROP
|
||||
# Start container when unit is started
|
||||
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/syncthing.yml up --build
|
||||
# Stop container when unit is stopped
|
||||
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/syncthing.yml down
|
||||
# Post stop
|
||||
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p udp --dport 21027 -j MISTBORN_LOG_DROP
|
||||
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p tcp --dport 22000 -j MISTBORN_LOG_DROP
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,23 @@
|
||||
[Unit]
|
||||
Description=Mistborn Tor Service
|
||||
Requires=Mistborn-base.service
|
||||
After=Mistborn-base.service
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
User=root
|
||||
Group=docker
|
||||
PermissionsStartOnly=true
|
||||
# Shutdown container (if running) when unit is stopped
|
||||
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/tor.yml down
|
||||
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
|
||||
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p tcp --dport 9150 -j MISTBORN_LOG_DROP
|
||||
# Start container when unit is started
|
||||
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/tor.yml up --build
|
||||
# Stop container when unit is stopped
|
||||
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/tor.yml down
|
||||
# Post stop
|
||||
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p tcp --dport 9150 -j MISTBORN_LOG_DROP
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# install on gateway
|
||||
sudo apt-get install -y hostapd vnstat
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Cockpit
|
||||
echo "Installing Cockpit"
|
||||
if [ "$DISTRO" == "ubuntu" ]; then
|
||||
echo "Ubuntu backports enabled by default"
|
||||
|
||||
sudo apt-get install -y cockpit cockpit-docker
|
||||
|
||||
elif [ "$DISTRO" == "debian" ]; then
|
||||
sudo grep -qF "buster-backports" /etc/apt/sources.list.d/backports.list \
|
||||
&& echo "buster-backports already in sources" \
|
||||
|| echo 'deb http://deb.debian.org/debian buster-backports main' | sudo tee -a /etc/apt/sources.list.d/backports.list
|
||||
|
||||
sudo apt-get install -y cockpit cockpit-docker
|
||||
|
||||
elif [ "$DISTRO" == "raspbian" ]; then
|
||||
|
||||
echo "Raspbian repos contain cockpit"
|
||||
sudo apt-get install -y cockpit cockpit-docker
|
||||
|
||||
fi
|
||||
|
||||
sudo cp ./scripts/conf/cockpit.conf /etc/cockpit/cockpit.conf
|
||||
sudo systemctl restart cockpit.socket
|
||||
|
||||
# create system cockpit user
|
||||
echo "Creating cockpit user"
|
||||
sudo useradd -s /bin/bash -d /home/cockpit -m -G sudo -p $(openssl passwd -1 "$MISTBORN_DEFAULT_PASSWORD") cockpit || true
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Docker
|
||||
# dependencies
|
||||
echo "Installing Docker dependencies"
|
||||
sudo apt-get install -y \
|
||||
apt-transport-https \
|
||||
ca-certificates \
|
||||
curl \
|
||||
gnupg-agent \
|
||||
software-properties-common
|
||||
|
||||
# Docker repo key
|
||||
echo "Adding docker repository key"
|
||||
if [ "$DISTRO" == "ubuntu" ]; then
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
|
||||
elif [ "$DISTRO" == "debian" ]; then
|
||||
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
|
||||
elif [ "$DISTRO" == "raspbian" ]; then
|
||||
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | sudo apt-key add -
|
||||
fi
|
||||
|
||||
# Docker repo to source list
|
||||
echo "Adding docker to sources list"
|
||||
if [ "$DISTRO" == "ubuntu" ]; then
|
||||
sudo add-apt-repository -y \
|
||||
"deb https://download.docker.com/linux/ubuntu \
|
||||
$(lsb_release -cs) \
|
||||
stable"
|
||||
elif [ "$DISTRO" == "debian" ]; then
|
||||
sudo add-apt-repository -y \
|
||||
"deb https://download.docker.com/linux/debian \
|
||||
$(lsb_release -cs) \
|
||||
stable"
|
||||
elif [ "$DISTRO" == "raspbian" ]; then
|
||||
echo "deb [arch=armhf] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
|
||||
$(lsb_release -cs) stable" | \
|
||||
sudo tee /etc/apt/sources.list.d/docker.list
|
||||
fi
|
||||
|
||||
# install Docker
|
||||
echo "Installing docker"
|
||||
sudo apt-get update
|
||||
|
||||
if [ "$DISTRO" == "ubuntu" ] || [ "$DISTRO" == "debian" ]; then
|
||||
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
|
||||
elif [ "$DISTRO" == "raspbian" ]; then
|
||||
sudo apt install -y --no-install-recommends \
|
||||
docker-ce \
|
||||
cgroupfs-mount
|
||||
fi
|
||||
|
||||
# Docker group
|
||||
sudo usermod -aG docker $USER
|
||||
|
||||
# Docker Compose
|
||||
echo "Installing Docker Compose"
|
||||
#if [ "$DISTRO" == "ubuntu" ] || [ "$DISTRO" == "debian" ]; then
|
||||
# sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
# sudo chmod +x /usr/local/bin/docker-compose
|
||||
#elif [ "$DISTRO" == "raspbian" ]; then
|
||||
# Install required packages
|
||||
sudo apt update
|
||||
sudo apt install -y python python3-pip libffi-dev python-backports.ssl-match-hostname
|
||||
|
||||
# Install Docker Compose from pip
|
||||
# This might take a while
|
||||
sudo pip3 install docker-compose
|
||||
#fi
|
||||
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/bin/sh
|
||||
|
||||
# generate production .env file for Django
|
||||
mkdir -p ./.envs/.production
|
||||
DJANGO_PROD_FILE="./.envs/.production/.django"
|
||||
DJANGO_SECRET_KEY=$(python3 -c "import secrets; import string; print(f''.join([secrets.choice(string.ascii_letters+string.digits) for x in range(50)]))")
|
||||
#CELERY_FLOWER_PASSWORD=$(python3 -c "import secrets; import string; print(f''.join([secrets.choice(string.ascii_letters+string.digits) for x in range(32)]))")
|
||||
MISTBORN_DEFAULT_PASSWORD="$1"
|
||||
echo "DJANGO_SETTINGS_MODULE=config.settings.production" > $DJANGO_PROD_FILE
|
||||
echo "DJANGO_SECRET_KEY=$DJANGO_SECRET_KEY" >> $DJANGO_PROD_FILE
|
||||
echo "DJANGO_ADMIN_URL=admin/" >> $DJANGO_PROD_FILE
|
||||
echo "USE_DOCKER=yes" >> $DJANGO_PROD_FILE
|
||||
echo "REDIS_URL=redis://redis:6379/0" >> $DJANGO_PROD_FILE
|
||||
echo "CELERY_FLOWER_USER=prod" >> $DJANGO_PROD_FILE
|
||||
echo "CELERY_FLOWER_PASSWORD=$MISTBORN_DEFAULT_PASSWORD" >> $DJANGO_PROD_FILE
|
||||
echo "MISTBORN_DEFAULT_PASSWORD=$MISTBORN_DEFAULT_PASSWORD" >> $DJANGO_PROD_FILE
|
||||
echo "#MAILGUN_API_KEY=" >> $DJANGO_PROD_FILE
|
||||
echo "#MAILGUN_API_URL=" >> $DJANGO_PROD_FILE
|
||||
echo "#SENTRY_DNS=" >> $DJANGO_PROD_FILE
|
||||
|
||||
# generate production .env file for postgresql
|
||||
POSTGRES_PROD_FILE="./.envs/.production/.postgres"
|
||||
POSTGRES_PASSWORD=$(python3 -c "import secrets; import string; print(f''.join([secrets.choice(string.ascii_letters+string.digits) for x in range(32)]))")
|
||||
echo "POSTGRES_HOST=postgres" > $POSTGRES_PROD_FILE
|
||||
echo "POSTGRES_PORT=5432" >> $POSTGRES_PROD_FILE
|
||||
echo "POSTGRES_DB=mistborn" >> $POSTGRES_PROD_FILE
|
||||
echo "POSTGRES_USER=prod" >> $POSTGRES_PROD_FILE
|
||||
echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> $POSTGRES_PROD_FILE
|
||||
|
||||
|
||||
# generate production .env file for pihole
|
||||
PIHOLE_PROD_FILE="./.envs/.production/.pihole"
|
||||
#WEBPASSWORD=$(python3 -c "import secrets; import string; print(f''.join([secrets.choice(string.ascii_letters+string.digits) for x in range(32)]))")
|
||||
WEBPASSWORD="$1"
|
||||
echo "TZ=\"America/New York\"" > $PIHOLE_PROD_FILE
|
||||
echo "WEBPASSWORD=$WEBPASSWORD" >> $PIHOLE_PROD_FILE
|
||||
|
||||
# generate rocketchat .env files
|
||||
ROCKETCHAT_PROD_FILE="./.envs/.production/.rocketchat"
|
||||
#ROCKETCHAT_PASSWORD=$(python3 -c "import secrets; import string; print(f''.join([secrets.choice(string.ascii_letters+string.digits) for x in range(32)]))")
|
||||
ROCKETCHAT_PASSWORD="$1"
|
||||
echo "ROCKETCHAT_USER=bot" > $ROCKETCHAT_PROD_FILE
|
||||
echo "ROCKETCHAT_ROOM=GENERAL" >> $ROCKETCHAT_PROD_FILE
|
||||
echo "BOT_NAME=bot" >> $ROCKETCHAT_PROD_FILE
|
||||
echo "ROCKETCHAT_PASSWORD=$ROCKETCHAT_PASSWORD" >> $ROCKETCHAT_PROD_FILE
|
||||
|
||||
# generate nextcloud .env files
|
||||
NEXTCLOUD_PROD_FILE="./.envs/.production/.nextcloud"
|
||||
#NEXTCLOUD_PASSWORD=$(python3 -c "import secrets; import string; print(f''.join([secrets.choice(string.ascii_letters+string.digits) for x in range(32)]))")
|
||||
NEXTCLOUD_PASSWORD="$1"
|
||||
echo "NEXTCLOUD_ADMIN_USER=mistborn" > $NEXTCLOUD_PROD_FILE
|
||||
echo "NEXTCLOUD_ADMIN_PASSWORD=$NEXTCLOUD_PASSWORD" >> $NEXTCLOUD_PROD_FILE
|
||||
echo "NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.mistborn" >> $NEXTCLOUD_PROD_FILE
|
||||
|
||||
# generate onlyoffice .env files
|
||||
ONLYOFFICE_PROD_FILE="./.envs/.production/.onlyoffice"
|
||||
JWT_SECRET="$1"
|
||||
echo "JWT_ENABLED=true" > $ONLYOFFICE_PROD_FILE
|
||||
echo "JWT_SECRET=$JWT_SECRET" >> $ONLYOFFICE_PROD_FILE
|
||||
|
||||
# generate bitwarden .env files
|
||||
BITWARDEN_PROD_FILE="./.envs/.production/.bitwarden"
|
||||
echo "WEBSOCKET_ENABLED=true" > $BITWARDEN_PROD_FILE
|
||||
echo "SIGNUPS_ALLOWED=true" >> $BITWARDEN_PROD_FILE
|
||||
Executable
+119
@@ -0,0 +1,119 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
|
||||
echo "stop iptables wrappers"
|
||||
if [ "$DISTRO" == "ubuntu" ]; then
|
||||
# Disable UFW
|
||||
sudo systemctl stop ufw || true
|
||||
sudo systemctl disable ufw || true
|
||||
fi
|
||||
|
||||
# default interface
|
||||
iface=$(ip -o -4 route show to default | egrep -o 'dev [^ ]*' | awk '{print $2}')
|
||||
|
||||
# real public interface
|
||||
riface=$(ip -o -4 route get 1.1.1.1 | egrep -o 'dev [^ ]*' | awk '{print $2}')
|
||||
|
||||
# resetting iptables
|
||||
sudo iptables -F
|
||||
sudo iptables -t nat -F
|
||||
sudo iptables -X MISTBORN_LOG_DROP 2>/dev/null || true
|
||||
sudo iptables -X MISTBORN_WIREGUARD_INPUT 2>/dev/null || true
|
||||
sudo iptables -X MISTBORN_WIREGUARD_FORWARD 2>/dev/null || true
|
||||
sudo iptables -X MISTBORN_DOCKER_INPUT 2>/dev/null || true
|
||||
|
||||
# iptables: log and drop chain
|
||||
sudo iptables -N MISTBORN_LOG_DROP
|
||||
sudo iptables -A MISTBORN_LOG_DROP -m limit --limit 2/min -j LOG --log-prefix "[IPTables-Dropped]: " --log-level 4
|
||||
sudo iptables -A MISTBORN_LOG_DROP -j DROP
|
||||
|
||||
# wireguard rules chains
|
||||
sudo iptables -N MISTBORN_WIREGUARD_INPUT
|
||||
sudo iptables -N MISTBORN_WIREGUARD_FORWARD
|
||||
|
||||
# iptables
|
||||
echo "Setting iptables rules"
|
||||
sudo iptables -P INPUT ACCEPT
|
||||
sudo iptables -I INPUT -i lo -j ACCEPT
|
||||
sudo iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||
|
||||
# if installing over SSH, add SSH rule
|
||||
if [ ! -z "${SSH_CLIENT}" ]; then
|
||||
SSH_SRC=$(echo $SSH_CLIENT | awk '{print $1}')
|
||||
sudo iptables -A INPUT -p tcp -s $SSH_SRC --dport 22 -j ACCEPT
|
||||
fi
|
||||
|
||||
# docker rules
|
||||
sudo iptables -N MISTBORN_DOCKER_INPUT
|
||||
sudo iptables -A MISTBORN_DOCKER_INPUT -i br-+ -j ACCEPT
|
||||
#sudo iptables -A INPUT ! -i $iface -s 172.16.0.0/12 -j ACCEPT
|
||||
|
||||
# last rules
|
||||
sudo iptables -A INPUT -j MISTBORN_DOCKER_INPUT
|
||||
sudo iptables -A INPUT -j MISTBORN_WIREGUARD_INPUT
|
||||
sudo iptables -A INPUT -j MISTBORN_LOG_DROP
|
||||
sudo iptables -A FORWARD -j MISTBORN_WIREGUARD_FORWARD
|
||||
|
||||
sudo iptables -P INPUT DROP
|
||||
sudo iptables -P FORWARD DROP
|
||||
sudo iptables -P OUTPUT ACCEPT
|
||||
|
||||
#if [ "$iface" == "$riface" ]; then
|
||||
sudo iptables -t nat -I POSTROUTING -o $iface -j MASQUERADE
|
||||
#else
|
||||
# sudo iptables -t nat -I POSTROUTING -o $iface -j MASQUERADE
|
||||
# sudo iptables -t nat -I POSTROUTING -o $riface -j MASQUERADE
|
||||
#fi
|
||||
|
||||
# resetting ip6tables rules
|
||||
sudo ip6tables -F
|
||||
sudo ip6tables -t nat -F
|
||||
sudo ip6tables -X MISTBORN_LOG_DROP 2>/dev/null || true
|
||||
|
||||
# ip6tables: log and drop chain
|
||||
sudo ip6tables -N MISTBORN_LOG_DROP
|
||||
sudo ip6tables -A MISTBORN_LOG_DROP -m limit --limit 6/min -j LOG --log-prefix "[IPTables-Dropped]: " --log-level 4
|
||||
sudo ip6tables -A MISTBORN_LOG_DROP -j DROP
|
||||
|
||||
# ip6tables
|
||||
echo "Setting ip6tables rules"
|
||||
sudo ip6tables -P INPUT ACCEPT
|
||||
sudo ip6tables -I INPUT -i lo -j ACCEPT
|
||||
sudo ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||
sudo ip6tables -A INPUT -j MISTBORN_LOG_DROP
|
||||
|
||||
sudo ip6tables -P INPUT DROP
|
||||
sudo ip6tables -P FORWARD DROP
|
||||
sudo ip6tables -P OUTPUT ACCEPT
|
||||
|
||||
|
||||
# initial load update package list
|
||||
sudo apt-get update
|
||||
|
||||
# iptables-persistent
|
||||
if [ ! "$(dpkg-query -l iptables-persistent)" ]; then
|
||||
echo "Installing iptables-persistent"
|
||||
|
||||
# answer variables
|
||||
echo iptables-persistent iptables-persistent/autosave_v4 boolean true | sudo debconf-set-selections
|
||||
echo iptables-persistent iptables-persistent/autosave_v6 boolean true | sudo debconf-set-selections
|
||||
|
||||
# install
|
||||
sudo apt-get install -y iptables-persistent ipset
|
||||
else
|
||||
echo "Saving iptables rules"
|
||||
sudo bash -c "iptables-save > /etc/iptables/rules.v4"
|
||||
echo "Saving ip6tables rules"
|
||||
sudo bash -c "ip6tables-save > /etc/iptables/rules.v6"
|
||||
fi
|
||||
|
||||
# IP forwarding
|
||||
sudo sed -i 's/.*net.ipv4.ip_forward.*/net.ipv4.ip_forward=1/' /etc/sysctl.conf
|
||||
sudo sysctl -p /etc/sysctl.conf
|
||||
|
||||
# rsyslog to create /var/log/iptables.log
|
||||
sudo cp ./scripts/conf/15-iptables.conf /etc/rsyslog.d/
|
||||
sudo chown root:root /etc/rsyslog.d/15-iptables.conf
|
||||
sudo systemctl restart rsyslog
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Wireguard
|
||||
if [ "$DISTRO" == "raspbian" ]; then
|
||||
echo "Adding Wireguard repo keys"
|
||||
sudo apt-get install -y dirmngr
|
||||
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 8B48AD6246925553
|
||||
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 7638D0442B90D010
|
||||
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 04EE7237B7D453EC
|
||||
fi
|
||||
|
||||
echo "Installing Wireguard"
|
||||
if [ "$DISTRO" == "ubuntu" ]; then
|
||||
# Ubuntu
|
||||
sudo add-apt-repository -y ppa:wireguard/wireguard
|
||||
elif [ "$DISTRO" == "debian" ] || [ "$DISTRO" == "raspbian" ]; then
|
||||
# Debian
|
||||
sudo bash -c 'echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable.list'
|
||||
sudo bash -c "printf 'Package: *\nPin: release a=unstable\nPin-Priority: 90\n' > /etc/apt/preferences.d/limit-unstable"
|
||||
fi
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y openresolv wireguard
|
||||
Reference in New Issue
Block a user