Compare commits
251 Commits
Author | SHA1 | Date |
---|---|---|
Derek Smith | 29f5b56223 | |
Derek Smith | 1a0ef1914d | |
Derek Smith | aa30705933 | |
Derek Smith | f3137873f0 | |
Derek Smith | afcc6b5fec | |
Derek Smith | 01c86c6ed0 | |
Derek Smith | cb93e58591 | |
Derek Smith | e34a765c69 | |
Derek Smith | 091e34462e | |
Derek Smith | 10801851c7 | |
Derek Smith | ea7bd1d42c | |
Derek Smith | c457118aec | |
Derek Smith | 5828fd1a38 | |
Derek Smith | 1973ee54f8 | |
Derek Smith | 17e9398588 | |
Derek Smith | 0edb94cdea | |
Derek Smith | 355adb13ab | |
Derek Smith | 17d7e9c75a | |
Derek Smith | 575deff1d2 | |
Derek Smith | 6fef36096e | |
Derek Smith | 0c6e00deb2 | |
Derek Smith | 8b6db37380 | |
Derek Smith | 5dd4de442d | |
Derek Smith | 7abf79e0a7 | |
Derek Smith | 56916a7d33 | |
Derek Smith | c4183a0b63 | |
Derek Smith | 4fde7a8a70 | |
Derek Smith | 7007891e1d | |
Derek Smith | a33a0bc459 | |
Derek Smith | 6f83bf5195 | |
Derek Smith | aaab6f3515 | |
Derek Smith | 6f1f2df6dd | |
Derek Smith | f3ec53521d | |
Derek Smith | 042cdb5b7e | |
Derek Smith | 882b5c6bf0 | |
Derek Smith | 60efc0a6fc | |
Derek Smith | 50d65ebe7c | |
Derek Smith | 9d7d08b0ed | |
Derek Smith | 1eff32efed | |
Derek Smith | 3f30fa11e2 | |
Derek Smith | 7512cbfd90 | |
Derek Smith | 3004a167c8 | |
Derek Smith | 57e75a88ec | |
Derek Smith | a2c29b189e | |
Derek Smith | 44c2859a84 | |
Derek Smith | 19997bcf89 | |
Derek Smith | 27e0dc6ccf | |
Derek Smith | f75f8d1bf7 | |
Derek Smith | a273488646 | |
Derek Smith | 559d5f11f4 | |
Derek Smith | 3f15800635 | |
Derek Smith | a44832c9ba | |
Derek Smith | 7e76d5ca43 | |
Derek Smith | 643fc70873 | |
Derek Smith | 65dfcf7aae | |
Derek Smith | a2050f4796 | |
Derek Smith | e5bdd0d6a5 | |
Derek Smith | 972a2df31e | |
Derek Smith | e78656d191 | |
Derek Smith | ab95b46745 | |
Derek Smith | 636d4c873d | |
Derek Smith | 75086610ca | |
Derek Smith | c02ed8e6f2 | |
Derek Smith | 9ffeb57981 | |
Derek Smith | 9182c7eb0a | |
Derek Smith | 8fa432672a | |
Derek Smith | f952b05de3 | |
Derek Smith | c02bb690e8 | |
Derek Smith | 855a91beb7 | |
Derek Smith | 8780f9e908 | |
Derek Smith | f8d6d2acfc | |
Derek Smith | 0c253e9a49 | |
Derek Smith | 8d28a68bd3 | |
Derek Smith | ffd4b607c2 | |
Derek Smith | eaa4f0abb1 | |
Derek Smith | 334b138770 | |
Derek Smith | 68f487a5dc | |
Derek Smith | 88291a2ee0 | |
Derek Smith | 132e32b806 | |
Derek Smith | 7819cbe564 | |
Derek Smith | 22ecde022f | |
Derek Smith | 9d7c9a51f6 | |
Derek Smith | 08235de798 | |
Derek Smith | 5369016265 | |
Derek Smith | 0ca1fdbea9 | |
Derek Smith | d88814e6e4 | |
Derek Smith | ddcc119030 | |
Derek Smith | 919acbf172 | |
Derek Smith | f41601ad04 | |
Derek Smith | d49f3f58b6 | |
Derek Smith | 62c7fd0504 | |
Derek Smith | e602f8be90 | |
Derek Smith | d8903eb5bc | |
Derek Smith | 0b38d6d635 | |
Derek Smith | beb1d7b5a4 | |
Derek Smith | 5d15d5f690 | |
Derek Smith | 6c4d262c43 | |
Derek Smith | d571680ff1 | |
Derek Smith | 6e6c55e801 | |
Derek Smith | e762d05828 | |
Derek Smith | bccef77d4e | |
Derek Smith | 0d8ece8362 | |
Derek Smith | d68d673c69 | |
Derek Smith | 4f466381f6 | |
Derek Smith | 6e2514b12f | |
Derek Smith | f615e14988 | |
Derek Smith | 086577f32a | |
Derek Smith | 879ec0c34f | |
Derek Smith | 8b65f22797 | |
Derek Smith | 7604c95aa0 | |
Derek Smith | 754ebc81a4 | |
Derek Smith | 8ec3af6703 | |
Derek Smith | 42a22f4942 | |
Derek Smith | d6eb1f3031 | |
Derek Smith | 200e6afc76 | |
Derek Smith | 8321345030 | |
Derek Smith | b665857921 | |
Derek Smith | 925d17d22c | |
Derek Smith | be69d5774d | |
Derek Smith | e4a19010c6 | |
Derek Smith | 9c0e29f772 | |
Derek Smith | 54be0f6b3c | |
Derek Smith | bf5ff6903e | |
Derek Smith | a3b29e129a | |
Derek Smith | 6a0255a326 | |
Derek Smith | a1c50b083d | |
Derek Smith | 0f65419d55 | |
Derek Smith | cae11df6a5 | |
Derek Smith | 18bff0d2e9 | |
Derek Smith | 425bfd8069 | |
Derek Smith | b82813231c | |
Derek Smith | f2b02e474d | |
Derek Smith | 5a54400831 | |
Derek Smith | 69ab9d0a42 | |
Derek Smith | 35afd1bbd4 | |
Derek Smith | a44ce22e00 | |
Derek Smith | 33a855e801 | |
Derek Smith | 69161e726e | |
Derek Smith | 622741ce06 | |
Derek Smith | a4301c0a1c | |
Derek Smith | d786227a5f | |
Derek Smith | 7d839e9724 | |
Derek Smith | 441eff3f26 | |
Derek Smith | 1b7e871758 | |
Derek Smith | fbf16a38a0 | |
Derek Smith | a8dccf6b5c | |
Derek Smith | fc441f72f4 | |
Derek Smith | efac5e4f45 | |
Derek Smith | f823ba361e | |
Derek Smith | dc40e732ee | |
Derek Smith | dc269fe29c | |
Derek Smith | d35a882d8b | |
Derek Smith | 3884c24e48 | |
Derek Smith | 2730bda32b | |
Derek Smith | 73eacb9125 | |
Derek Smith | 9723474b7b | |
Derek Smith | a595491ee6 | |
Derek Smith | 46dedcf6b2 | |
Derek Smith | d5c2d67562 | |
Derek Smith | b5c2b0ef81 | |
Derek Smith | f06a3545d2 | |
Derek Smith | 786d34df93 | |
Derek Smith | 5dc7194a62 | |
Derek Smith | 1fdf96bfa2 | |
Derek Smith | 9e7d9d3a90 | |
Derek Smith | ab08923543 | |
Derek Smith | 27a02534b6 | |
Derek Smith | 2992f34092 | |
Derek Smith | f1abfd77af | |
Derek Smith | de6f078774 | |
Derek Smith | 18fb5a1fe0 | |
Derek Smith | 731639bc4b | |
Derek Smith | a3ea78cfe2 | |
Derek Smith | 8aef17fa00 | |
Derek Smith | 03d669750c | |
Derek Smith | 5f83e83fc8 | |
Derek Smith | 086aee9ed4 | |
Derek Smith | 1a586e2399 | |
Derek Smith | 1c2511af21 | |
Derek Smith | e12ead7ede | |
Derek Smith | 1775f28cdb | |
Derek Smith | cde7d287c5 | |
Derek Smith | 16d4339af6 | |
Derek Smith | 672be48b08 | |
Derek Smith | 7e8706f81c | |
Derek Smith | 5da08eab26 | |
Derek Smith | e2bfd5d090 | |
Derek Smith | a6ac567f12 | |
Derek Smith | 34c1edf27e | |
Derek Smith | 180cd1fa8d | |
Derek Smith | afa6c530ff | |
Derek Smith | cc6bdef20d | |
Derek Smith | 514ae6ce24 | |
Derek Smith | d283dfb353 | |
Derek Smith | c08260a2d4 | |
Derek Smith | efeb0261bc | |
Derek Smith | b2abf3fdf4 | |
Derek Smith | 870d0b685c | |
Derek Smith | 6884154c04 | |
Derek Smith | 8590e82411 | |
Derek Smith | 7a705828b7 | |
Derek Smith | 867771c908 | |
Derek Smith | e205d1cc7a | |
Derek Smith | 7ba91f8bcb | |
Derek Smith | 628df90d32 | |
Derek Smith | bd3acd8ef4 | |
Derek Smith | c3980df073 | |
Derek Smith | 9c518e47e2 | |
Derek Smith | f5deac4874 | |
Derek Smith | 493946c1f5 | |
Derek Smith | 98866559bd | |
Derek Smith | 03d7411a05 | |
Derek Smith | eb67ec10a7 | |
Derek Smith | 2f16d2de0a | |
Derek Smith | 0510a36522 | |
Derek Smith | 49b435c113 | |
Derek Smith | 299446b7e8 | |
Derek Smith | a19bbec9c1 | |
Derek Smith | ecd6b3a77d | |
Derek Smith | 9b8a2403eb | |
Derek Smith | 1de414dfc9 | |
Derek Smith | 7ce1f0adbe | |
Derek Smith | 8caae387b6 | |
Derek Smith | 610946e357 | |
Derek Smith | ddb0fbef57 | |
Derek Smith | 4a84fd24e5 | |
Derek Smith | 16f88d964d | |
Derek Smith | b6e0e5ac4d | |
Derek Smith | c3bab8c844 | |
Derek Smith | 48a26c0db0 | |
Derek Smith | 144b0209eb | |
Derek Smith | 864926ffd0 | |
Derek Smith | a875137b05 | |
Derek Smith | faca4f41ce | |
Derek Smith | ce66768038 | |
Derek Smith | 4124efe2ea | |
Derek Smith | c832d1d050 | |
Derek Smith | bd3918ec93 | |
Derek Smith | 2c0645c951 | |
Derek Smith | d91ba02e7f | |
Derek Smith | bd129ed073 | |
Derek Smith | 9d13ec3991 | |
Derek Smith | dbb48d7f99 | |
Derek Smith | 12d7d33053 | |
Derek Smith | 902121a72d | |
Derek Smith | 9a419ccc6e | |
Derek Smith | 59ca96cb6c | |
Derek Smith | 42aa3742fc | |
Derek Smith | 104e547a57 | |
Derek Smith | 7a08b7cdcf | |
Derek Smith | fac6ab0ecf |
|
@ -1 +1 @@
|
|||
./reset.sh
|
||||
archive
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "deployment/project"]
|
||||
path = deployment/project
|
||||
url = https://git.sovereign-stack.org/ss/project
|
|
@ -10,13 +10,15 @@
|
|||
"shellcheck.enableQuickFix": true,
|
||||
"shellcheck.run": "onType",
|
||||
"shellcheck.executablePath": "shellcheck",
|
||||
"shellcheck.customArgs": [],
|
||||
"shellcheck.ignorePatterns": {},
|
||||
"shellcheck.exclude": [
|
||||
// "SC1090",
|
||||
// "SC1091",
|
||||
"SC2029"
|
||||
"shellcheck.customArgs": [
|
||||
"-x"
|
||||
],
|
||||
"shellcheck.ignorePatterns": {},
|
||||
// "shellcheck.exclude": [
|
||||
// "SC1090",
|
||||
// "SC1091",
|
||||
// "SC2029"
|
||||
// ],
|
||||
"terminal.integrated.fontFamily": "monospace",
|
||||
"workbench.colorCustomizations": {
|
||||
"activityBar.background": "#1900a565",
|
||||
|
@ -28,8 +30,8 @@
|
|||
"titleBar.inactiveBackground": "#02972799",
|
||||
"titleBar.activeForeground": "#e7e7e7",
|
||||
"titleBar.inactiveForeground": "#e7e7e799",
|
||||
"statusBar.background": "#ff9900",
|
||||
"statusBarItem.hoverBackground": "#ff9900",
|
||||
"statusBar.background": "#d68100",
|
||||
"statusBarItem.hoverBackground": "#c77700",
|
||||
"statusBar.foreground": "#000000"
|
||||
}
|
||||
}
|
1
NOTES
1
NOTES
|
@ -1 +0,0 @@
|
|||
Trezor MUST Use the "Crypto" firmware with shitcoin support in order for 2FA (WEBAUTHN) to work. Bummer.
|
14
README.md
14
README.md
|
@ -1,15 +1,3 @@
|
|||
# Documentation
|
||||
|
||||
The Sovereign Stack scripts in this repository are meant to be cloned to and executed from your management machine.
|
||||
|
||||
You can update Sovereign Stack scripts on your management machine by running `git pull --all --tags`. Generally, you want to use ONLY signed git tags for your deployments. Use `git checkout v0.1.0` for example to switch to a specific version of Sovereign Stack. The scripts check to ensure that the code you're running on your management machine is GREATER THAN OR EQUAL TO the version of your deployments (TODO). The scripts work to bring your existing deployments into line with the current Sovereign Stack version.
|
||||
|
||||
Once your managent machine checkedout a specific version of Sovereign stack, you will want to run the various scripts against your remotes. But before you can do that, you need to bring a bare-metal Ubuntu 22.04 cluster host under management (i.e., add it as a remote). Generally speaking you will run `ss-cluster` to bring a new bare-metal host under management of your management machine. This can be run AFTER you have verified SSH access to the bare-metal hosts. The device SHOULD also have a DHCP Reservation and DNS records in place.
|
||||
|
||||
After you have taken a machine under management, you can run `ss-deploy` it. All Sovereign Stack scripts execute against your current lxc remote. (Run `lxc remote list` to see your remotes). This will deploy Sovereign Stack software to your active remote in accordance with the various cluster, project, and site definitions. These files are stubbed out for the user automatically and documetnation guides the user through the process.
|
||||
|
||||
It is the responsiblity of the management machine (i.e,. system owner) to run the scripts on a regular and ongoing basis to ensure active deployments stay up-to-date with the Sovereign Stack master branch.
|
||||
|
||||
By default (i.e., without any command line modifiers), Sovereign Stack scripts will back up active deployments resulting in minimal downtime. (zero downtime for Ghost, minimal for Nextcloud/Gitea, BTCPAY Server).
|
||||
|
||||
All other documentation for this project can be found at the [sovereign-stack.org](https://www.sovereign-stack.org).
|
||||
All documentation for this project can be found at [sovereign-stack.org](https://www.sovereign-stack.org). To get started with this code, check out [this post](https://www.sovereign-stack.org/get/).
|
|
@ -1,23 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
|
||||
check_dependencies () {
|
||||
for cmd in "$@"; do
|
||||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||
echo "This script requires \"${cmd}\" to be installed. Please run 'install.sh'."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Check system's dependencies
|
||||
check_dependencies wait-for-it dig rsync sshfs lxc
|
||||
|
||||
# let's check to ensure the management machine is on the Baseline ubuntu 21.04
|
||||
if ! lsb_release -d | grep -q "Ubuntu 22.04"; then
|
||||
echo "ERROR: Your machine is not running the Ubuntu 22.04 LTS baseline OS on your management machine."
|
||||
exit 1
|
||||
fi
|
225
cluster.sh
225
cluster.sh
|
@ -1,225 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# This script is meant to be executed on the management machine.
|
||||
# it reaches out to an SSH endpoint and provisions that machine
|
||||
# to use LXD.
|
||||
|
||||
DATA_PLANE_MACVLAN_INTERFACE=
|
||||
DISK_TO_USE=
|
||||
|
||||
# override the cluster name.
|
||||
CLUSTER_NAME="${1:-}"
|
||||
if [ -z "$CLUSTER_NAME" ]; then
|
||||
echo "ERROR: The cluster name was not provided."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#shellcheck disable=SC1091
|
||||
source ./defaults.sh
|
||||
|
||||
export CLUSTER_PATH="$CLUSTERS_DIR/$CLUSTER_NAME"
|
||||
CLUSTER_DEFINITION="$CLUSTER_PATH/cluster_definition"
|
||||
export CLUSTER_DEFINITION="$CLUSTER_DEFINITION"
|
||||
|
||||
mkdir -p "$CLUSTER_PATH"
|
||||
if [ ! -f "$CLUSTER_DEFINITION" ]; then
|
||||
# stub out a cluster_definition.
|
||||
cat >"$CLUSTER_DEFINITION" <<EOL
|
||||
#!/bin/bash
|
||||
|
||||
# see https://www.sovereign-stack.org/cluster_definition for more info!
|
||||
|
||||
export LXD_CLUSTER_PASSWORD="$(gpg --gen-random --armor 1 14)"
|
||||
export SOVEREIGN_STACK_MAC_ADDRESS="CHANGE_ME_REQUIRED"
|
||||
export PROJECT_NAME="regtest"
|
||||
#export REGISTRY_URL="https://index.docker.io/v1/"
|
||||
|
||||
EOL
|
||||
|
||||
chmod 0744 "$CLUSTER_DEFINITION"
|
||||
echo "We stubbed out a '$CLUSTER_DEFINITION' file for you."
|
||||
echo "Use this file to customize your cluster deployment;"
|
||||
echo "Check out 'https://www.sovereign-stack.org/cluster-definition' for an example."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$CLUSTER_DEFINITION"
|
||||
|
||||
if ! lxc remote list | grep -q "$CLUSTER_NAME"; then
|
||||
FQDN="${2:-}"
|
||||
shift
|
||||
|
||||
if [ -z "$FQDN" ]; then
|
||||
echo "ERROR: The Fully Qualified Domain Name of the new cluster member was not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# let's check to ensure we have SSH access to the specified host.
|
||||
if ! wait-for-it -t 5 "$FQDN:22"; then
|
||||
echo "ERROR: We can't get an SSH connection to '$FQDN:22'. Ensure you have the host set up correctly."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# grab any modifications from the command line.
|
||||
for i in "$@"; do
|
||||
case $i in
|
||||
--data-plane-interface=*)
|
||||
DATA_PLANE_MACVLAN_INTERFACE="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
--disk=*)
|
||||
DISK_TO_USE="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$DATA_PLANE_MACVLAN_INTERFACE" ]; then
|
||||
echo "INFO: It looks like you didn't provide input on the command line for the data plane macvlan interface."
|
||||
echo " We need to know which interface that is! Enter it here now."
|
||||
echo ""
|
||||
|
||||
ssh "ubuntu@$FQDN" ip link
|
||||
|
||||
echo "Please enter the network interface that's dedicated to the Sovereign Stack data plane: "
|
||||
read -r DATA_PLANE_MACVLAN_INTERFACE
|
||||
|
||||
fi
|
||||
|
||||
if [ -z "$DISK_TO_USE" ]; then
|
||||
echo "INFO: It looks like the DISK_TO_USE has not been set. Enter it now."
|
||||
echo ""
|
||||
|
||||
ssh "ubuntu@$FQDN" lsblk
|
||||
|
||||
echo "Please enter the disk or partition that Sovereign Stack will use to store data (default: loop): "
|
||||
read -r DISK_TO_USE
|
||||
else
|
||||
DISK_TO_USE=loop
|
||||
fi
|
||||
|
||||
else
|
||||
echo "ERROR: the cluster already exists! You need to go delete your lxd remote if you want to re-create your cluster."
|
||||
echo " It's may also be helpful to reset/rename your cluster path."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# if the disk is loop-based, then we assume the / path exists.
|
||||
if [ "$DISK_TO_USE" != loop ]; then
|
||||
# ensure we actually have that disk/partition on the system.
|
||||
if ssh "ubuntu@$FQDN" lsblk | grep -q "$DISK_TO_USE"; then
|
||||
echo "ERROR: We could not the disk you specified. Please run this command again and supply a different disk."
|
||||
echo "NOTE: You can always specify on the command line by adding the '--disk=/dev/sdd', for example."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# The MGMT Plane IP is the IP address that the LXD API binds to, which happens
|
||||
# to be the same as whichever SSH connection you're coming in on.
|
||||
MGMT_PLANE_IP="$(ssh ubuntu@"$FQDN" env | grep SSH_CONNECTION | cut -d " " -f 3)"
|
||||
IP_OF_MGMT_MACHINE="$(ssh ubuntu@"$FQDN" env | grep SSH_CLIENT | cut -d " " -f 1 )"
|
||||
IP_OF_MGMT_MACHINE="${IP_OF_MGMT_MACHINE#*=}"
|
||||
IP_OF_MGMT_MACHINE="$(echo "$IP_OF_MGMT_MACHINE" | cut -d: -f1)"
|
||||
|
||||
# error out if the cluster password is unset.
|
||||
if [ -z "$LXD_CLUSTER_PASSWORD" ]; then
|
||||
echo "ERROR: LXD_CLUSTER_PASSWORD must be set in your cluster_definition."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v lxc >/dev/null 2>&1; then
|
||||
if lxc profile list --format csv | grep -q sovereign-stack; then
|
||||
lxc profile delete sovereign-stack
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
if lxc network list --format csv | grep -q lxdbrSS; then
|
||||
lxc network delete lxdbrSS
|
||||
sleep 1
|
||||
fi
|
||||
fi
|
||||
|
||||
ssh -t "ubuntu@$FQDN" "
|
||||
set -e
|
||||
|
||||
# install ufw and allow SSH.
|
||||
sudo apt update
|
||||
sudo apt upgrade -y
|
||||
sudo apt install ufw htop dnsutils nano -y
|
||||
sudo ufw allow ssh
|
||||
sudo ufw allow 8443/tcp comment 'allow LXD management'
|
||||
|
||||
# enable the host firewall
|
||||
if sudo ufw status | grep -q 'Status: inactive'; then
|
||||
sudo ufw enable
|
||||
fi
|
||||
|
||||
# install lxd as a snap if it's not installed.
|
||||
if ! snap list | grep -q lxd; then
|
||||
sudo snap install lxd --candidate
|
||||
sleep 4
|
||||
fi
|
||||
"
|
||||
|
||||
# if the DATA_PLANE_MACVLAN_INTERFACE is not specified, then we 'll
|
||||
# just attach VMs to the network interface used for for the default route.
|
||||
if [ -z "$DATA_PLANE_MACVLAN_INTERFACE" ]; then
|
||||
DATA_PLANE_MACVLAN_INTERFACE="$(ssh -t ubuntu@"$FQDN" ip route | grep default | cut -d " " -f 5)"
|
||||
fi
|
||||
|
||||
# stub out the lxd init file for the remote SSH endpoint.
|
||||
CLUSTER_MASTER_LXD_INIT="$CLUSTER_PATH/lxdinit_profile.yml"
|
||||
cat >"$CLUSTER_MASTER_LXD_INIT" <<EOF
|
||||
config:
|
||||
core.https_address: ${MGMT_PLANE_IP}:8443
|
||||
core.trust_password: ${LXD_CLUSTER_PASSWORD}
|
||||
images.auto_update_interval: 15
|
||||
|
||||
networks:
|
||||
- name: lxdbrSS
|
||||
type: bridge
|
||||
config:
|
||||
ipv4.address: 10.139.144.1/24
|
||||
ipv4.nat: "false"
|
||||
ipv4.dhcp: "false"
|
||||
ipv6.address: "none"
|
||||
dns.mode: "none"
|
||||
#managed: true
|
||||
description: ss-config,${DATA_PLANE_MACVLAN_INTERFACE:-},${DISK_TO_USE:-}
|
||||
# lxdbrSS is an isolated inter-vm network segment with no outbount Internet access.
|
||||
|
||||
cluster:
|
||||
server_name: ${CLUSTER_NAME}
|
||||
enabled: true
|
||||
member_config: []
|
||||
cluster_address: ""
|
||||
cluster_certificate: ""
|
||||
server_address: ""
|
||||
cluster_password: ""
|
||||
cluster_certificate_path: ""
|
||||
cluster_token: ""
|
||||
EOF
|
||||
|
||||
# configure the LXD Daemon with our preseed.
|
||||
cat "$CLUSTER_MASTER_LXD_INIT" | ssh "ubuntu@$FQDN" lxd init --preseed
|
||||
|
||||
# ensure the lxd service is available over the network, then add a lxc remote, then switch the active remote to it.
|
||||
if wait-for-it -t 20 "$FQDN:8443"; then
|
||||
# now create a remote on your local LXC client and switch to it.
|
||||
# the software will now target the new cluster.
|
||||
lxc remote add "$CLUSTER_NAME" "$FQDN" --password="$LXD_CLUSTER_PASSWORD" --protocol=lxd --auth-type=tls --accept-certificate
|
||||
lxc remote switch "$CLUSTER_NAME"
|
||||
|
||||
echo "INFO: You have create a new cluster named '$CLUSTER_NAME'. Great! We switched your lxd remote to it."
|
||||
else
|
||||
echo "ERROR: Could not detect the LXD endpoint. Something went wrong."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "HINT: Now you can consider running 'ss-deploy'."
|
117
defaults.sh
117
defaults.sh
|
@ -1,117 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
export WWW_SERVER_MAC_ADDRESS=
|
||||
export DEPLOY_WWW_SERVER=false
|
||||
export DEPLOY_BTCPAY_SERVER=false
|
||||
export DEPLOY_GHOST=false
|
||||
export DEPLOY_NOSTR_RELAY=false
|
||||
export DEPLOY_ONION_SITE=false
|
||||
export DEPLOY_NEXTCLOUD=false
|
||||
export DEPLOY_GITEA=false
|
||||
|
||||
export WWW_HOSTNAME="www"
|
||||
export BTCPAY_HOSTNAME="btcpayserver"
|
||||
export BTCPAY_HOSTNAME_IN_CERT="btcpay"
|
||||
export NEXTCLOUD_HOSTNAME="nextcloud"
|
||||
export GITEA_HOSTNAME="git"
|
||||
export NOSTR_HOSTNAME="relay"
|
||||
|
||||
export SITE_LANGUAGE_CODES="en"
|
||||
export LANGUAGE_CODE="en"
|
||||
export NOSTR_ACCOUNT_PUBKEY=
|
||||
|
||||
# this is where the html is sourced from.
|
||||
export SITE_HTML_PATH=
|
||||
export BTCPAY_ADDITIONAL_HOSTNAMES=
|
||||
|
||||
export GHOST_MYSQL_PASSWORD=
|
||||
export GHOST_MYSQL_ROOT_PASSWORD=
|
||||
export NEXTCLOUD_MYSQL_PASSWORD=
|
||||
export GITEA_MYSQL_PASSWORD=
|
||||
export NEXTCLOUD_MYSQL_ROOT_PASSWORD=
|
||||
export GITEA_MYSQL_ROOT_PASSWORD=
|
||||
export DUPLICITY_BACKUP_PASSPHRASE=
|
||||
#opt-add-fireflyiii;opt-add-zammad
|
||||
|
||||
|
||||
export SSH_HOME="$HOME/.ssh"
|
||||
export PASS_HOME="$HOME/.password-store"
|
||||
export VM_NAME="sovereign-stack-base"
|
||||
|
||||
export BTCPAY_SERVER_CPU_COUNT="4"
|
||||
export BTCPAY_SERVER_MEMORY_MB="4096"
|
||||
export WWW_SERVER_CPU_COUNT="4"
|
||||
export WWW_SERVER_MEMORY_MB="4096"
|
||||
|
||||
export DOCKER_IMAGE_CACHE_FQDN="registry-1.docker.io"
|
||||
|
||||
export NEXTCLOUD_SPACE_GB=10
|
||||
|
||||
# first of all, if there are uncommited changes, we quit. You better stash or commit!
|
||||
# Remote VPS instances are tagged with your current git HEAD so we know which code revision
|
||||
# used when provisioning the VPS.
|
||||
#LATEST_GIT_COMMIT="$(cat ./.git/refs/heads/master)"
|
||||
#export LATEST_GIT_COMMIT="$LATEST_GIT_COMMIT"
|
||||
|
||||
# check if there are any uncommited changes. It's dangerous to instantiate VMs using
|
||||
# code that hasn't been committed.
|
||||
# if git update-index --refresh | grep -q "needs update"; then
|
||||
# echo "ERROR: You have uncommited changes! Better stash your work with 'git stash'."
|
||||
# exit 1
|
||||
# fi
|
||||
|
||||
BTC_CHAIN=regtest
|
||||
|
||||
export BTC_CHAIN="$BTC_CHAIN"
|
||||
|
||||
DEFAULT_DB_IMAGE="mariadb:10.9.3-jammy"
|
||||
|
||||
|
||||
# run the docker stack.
|
||||
export GHOST_IMAGE="ghost:5.26.2"
|
||||
|
||||
# TODO switch to mysql. May require intricate export work for existing sites.
|
||||
# THIS MUST BE COMPLETED BEFORE v1 RELEASE
|
||||
#https://forum.ghost.org/t/how-to-migrate-from-mariadb-10-to-mysql-8/29575
|
||||
export GHOST_DB_IMAGE="$DEFAULT_DB_IMAGE"
|
||||
|
||||
|
||||
export NGINX_IMAGE="nginx:1.23.2"
|
||||
|
||||
# version of backup is 24.0.3
|
||||
export NEXTCLOUD_IMAGE="nextcloud:25.0.1"
|
||||
export NEXTCLOUD_DB_IMAGE="$DEFAULT_DB_IMAGE"
|
||||
|
||||
# TODO PIN the gitea version number.
|
||||
export GITEA_IMAGE="gitea/gitea:latest"
|
||||
export GITEA_DB_IMAGE="$DEFAULT_DB_IMAGE"
|
||||
|
||||
export NOSTR_RELAY_IMAGE="scsibug/nostr-rs-relay"
|
||||
|
||||
export SOVEREIGN_STACK_MAC_ADDRESS=
|
||||
export WWW_SERVER_MAC_ADDRESS=
|
||||
export BTCPAYSERVER_MAC_ADDRESS=
|
||||
|
||||
export CLUSTERS_DIR="$HOME/ss-clusters"
|
||||
export PROJECTS_DIR="$HOME/ss-projects"
|
||||
export SITES_PATH="$HOME/ss-sites"
|
||||
|
||||
|
||||
# The base VM image.
|
||||
export BASE_LXC_IMAGE="ubuntu/22.04/cloud"
|
||||
|
||||
# Deploy a registry cache on your management machine.
|
||||
export DEPLOY_MGMT_REGISTRY=false
|
||||
export OTHER_SITES_LIST=
|
||||
export BTCPAY_ALT_NAMES=
|
||||
|
||||
export REMOTE_HOME="/home/ubuntu"
|
||||
|
||||
export BTCPAY_SERVER_APPPATH="$REMOTE_HOME/btcpayserver-docker"
|
||||
export REMOTE_CERT_BASE_DIR="$REMOTE_HOME/.certs"
|
||||
|
||||
# this space is for OS, docker images, etc. DOES NOT INCLUDE USER DATA.
|
||||
export ROOT_DISK_SIZE_GB=20
|
||||
export REGISTRY_URL="https://index.docker.io/v1/"
|
413
deploy.sh
413
deploy.sh
|
@ -1,413 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
RESPOSITORY_PATH="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
export RESPOSITORY_PATH="$RESPOSITORY_PATH"
|
||||
|
||||
./check_dependencies.sh
|
||||
|
||||
DOMAIN_NAME=
|
||||
RUN_CERT_RENEWAL=true
|
||||
SKIP_WWW=false
|
||||
RESTORE_WWW=false
|
||||
BACKUP_CERTS=true
|
||||
BACKUP_APPS=true
|
||||
BACKUP_BTCPAY=true
|
||||
BACKUP_BTCPAY_ARCHIVE_PATH=
|
||||
RESTORE_BTCPAY=false
|
||||
SKIP_BTCPAY=false
|
||||
UPDATE_BTCPAY=false
|
||||
RECONFIGURE_BTCPAY_SERVER=false
|
||||
CLUSTER_NAME="$(lxc remote get-default)"
|
||||
STOP_SERVICES=false
|
||||
USER_SAYS_YES=false
|
||||
RESTART_FRONT_END=false
|
||||
|
||||
# grab any modifications from the command line.
|
||||
for i in "$@"; do
|
||||
case $i in
|
||||
--restore-www)
|
||||
RESTORE_WWW=true
|
||||
BACKUP_APPS=false
|
||||
RUN_CERT_RENEWAL=false
|
||||
shift
|
||||
;;
|
||||
--restore-btcpay)
|
||||
RESTORE_BTCPAY=true
|
||||
BACKUP_BTCPAY=false
|
||||
RUN_CERT_RENEWAL=false
|
||||
shift
|
||||
;;
|
||||
--backup-certs)
|
||||
BACKUP_CERTS=true
|
||||
shift
|
||||
;;
|
||||
--no-backup-www)
|
||||
BACKUP_CERTS=false
|
||||
BACKUP_APPS=false
|
||||
shift
|
||||
;;
|
||||
--stop)
|
||||
STOP_SERVICES=true
|
||||
shift
|
||||
;;
|
||||
--restart-front-end)
|
||||
RESTART_FRONT_END=true
|
||||
shift
|
||||
;;
|
||||
--domain=*)
|
||||
DOMAIN_NAME="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
--backup-archive-path=*)
|
||||
BACKUP_BTCPAY_ARCHIVE_PATH="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
--update-btcpay)
|
||||
UPDATE_BTCPAY=true
|
||||
shift
|
||||
;;
|
||||
--skip-www)
|
||||
SKIP_WWW=true
|
||||
shift
|
||||
;;
|
||||
--skip-btcpay)
|
||||
SKIP_BTCPAY=true
|
||||
shift
|
||||
;;
|
||||
--backup-ghost)
|
||||
BACKUP_APPS=true
|
||||
shift
|
||||
;;
|
||||
--no-cert-renew)
|
||||
RUN_CERT_RENEWAL=false
|
||||
shift
|
||||
;;
|
||||
--reconfigure-btcpay)
|
||||
RECONFIGURE_BTCPAY_SERVER=true
|
||||
shift
|
||||
;;
|
||||
-y)
|
||||
USER_SAYS_YES=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unexpected option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$RESTORE_BTCPAY" = true ] && [ -z "$BACKUP_BTCPAY_ARCHIVE_PATH" ]; then
|
||||
echo "ERROR: BACKUP_BTCPAY_ARCHIVE_PATH was not set event when the RESTORE_BTCPAY = true. "
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# set up our default paths.
|
||||
source ./defaults.sh
|
||||
|
||||
export DOMAIN_NAME="$DOMAIN_NAME"
|
||||
export REGISTRY_DOCKER_IMAGE="registry:2"
|
||||
export RESTORE_WWW="$RESTORE_WWW"
|
||||
export STOP_SERVICES="$STOP_SERVICES"
|
||||
export BACKUP_CERTS="$BACKUP_CERTS"
|
||||
export BACKUP_APPS="$BACKUP_APPS"
|
||||
export RESTORE_BTCPAY="$RESTORE_BTCPAY"
|
||||
export BACKUP_BTCPAY="$BACKUP_BTCPAY"
|
||||
export RUN_CERT_RENEWAL="$RUN_CERT_RENEWAL"
|
||||
export CLUSTER_NAME="$CLUSTER_NAME"
|
||||
export CLUSTER_PATH="$CLUSTERS_DIR/$CLUSTER_NAME"
|
||||
export USER_SAYS_YES="$USER_SAYS_YES"
|
||||
export BACKUP_BTCPAY_ARCHIVE_PATH="$BACKUP_BTCPAY_ARCHIVE_PATH"
|
||||
export RESTART_FRONT_END="$RESTART_FRONT_END"
|
||||
|
||||
|
||||
# ensure our cluster path is created.
|
||||
mkdir -p "$CLUSTER_PATH"
|
||||
|
||||
# if an authorized_keys file does not exist, we'll stub one out with the current user.
|
||||
# add additional id_rsa.pub entries manually for more administrative logins.
|
||||
if [ ! -f "$CLUSTER_PATH/authorized_keys" ]; then
|
||||
cat "$SSH_HOME/id_rsa.pub" >> "$CLUSTER_PATH/authorized_keys"
|
||||
echo "INFO: Sovereign Stack just stubbed out '$CLUSTER_PATH/authorized_keys'. Go update it."
|
||||
echo " Add ssh pubkeys for your various management machines, if any."
|
||||
echo " By default we added your main ssh pubkey: '$SSH_HOME/id_rsa.pub'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
CLUSTER_DEFINITION="$CLUSTER_PATH/cluster_definition"
|
||||
export CLUSTER_DEFINITION="$CLUSTER_DEFINITION"
|
||||
|
||||
#########################################
|
||||
if [ ! -f "$CLUSTER_DEFINITION" ]; then
|
||||
echo "ERROR: The cluster definition could not be found. You may need to re-run 'ss-cluster create'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$CLUSTER_DEFINITION"
|
||||
|
||||
# this is our password generation mechanism. Relying on GPG for secure password generation
|
||||
function new_pass {
|
||||
gpg --gen-random --armor 1 25
|
||||
}
|
||||
|
||||
function instantiate_vms {
|
||||
|
||||
export BTC_CHAIN="$BTC_CHAIN"
|
||||
export UPDATE_BTCPAY="$UPDATE_BTCPAY"
|
||||
export RECONFIGURE_BTCPAY_SERVER="$RECONFIGURE_BTCPAY_SERVER"
|
||||
|
||||
# iterate over all our server endpoints and provision them if needed.
|
||||
# www
|
||||
VPS_HOSTNAME=
|
||||
|
||||
for VIRTUAL_MACHINE in www btcpayserver; do
|
||||
export VIRTUAL_MACHINE="$VIRTUAL_MACHINE"
|
||||
FQDN=
|
||||
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
|
||||
source "$SITE_PATH/site_definition"
|
||||
source "$RESPOSITORY_PATH/domain_env.sh"
|
||||
|
||||
# VALIDATE THE INPUT from the ENVFILE
|
||||
if [ -z "$DOMAIN_NAME" ]; then
|
||||
echo "ERROR: DOMAIN_NAME not specified. Use the --domain-name= option."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# first let's get the DISK_TO_USE and DATA_PLANE_MACVLAN_INTERFACE from the ss-config
|
||||
# which is set up during LXD cluster creation ss-cluster.
|
||||
LXD_SS_CONFIG_LINE=
|
||||
if lxc network list --format csv | grep lxdbrSS | grep -q ss-config; then
|
||||
LXD_SS_CONFIG_LINE="$(lxc network list --format csv | grep lxdbrSS | grep ss-config)"
|
||||
fi
|
||||
|
||||
if [ -z "$LXD_SS_CONFIG_LINE" ]; then
|
||||
echo "ERROR: the MACVLAN interface has not been specified. You may need to run ss-cluster again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CONFIG_ITEMS="$(echo "$LXD_SS_CONFIG_LINE" | awk -F'"' '{print $2}')"
|
||||
DATA_PLANE_MACVLAN_INTERFACE="$(echo "$CONFIG_ITEMS" | cut -d ',' -f2)"
|
||||
DISK_TO_USE="$(echo "$CONFIG_ITEMS" | cut -d ',' -f3)"
|
||||
|
||||
export DATA_PLANE_MACVLAN_INTERFACE="$DATA_PLANE_MACVLAN_INTERFACE"
|
||||
export DISK_TO_USE="$DISK_TO_USE"
|
||||
|
||||
./deployment/create_lxc_base.sh
|
||||
|
||||
export MAC_ADDRESS_TO_PROVISION=
|
||||
export VPS_HOSTNAME="$VPS_HOSTNAME"
|
||||
export FQDN="$VPS_HOSTNAME.$DOMAIN_NAME"
|
||||
|
||||
# ensure the admin has set the MAC address for the base image.
|
||||
if [ -z "$SOVEREIGN_STACK_MAC_ADDRESS" ]; then
|
||||
echo "ERROR: SOVEREIGN_STACK_MAC_ADDRESS is undefined. Check your project definition."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DDNS_HOST=
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" = www ]; then
|
||||
if [ "$SKIP_WWW" = true ]; then
|
||||
echo "INFO: Skipping WWW due to command line argument."
|
||||
continue
|
||||
fi
|
||||
|
||||
VPS_HOSTNAME="$WWW_HOSTNAME"
|
||||
MAC_ADDRESS_TO_PROVISION="$WWW_SERVER_MAC_ADDRESS"
|
||||
DDNS_HOST="$WWW_HOSTNAME"
|
||||
ROOT_DISK_SIZE_GB="$((ROOT_DISK_SIZE_GB + NEXTCLOUD_SPACE_GB))"
|
||||
elif [ "$VIRTUAL_MACHINE" = btcpayserver ] || [ "$SKIP_BTCPAY" = true ]; then
|
||||
DDNS_HOST="$BTCPAY_HOSTNAME"
|
||||
VPS_HOSTNAME="$BTCPAY_HOSTNAME"
|
||||
MAC_ADDRESS_TO_PROVISION="$BTCPAYSERVER_MAC_ADDRESS"
|
||||
if [ "$BTC_CHAIN" = mainnet ]; then
|
||||
ROOT_DISK_SIZE_GB=150
|
||||
elif [ "$BTC_CHAIN" = testnet ]; then
|
||||
ROOT_DISK_SIZE_GB=70
|
||||
fi
|
||||
|
||||
elif [ "$VIRTUAL_MACHINE" = "sovereign-stack" ]; then
|
||||
DDNS_HOST="sovereign-stack-base"
|
||||
ROOT_DISK_SIZE_GB=8
|
||||
else
|
||||
echo "ERROR: VIRTUAL_MACHINE not within allowable bounds."
|
||||
exit
|
||||
fi
|
||||
|
||||
export DDNS_HOST="$DDNS_HOST"
|
||||
export FQDN="$DDNS_HOST.$DOMAIN_NAME"
|
||||
export LXD_VM_NAME="${FQDN//./-}"
|
||||
export VIRTUAL_MACHINE="$VIRTUAL_MACHINE"
|
||||
export REMOTE_CERT_DIR="$REMOTE_CERT_BASE_DIR/$FQDN"
|
||||
export MAC_ADDRESS_TO_PROVISION="$MAC_ADDRESS_TO_PROVISION"
|
||||
./deployment/deploy_vms.sh
|
||||
|
||||
# if the local docker client isn't logged in, do so;
|
||||
# this helps prevent docker pull errors since they throttle.
|
||||
# if [ ! -f "$HOME/.docker/config.json" ]; then
|
||||
# echo "$REGISTRY_PASSWORD" | docker login --username "$REGISTRY_USERNAME" --password-stdin
|
||||
# fi
|
||||
|
||||
# this tells our local docker client to target the remote endpoint via SSH
|
||||
export DOCKER_HOST="ssh://ubuntu@$PRIMARY_WWW_FQDN"
|
||||
|
||||
# enable docker swarm mode so we can support docker stacks.
|
||||
if docker info | grep -q "Swarm: inactive"; then
|
||||
docker swarm init --advertise-addr enp6s0
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
|
||||
function stub_site_definition {
|
||||
mkdir -p "$SITE_PATH" "$PROJECT_PATH/sites"
|
||||
|
||||
# create a symlink from the CLUSTERPATH/sites/DOMAIN_NAME to the ss-sites/domain name
|
||||
if [ ! -d "$PROJECT_PATH/sites/$DOMAIN_NAME" ]; then
|
||||
ln -s "$SITE_PATH" "$PROJECT_PATH/sites/$DOMAIN_NAME"
|
||||
fi
|
||||
|
||||
if [ ! -f "$SITE_PATH/site_definition" ]; then
|
||||
# check to see if the enf file exists. exist if not.
|
||||
SITE_DEFINITION_PATH="$SITE_PATH/site_definition"
|
||||
if [ ! -f "$SITE_DEFINITION_PATH" ]; then
|
||||
|
||||
# stub out a site_definition with new passwords.
|
||||
cat >"$SITE_DEFINITION_PATH" <<EOL
|
||||
#!/bin/bash
|
||||
|
||||
export DOMAIN_NAME="${DOMAIN_NAME}"
|
||||
#export BTCPAY_ALT_NAMES="tip,store,pay,send"
|
||||
export SITE_LANGUAGE_CODES="en"
|
||||
export DUPLICITY_BACKUP_PASSPHRASE="$(new_pass)"
|
||||
export DEPLOY_GHOST=true
|
||||
export DEPLOY_NEXTCLOUD=false
|
||||
export DEPLOY_NOSTR_RELAY=false
|
||||
export NOSTR_ACCOUNT_PUBKEY="NOSTR_IDENTITY_PUBKEY_GOES_HERE"
|
||||
export DEPLOY_GITEA=false
|
||||
#export DEPLOY_ONION_SITE=false
|
||||
export GHOST_MYSQL_PASSWORD="$(new_pass)"
|
||||
export GHOST_MYSQL_ROOT_PASSWORD="$(new_pass)"
|
||||
export NEXTCLOUD_MYSQL_PASSWORD="$(new_pass)"
|
||||
export NEXTCLOUD_MYSQL_ROOT_PASSWORD="$(new_pass)"
|
||||
export GITEA_MYSQL_PASSWORD="$(new_pass)"
|
||||
export GITEA_MYSQL_ROOT_PASSWORD="$(new_pass)"
|
||||
|
||||
EOL
|
||||
|
||||
chmod 0744 "$SITE_DEFINITION_PATH"
|
||||
echo "INFO: we stubbed a new site_definition for you at '$SITE_DEFINITION_PATH'. Go update it yo!"
|
||||
exit 1
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
CURRENT_PROJECT="$(lxc info | grep "project:" | awk '{print $2}')"
|
||||
PROJECT_PATH="$PROJECTS_DIR/$PROJECT_NAME"
|
||||
mkdir -p "$PROJECT_PATH" "$CLUSTER_PATH/projects"
|
||||
export PROJECT_PATH="$PROJECT_PATH"
|
||||
|
||||
# create a symlink from ./clusterpath/projects/project
|
||||
if [ ! -d "$CLUSTER_PATH/projects/$PROJECT_NAME" ]; then
|
||||
ln -s "$PROJECT_PATH" "$CLUSTER_PATH/projects/$PROJECT_NAME"
|
||||
fi
|
||||
|
||||
# check if we need to provision a new lxc project.
|
||||
if [ "$PROJECT_NAME" != "$CURRENT_PROJECT" ]; then
|
||||
if ! lxc project list | grep -q "$PROJECT_NAME"; then
|
||||
echo "INFO: The lxd project specified in the cluster_definition did not exist. We'll create one!"
|
||||
lxc project create "$PROJECT_NAME"
|
||||
fi
|
||||
|
||||
echo "INFO: switch to lxd project '$PROJECT_NAME'."
|
||||
lxc project switch "$PROJECT_NAME"
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# check to see if the enf file exists. exist if not.
|
||||
PROJECT_DEFINITION_PATH="$PROJECT_PATH/project_definition"
|
||||
if [ ! -f "$PROJECT_DEFINITION_PATH" ]; then
|
||||
|
||||
# stub out a project_definition
|
||||
cat >"$PROJECT_DEFINITION_PATH" <<EOL
|
||||
#!/bin/bash
|
||||
|
||||
# see https://www.sovereign-stack.org/project-definition for more info.
|
||||
|
||||
export WWW_SERVER_MAC_ADDRESS="CHANGE_ME_REQUIRED"
|
||||
export BTCPAYSERVER_MAC_ADDRESS="CHANGE_ME_REQUIRED"
|
||||
export BTC_CHAIN="regtest|testnet|mainnet"
|
||||
export PRIMARY_DOMAIN="domain0.tld"
|
||||
export OTHER_SITES_LIST="domain1.tld,domain2.tld,domain3.tld"
|
||||
export BTCPAY_SERVER_CPU_COUNT="4"
|
||||
export BTCPAY_SERVER_MEMORY_MB="4096"
|
||||
export WWW_SERVER_CPU_COUNT="6"
|
||||
export WWW_SERVER_MEMORY_MB="4096"
|
||||
|
||||
EOL
|
||||
|
||||
chmod 0744 "$PROJECT_DEFINITION_PATH"
|
||||
echo "INFO: we stubbed a new project_defition for you at '$PROJECT_DEFINITION_PATH'. Go update it yo!"
|
||||
echo "INFO: Learn more at https://www.sovereign-stack.org/project-definitions/"
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# source project defition.
|
||||
source "$PROJECT_DEFINITION_PATH"
|
||||
|
||||
# the DOMAIN_LIST is a complete list of all our domains. We often iterate over this list.
|
||||
DOMAIN_LIST="${PRIMARY_DOMAIN}"
|
||||
if [ -n "$OTHER_SITES_LIST" ]; then
|
||||
DOMAIN_LIST="${DOMAIN_LIST},${OTHER_SITES_LIST}"
|
||||
fi
|
||||
|
||||
export DOMAIN_LIST="$DOMAIN_LIST"
|
||||
export DOMAIN_COUNT=$(("$(echo "$DOMAIN_LIST" | tr -cd , | wc -c)"+1))
|
||||
|
||||
# let's provision our primary domain first.
|
||||
export DOMAIN_NAME="$PRIMARY_DOMAIN"
|
||||
|
||||
# we deploy the WWW and btcpay server under the PRIMARY_DOMAIN.
|
||||
export DEPLOY_WWW_SERVER=true
|
||||
export DEPLOY_BTCPAY_SERVER=true
|
||||
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
export PRIMARY_WWW_FQDN="$WWW_HOSTNAME.$DOMAIN_NAME"
|
||||
|
||||
stub_site_definition
|
||||
|
||||
# bring the VMs up under the primary domain name.
|
||||
instantiate_vms
|
||||
|
||||
# let's stub out the rest of our site definitions, if any.
|
||||
for DOMAIN_NAME in ${OTHER_SITES_LIST//,/ }; do
|
||||
export DOMAIN_NAME="$DOMAIN_NAME"
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
|
||||
# stub out the site_defition if it's doesn't exist.
|
||||
stub_site_definition
|
||||
done
|
||||
|
||||
# now let's run the www and btcpay-specific provisioning scripts.
|
||||
if [ "$SKIP_WWW" = false ] && [ "$DEPLOY_BTCPAY_SERVER" = true ]; then
|
||||
bash -c "./deployment/www/go.sh"
|
||||
fi
|
||||
|
||||
export DOMAIN_NAME="$PRIMARY_DOMAIN"
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
if [ "$SKIP_BTCPAY" = false ] && [ "$DEPLOY_BTCPAY_SERVER" = true ]; then
|
||||
bash -c "./deployment/btcpayserver/go.sh"
|
||||
fi
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
# The base VM image.
|
||||
export INCUS_UBUNTU_BASE_VERSION="jammy"
|
||||
export BASE_IMAGE_VM_NAME="ss-base-${INCUS_UBUNTU_BASE_VERSION//./-}"
|
||||
export BASE_INCUS_IMAGE="ubuntu/$INCUS_UBUNTU_BASE_VERSION/cloud"
|
||||
WEEK_NUMBER=$(date +%U)
|
||||
export UBUNTU_BASE_IMAGE_NAME="ss-ubuntu-${INCUS_UBUNTU_BASE_VERSION//./-}"
|
||||
export DOCKER_BASE_IMAGE_NAME="ss-docker-${INCUS_UBUNTU_BASE_VERSION//./-}-$WEEK_NUMBER"
|
|
@ -1,39 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# take the services down, create a backup archive, then pull it down.
|
||||
# the script executed here from the BTCPAY repo will automatically take services down
|
||||
# and bring them back up.
|
||||
|
||||
echo "INFO: Starting BTCPAY Backup script for host '$BTCPAY_FQDN'."
|
||||
|
||||
sleep 5
|
||||
|
||||
ssh "$BTCPAY_FQDN" "mkdir -p $REMOTE_HOME/backups; cd $REMOTE_HOME/; sudo BTCPAY_BASE_DIRECTORY=$REMOTE_HOME bash -c $BTCPAY_SERVER_APPPATH/btcpay-down.sh"
|
||||
|
||||
# TODO; not sure if this is necessary, but we want to give the VM additional time to take down all services
|
||||
# that way processes can run shutdown procedures and leave files in the correct state.
|
||||
sleep 10
|
||||
|
||||
# TODO enable encrypted archives
|
||||
# TODO switch to btcpay-backup.sh when on LXD fully.
|
||||
scp ./remote_scripts/btcpay-backup.sh "$BTCPAY_FQDN:$REMOTE_HOME/btcpay-backup.sh"
|
||||
ssh "$BTCPAY_FQDN" "sudo cp $REMOTE_HOME/btcpay-backup.sh $BTCPAY_SERVER_APPPATH/btcpay-backup.sh && sudo chmod 0755 $BTCPAY_SERVER_APPPATH/btcpay-backup.sh"
|
||||
ssh "$BTCPAY_FQDN" "cd $REMOTE_HOME/; sudo BTCPAY_BASE_DIRECTORY=$REMOTE_HOME BTCPAY_DOCKER_COMPOSE=$REMOTE_HOME/btcpayserver-docker/Generated/docker-compose.generated.yml bash -c $BTCPAY_SERVER_APPPATH/btcpay-backup.sh"
|
||||
|
||||
# next we pull the resulting backup archive down to our management machine.
|
||||
ssh "$BTCPAY_FQDN" "sudo cp /var/lib/docker/volumes/backup_datadir/_data/backup.tar.gz $REMOTE_HOME/backups/btcpay.tar.gz"
|
||||
ssh "$BTCPAY_FQDN" "sudo chown ubuntu:ubuntu $REMOTE_HOME/backups/btcpay.tar.gz"
|
||||
|
||||
# if the backup archive path is not set, then we set it. It is usually set only when we are running a migration script.
|
||||
BTCPAY_LOCAL_BACKUP_PATH="$SITES_PATH/$PRIMARY_DOMAIN/backups/btcpayserver"
|
||||
if [ -z "$BACKUP_BTCPAY_ARCHIVE_PATH" ]; then
|
||||
BACKUP_BTCPAY_ARCHIVE_PATH="$BTCPAY_LOCAL_BACKUP_PATH/$(date +%s).tar.gz"
|
||||
fi
|
||||
|
||||
mkdir -p "$BTCPAY_LOCAL_BACKUP_PATH"
|
||||
scp "$BTCPAY_FQDN:$REMOTE_HOME/backups/btcpay.tar.gz" "$BACKUP_BTCPAY_ARCHIVE_PATH"
|
||||
|
||||
echo "INFO: Created backup archive '$BACKUP_BTCPAY_ARCHIVE_PATH' for host '$BTCPAY_FQDN'."
|
|
@ -1,6 +0,0 @@
|
|||
# we append this text to the btcpay server /home/ubuntu/.bashrc so
|
||||
# logged in users have more common access to the variou
|
||||
|
||||
alias bitcoin-cli="bitcoin-cli.sh $@"
|
||||
alias lightning-cli="bitcoin-lightning-cli.sh $@"
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
export DOCKER_HOST="ssh://ubuntu@$BTCPAY_FQDN"
|
||||
|
||||
OPEN_URL=true
|
||||
RUN_SERVICES=true
|
||||
|
||||
# we will re-run the btcpayserver provisioning scripts if directed to do so.
|
||||
# if an update does occur, we grab another backup.
|
||||
if [ "$UPDATE_BTCPAY" = true ]; then
|
||||
# run the update.
|
||||
ssh "$FQDN" "bash -c $BTCPAY_SERVER_APPPATH/btcpay-down.sh"
|
||||
|
||||
# btcpay-update.sh brings services back up, but does not take them down.
|
||||
ssh "$FQDN" "sudo bash -c $BTCPAY_SERVER_APPPATH/btcpay-update.sh"
|
||||
|
||||
sleep 20
|
||||
|
||||
elif [ "$RESTORE_BTCPAY" = true ]; then
|
||||
# run the update.
|
||||
ssh "$FQDN" "bash -c $BTCPAY_SERVER_APPPATH/btcpay-down.sh"
|
||||
sleep 15
|
||||
|
||||
./restore.sh
|
||||
|
||||
RUN_SERVICES=true
|
||||
OPEN_URL=true
|
||||
BACKUP_BTCPAY=false
|
||||
|
||||
elif [ "$RECONFIGURE_BTCPAY_SERVER" == true ]; then
|
||||
# the administrator may have indicated a reconfig;
|
||||
# if so, we re-run setup script.
|
||||
./stub_btcpay_setup.sh
|
||||
|
||||
RUN_SERVICES=true
|
||||
OPEN_URL=true
|
||||
fi
|
||||
|
||||
# if the script gets this far, then we grab a regular backup.
|
||||
if [ "$BACKUP_BTCPAY" = true ]; then
|
||||
# we just grab a regular backup
|
||||
./backup_btcpay.sh
|
||||
fi
|
||||
|
||||
if [ "$RUN_SERVICES" = true ] && [ "$STOP_SERVICES" = false ]; then
|
||||
# The default is to resume services, though admin may want to keep services off (eg., for a migration)
|
||||
# we bring the services back up by default.
|
||||
ssh "$FQDN" "bash -c $BTCPAY_SERVER_APPPATH/btcpay-up.sh"
|
||||
|
||||
OPEN_URL=true
|
||||
|
||||
fi
|
||||
|
||||
if [ "$OPEN_URL" = true ]; then
|
||||
if wait-for-it -t 5 "$PRIMARY_WWW_FQDN:80"; then
|
||||
xdg-open "http://$PRIMARY_WWW_FQDN" > /dev/null 2>&1
|
||||
fi
|
||||
fi
|
|
@ -1,116 +0,0 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
set -o pipefail -o errexit
|
||||
|
||||
# Please be aware of these important issues:
|
||||
#
|
||||
# - Old channel state is toxic and you can loose all your funds, if you or someone
|
||||
# else closes a channel based on the backup with old state - and the state changes
|
||||
# often! If you publish an old state (say from yesterday's backup) on chain, you
|
||||
# WILL LOSE ALL YOUR FUNDS IN A CHANNEL, because the counterparty will publish a
|
||||
# revocation key!
|
||||
|
||||
if [ "$(id -u)" != "0" ]; then
|
||||
echo "INFO: This script must be run as root."
|
||||
echo " Use the command 'sudo su -' (include the trailing hypen) and try again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# preparation
|
||||
docker_dir=$(docker volume inspect generated_btcpay_datadir --format="{{.Mountpoint}}" | sed -e "s%/volumes/.*%%g")
|
||||
dbdump_name=postgres.sql.gz
|
||||
btcpay_dir="$BTCPAY_BASE_DIRECTORY/btcpayserver-docker"
|
||||
backup_dir="$docker_dir/volumes/backup_datadir/_data"
|
||||
dbdump_path="$docker_dir/$dbdump_name"
|
||||
backup_path="$backup_dir/backup.tar.gz"
|
||||
|
||||
# ensure backup dir exists
|
||||
if [ ! -d "$backup_dir" ]; then
|
||||
mkdir -p "$backup_dir"
|
||||
fi
|
||||
|
||||
cd "$btcpay_dir"
|
||||
. helpers.sh
|
||||
|
||||
dbcontainer=$(docker ps -a -q -f "name=postgres_1")
|
||||
if [ -z "$dbcontainer" ]; then
|
||||
printf "\n"
|
||||
echo "INFO: Database container is not up and running. Starting BTCPay Server."
|
||||
docker volume create generated_postgres_datadir
|
||||
docker-compose -f "$BTCPAY_DOCKER_COMPOSE" up -d postgres
|
||||
|
||||
printf "\n"
|
||||
dbcontainer=$(docker ps -a -q -f "name=postgres_1")
|
||||
if [ -z "$dbcontainer" ]; then
|
||||
echo "INFO: Database container could not be started or found."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
printf "\n"
|
||||
echo "INFO: Dumping database."
|
||||
{
|
||||
docker exec "$dbcontainer" pg_dumpall -c -U postgres | gzip > "$dbdump_path"
|
||||
echo "INFO: Database dump done."
|
||||
} || {
|
||||
echo "ERROR: Dumping failed. Please check the error message above."
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "Stopping BTCPay Server..."
|
||||
btcpay_down
|
||||
|
||||
printf "\n"
|
||||
cd "$docker_dir"
|
||||
echo "Archiving files in $(pwd)."
|
||||
|
||||
{
|
||||
tar \
|
||||
--exclude="volumes/backup_datadir" \
|
||||
--exclude="volumes/generated_bitcoin_datadir/_data/blocks" \
|
||||
--exclude="volumes/generated_bitcoin_datadir/_data/chainstate" \
|
||||
--exclude="volumes/generated_bitcoin_datadir/_data/debug.log" \
|
||||
--exclude="volumes/generated_bitcoin_datadir/_data/testnet3/blocks" \
|
||||
--exclude="volumes/generated_bitcoin_datadir/_data/testnet3/chainstate" \
|
||||
--exclude="volumes/generated_bitcoin_datadir/_data/testnet3/debug.log" \
|
||||
--exclude="volumes/generated_bitcoin_datadir/_data/regtest/blocks" \
|
||||
--exclude="volumes/generated_bitcoin_datadir/_data/regtest/chainstate" \
|
||||
--exclude="volumes/generated_bitcoin_datadir/_data/regtest/debug.log" \
|
||||
--exclude="volumes/generated_postgres_datadir" \
|
||||
--exclude="volumes/generated_tor_relay_datadir" \
|
||||
--exclude="volumes/generated_clightning_bitcoin_datadir/_data/lightning-rpc" \
|
||||
--exclude="**/logs/*" \
|
||||
-cvzf "$backup_path" "$dbdump_name" volumes/generated_*
|
||||
echo "INFO: Archive done."
|
||||
|
||||
if [ -n "$BTCPAY_BACKUP_PASSPHRASE" ]; then
|
||||
printf "\n"
|
||||
echo "INFO: BTCPAY_BACKUP_PASSPHRASE is set, the backup will be encrypted."
|
||||
{
|
||||
gpg -o "$backup_path.gpg" --batch --yes -c --passphrase "$BTCPAY_BACKUP_PASSPHRASE" "$backup_path"
|
||||
rm "$backup_path"
|
||||
backup_path="$backup_path.gpg"
|
||||
echo "INFO: Encryption done."
|
||||
} || {
|
||||
echo "INFO: Encrypting failed. Please check the error message above."
|
||||
echo "INFO: Restarting BTCPay Server."
|
||||
cd "$btcpay_dir"
|
||||
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
} || {
|
||||
echo "INFO: Archiving failed. Please check the error message above."
|
||||
echo "Restarting BTCPay Server"
|
||||
cd "$btcpay_dir"
|
||||
|
||||
exit 1
|
||||
}
|
||||
|
||||
printf "Restarting BTCPay Server."
|
||||
cd "$btcpay_dir"
|
||||
|
||||
echo "Cleaning up."
|
||||
rm "$dbdump_path"
|
||||
|
||||
echo "INFO: Backup done => $backup_path."
|
|
@ -1,115 +0,0 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
set -o pipefail -o errexit
|
||||
|
||||
if [ "$(id -u)" != "0" ]; then
|
||||
echo "ERROR: This script must be run as root."
|
||||
echo "➡️ Use the command 'sudo su -' (include the trailing hypen) and try again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
backup_path="$1"
|
||||
if [ -z "$backup_path" ]; then
|
||||
echo "ERROR: Usage: btcpay-restore.sh /path/to/backup.tar.gz"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$backup_path" ]; then
|
||||
echo "ERROR: $backup_path does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$backup_path" == *.gpg && -z "$BTCPAY_BACKUP_PASSPHRASE" ]]; then
|
||||
echo "INFO: $backup_path is encrypted. Please provide the passphrase to decrypt it."
|
||||
echo "INFO: Usage: BTCPAY_BACKUP_PASSPHRASE=t0pSeCrEt btcpay-restore.sh /path/to/backup.tar.gz.gpg"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# preparation
|
||||
docker_dir=$(docker volume inspect generated_btcpay_datadir --format="{{.Mountpoint}}" | sed -e "s%/volumes/.*%%g")
|
||||
restore_dir="$docker_dir/volumes/backup_datadir/_data/restore"
|
||||
dbdump_name=postgres.sql.gz
|
||||
btcpay_dir="$BTCPAY_BASE_DIRECTORY/btcpayserver-docker"
|
||||
|
||||
# ensure clean restore dir
|
||||
echo "INFO: Cleaning restore directory $restore_dir."
|
||||
rm -rf "$restore_dir"
|
||||
mkdir -p "$restore_dir"
|
||||
|
||||
if [[ "$backup_path" == *.gpg ]]; then
|
||||
echo "INFO: Decrypting backup file."
|
||||
{
|
||||
gpg -o "${backup_path%.*}" --batch --yes --passphrase "$BTCPAY_BACKUP_PASSPHRASE" -d "$backup_path"
|
||||
backup_path="${backup_path%.*}"
|
||||
echo "SUCESS: Decryption done."
|
||||
} || {
|
||||
echo "INFO: Decryption failed. Please check the error message above."
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
cd "$restore_dir"
|
||||
|
||||
echo "INFO: Extracting files in $(pwd)."
|
||||
tar -h -xvf "$backup_path" -C "$restore_dir"
|
||||
|
||||
# basic control checks
|
||||
if [ ! -f "$dbdump_name" ]; then
|
||||
echo "ERROR: '$dbdump_name' does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "volumes" ]; then
|
||||
echo "ERROR: volumes directory does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$btcpay_dir"
|
||||
. helpers.sh
|
||||
|
||||
cd "$restore_dir"
|
||||
|
||||
{
|
||||
echo "INFO: Restoring volumes."
|
||||
# ensure volumes dir exists
|
||||
if [ ! -d "$docker_dir/volumes" ]; then
|
||||
mkdir -p "$docker_dir/volumes"
|
||||
fi
|
||||
# copy volume directories over
|
||||
cp -r volumes/* "$docker_dir/volumes/"
|
||||
# ensure datadirs excluded in backup exist
|
||||
mkdir -p "$docker_dir/volumes/generated_postgres_datadir/_data"
|
||||
echo "INFO: Volume restore done."
|
||||
} || {
|
||||
echo "INFO: Restoring volumes failed. Please check the error message above."
|
||||
exit 1
|
||||
}
|
||||
|
||||
{
|
||||
echo "INFO: Starting database container"
|
||||
docker-compose -f "$BTCPAY_DOCKER_COMPOSE" up -d postgres
|
||||
dbcontainer=$(docker ps -a -q -f "name=postgres")
|
||||
if [ -z "$dbcontainer" ]; then
|
||||
echo "ERROR: Database container could not be started or found."
|
||||
exit 1
|
||||
fi
|
||||
} || {
|
||||
echo "ERROR: Starting database container failed. Please check the error message above."
|
||||
exit 1
|
||||
}
|
||||
|
||||
cd "$restore_dir"
|
||||
|
||||
{
|
||||
echo "INFO: Restoring database..."
|
||||
gunzip -c $dbdump_name | docker exec -i "$dbcontainer" psql -U postgres postgres -a
|
||||
echo "SUCCESS: Database restore done."
|
||||
} || {
|
||||
echo "ERROR: Restoring database failed. Please check the error message above."
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "INFO: Cleaning up."
|
||||
rm -rf "$restore_dir"
|
||||
|
||||
echo "SUCCESS: Restore done"
|
|
@ -1,33 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
if [ "$RESTORE_BTCPAY" = false ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -f "$BACKUP_BTCPAY_ARCHIVE_PATH" ]; then
|
||||
# push the restoration archive to the remote server
|
||||
echo "INFO: Restoring BTCPAY Server: $BACKUP_BTCPAY_ARCHIVE_PATH"
|
||||
|
||||
REMOTE_BACKUP_PATH="$REMOTE_HOME/backups/btcpayserver"
|
||||
ssh "$FQDN" mkdir -p "$REMOTE_BACKUP_PATH"
|
||||
REMOTE_BTCPAY_ARCHIVE_PATH="$REMOTE_BACKUP_PATH/btcpay.tar.gz"
|
||||
scp "$BACKUP_BTCPAY_ARCHIVE_PATH" "$FQDN:$REMOTE_BTCPAY_ARCHIVE_PATH"
|
||||
|
||||
# we clean up any old containers first before restoring.
|
||||
ssh "$FQDN" docker system prune -f
|
||||
|
||||
# push the modified restore script to the remote directory, set permissions, and execute.
|
||||
scp ./remote_scripts/btcpay-restore.sh "$FQDN:$REMOTE_HOME/btcpay-restore.sh"
|
||||
ssh "$FQDN" "sudo mv $REMOTE_HOME/btcpay-restore.sh $BTCPAY_SERVER_APPPATH/btcpay-restore.sh && sudo chmod 0755 $BTCPAY_SERVER_APPPATH/btcpay-restore.sh"
|
||||
ssh "$FQDN" "cd $REMOTE_HOME/; sudo BTCPAY_BASE_DIRECTORY=$REMOTE_HOME BTCPAY_DOCKER_COMPOSE=$REMOTE_HOME/btcpayserver-docker/Generated/docker-compose.generated.yml bash -c '$BTCPAY_SERVER_APPPATH/btcpay-restore.sh $REMOTE_BTCPAY_ARCHIVE_PATH'"
|
||||
|
||||
# now, we're going to take things down because aparently we this needs to be re-exececuted.
|
||||
ssh "$FQDN" "bash -c $BTCPAY_SERVER_APPPATH/btcpay-down.sh"
|
||||
|
||||
else
|
||||
echo "ERROR: File does not exist."
|
||||
exit 1
|
||||
fi
|
|
@ -1,94 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# export BTCPAY_FASTSYNC_ARCHIVE_FILENAME="utxo-snapshot-bitcoin-testnet-1445586.tar"
|
||||
# BTCPAY_REMOTE_RESTORE_PATH="/var/lib/docker/volumes/generated_bitcoin_datadir/_data"
|
||||
|
||||
# This is the config for a basic proxy to the listening port 127.0.0.1:2368
|
||||
# It also supports modern TLS, so SSL certs must be available.
|
||||
#opt-add-nostr-relay;
|
||||
cat > "$SITE_PATH/btcpay.sh" <<EOL
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
cd "\$(dirname "\$0")"
|
||||
|
||||
# wait for cloud-init to complete yo
|
||||
while [ ! -f /var/lib/cloud/instance/boot-finished ]; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if [ ! -d "btcpayserver-docker" ]; then
|
||||
echo "cloning btcpayserver-docker";
|
||||
git clone -b master https://github.com/btcpayserver/btcpayserver-docker btcpayserver-docker;
|
||||
git config --global --add safe.directory /home/ubuntu/btcpayserver-docker
|
||||
else
|
||||
cd ./btcpayserver-docker
|
||||
git pull
|
||||
git pull --all --tags
|
||||
cd -
|
||||
fi
|
||||
|
||||
cd btcpayserver-docker
|
||||
|
||||
export BTCPAY_HOST="${BTCPAY_USER_FQDN}"
|
||||
export BTCPAY_ANNOUNCEABLE_HOST="${DOMAIN_NAME}"
|
||||
export NBITCOIN_NETWORK="${BTC_CHAIN}"
|
||||
export LIGHTNING_ALIAS="${PRIMARY_DOMAIN}"
|
||||
export BTCPAYGEN_LIGHTNING="clightning"
|
||||
export BTCPAYGEN_CRYPTO1="btc"
|
||||
export BTCPAYGEN_ADDITIONAL_FRAGMENTS="opt-save-storage-s;opt-add-btctransmuter;bitcoin-clightning.custom;"
|
||||
export BTCPAYGEN_REVERSEPROXY="nginx"
|
||||
export BTCPAY_ENABLE_SSH=false
|
||||
export BTCPAY_BASE_DIRECTORY=${REMOTE_HOME}
|
||||
export BTCPAYGEN_EXCLUDE_FRAGMENTS="nginx-https;"
|
||||
export REVERSEPROXY_DEFAULT_HOST="$BTCPAY_USER_FQDN"
|
||||
|
||||
if [ "\$NBITCOIN_NETWORK" != regtest ]; then
|
||||
# run fast_sync if it's not been done before.
|
||||
if [ ! -f /home/ubuntu/fast_sync_completed ]; then
|
||||
cd ./contrib/FastSync
|
||||
./load-utxo-set.sh
|
||||
touch /home/ubuntu/fast_sync_completed
|
||||
cd -
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# next we create fragments to customize various aspects of the system
|
||||
# this block customizes clightning to ensure the correct endpoints are being advertised
|
||||
# We want to advertise the correct ipv4 endpoint for remote hosts to get in touch.
|
||||
cat > ${REMOTE_HOME}/btcpayserver-docker/docker-compose-generator/docker-fragments/bitcoin-clightning.custom.yml <<EOF
|
||||
|
||||
services:
|
||||
clightning_bitcoin:
|
||||
environment:
|
||||
LIGHTNINGD_OPT: |
|
||||
announce-addr-dns=true
|
||||
|
||||
EOF
|
||||
|
||||
# run the setup script.
|
||||
. ./btcpay-setup.sh -i
|
||||
|
||||
touch ${REMOTE_HOME}/btcpay.complete
|
||||
|
||||
EOL
|
||||
|
||||
# send an updated ~/.bashrc so we have quicker access to cli tools
|
||||
scp ./bashrc.txt "ubuntu@$FQDN:$REMOTE_HOME/.bashrc"
|
||||
ssh "$BTCPAY_FQDN" "chown ubuntu:ubuntu $REMOTE_HOME/.bashrc"
|
||||
ssh "$BTCPAY_FQDN" "chmod 0664 $REMOTE_HOME/.bashrc"
|
||||
|
||||
# send the setup script to the remote machine.
|
||||
scp "$SITE_PATH/btcpay.sh" "ubuntu@$FQDN:$REMOTE_HOME/btcpay_setup.sh"
|
||||
ssh "$BTCPAY_FQDN" "chmod 0744 $REMOTE_HOME/btcpay_setup.sh"
|
||||
|
||||
# script is executed under sudo
|
||||
ssh "$BTCPAY_FQDN" "sudo bash -c $REMOTE_HOME/btcpay_setup.sh"
|
||||
|
||||
|
||||
# lets give time for the containers to spin up
|
||||
sleep 10
|
|
@ -0,0 +1,102 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -exu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
. ./base.sh
|
||||
|
||||
bash -c "./stub_profile.sh --incus-hostname=$BASE_IMAGE_VM_NAME"
|
||||
|
||||
if incus list -q --project default | grep -q "$BASE_IMAGE_VM_NAME" ; then
|
||||
incus delete -f "$BASE_IMAGE_VM_NAME" --project default
|
||||
fi
|
||||
|
||||
# let's download our base image.
|
||||
if ! incus image list --format csv --columns l --project default | grep -q "$UBUNTU_BASE_IMAGE_NAME"; then
|
||||
# copy the image down from canonical.
|
||||
incus image copy "images:$BASE_INCUS_IMAGE" "$REMOTE_NAME": --alias "$UBUNTU_BASE_IMAGE_NAME" --public --vm --auto-update --target-project default
|
||||
fi
|
||||
|
||||
# If the VM does exist, then we will delete it (so we can start fresh)
|
||||
if incus list --format csv -q --project default | grep -q "$UBUNTU_BASE_IMAGE_NAME"; then
|
||||
# if there's no snapshot, we dispense with the old image and try again.
|
||||
if ! incus info "$BASE_IMAGE_VM_NAME" --project default | grep -q "$UBUNTU_BASE_IMAGE_NAME"; then
|
||||
incus delete "$BASE_IMAGE_VM_NAME" --force --project default
|
||||
ssh-keygen -f "$SSH_HOME/known_hosts" -R "$BASE_IMAGE_VM_NAME"
|
||||
fi
|
||||
else
|
||||
|
||||
if ! incus list --project default | grep -q "$BASE_IMAGE_VM_NAME"; then
|
||||
# the base image is ubuntu:22.04.
|
||||
script -q -c "incus init -q --profile=$BASE_IMAGE_VM_NAME $UBUNTU_BASE_IMAGE_NAME $BASE_IMAGE_VM_NAME --vm --project default" /dev/null
|
||||
fi
|
||||
|
||||
if incus info "$BASE_IMAGE_VM_NAME" --project default | grep -q "Status: STOPPED"; then
|
||||
# TODO move this sovereign-stack-base construction VM to separate dedicated IP
|
||||
incus config set "$BASE_IMAGE_VM_NAME" --project default
|
||||
incus start "$BASE_IMAGE_VM_NAME" --project default
|
||||
sleep 15
|
||||
fi
|
||||
|
||||
# for CHAIN in mainnet testnet; do
|
||||
# for DATA in blocks chainstate; do
|
||||
# incus storage volume attach ss-base "$CHAIN-$DATA" "$BASE_IMAGE_VM_NAME" "/home/ubuntu/bitcoin/$DATA"
|
||||
# done
|
||||
# done
|
||||
|
||||
if incus info "$BASE_IMAGE_VM_NAME" --project default | grep -q "Status: RUNNING"; then
|
||||
|
||||
while incus exec "$BASE_IMAGE_VM_NAME" --project default -- [ ! -f /var/lib/cloud/instance/boot-finished ]; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# ensure the ssh service is listening at localhost
|
||||
incus exec "$BASE_IMAGE_VM_NAME" --project default -- wait-for-it -t 100 127.0.0.1:22
|
||||
|
||||
# # If we have any chaninstate or blocks in our SSME, let's push them to the
|
||||
# # remote host as a zfs volume that way deployments can share a common history
|
||||
# # of chainstate/blocks.
|
||||
# for CHAIN in testnet mainnet; do
|
||||
# for DATA in blocks chainstate; do
|
||||
# # if the storage snapshot doesn't yet exist, create it.
|
||||
# if ! incus storage volume list ss-base -q --format csv -c n | grep -q "$CHAIN-$DATA/snap0"; then
|
||||
# DATA_PATH="/home/ubuntu/.ss/cache/bitcoin/$CHAIN/$DATA"
|
||||
# if [ -d "$DATA_PATH" ]; then
|
||||
# COMPLETE_FILE_PATH="$DATA_PATH/complete"
|
||||
# if incus exec "$BASE_IMAGE_VM_NAME" -- [ ! -f "$COMPLETE_FILE_PATH" ]; then
|
||||
# incus file push --recursive --project default "$DATA_PATH/" "$BASE_IMAGE_VM_NAME""$DATA_PATH/"
|
||||
# incus exec "$BASE_IMAGE_VM_NAME" -- su ubuntu - bash -c "echo $(date) > $COMPLETE_FILE_PATH"
|
||||
# incus exec "$BASE_IMAGE_VM_NAME" -- chown -R 999:999 "$DATA_PATH/$DATA"
|
||||
# else
|
||||
# echo "INFO: it appears as though $CHAIN/$DATA has already been initialized. Continuing."
|
||||
# fi
|
||||
# fi
|
||||
# fi
|
||||
# done
|
||||
# done
|
||||
|
||||
# stop the VM and get a snapshot.
|
||||
incus stop "$BASE_IMAGE_VM_NAME" --project default
|
||||
fi
|
||||
|
||||
incus snapshot create "$BASE_IMAGE_VM_NAME" "$UBUNTU_BASE_IMAGE_NAME" --project default
|
||||
|
||||
fi
|
||||
|
||||
echo "INFO: Publishing '$BASE_IMAGE_VM_NAME' as image '$DOCKER_BASE_IMAGE_NAME'. Please wait."
|
||||
incus publish -q --public "$BASE_IMAGE_VM_NAME/$UBUNTU_BASE_IMAGE_NAME" \
|
||||
--project default --alias="$DOCKER_BASE_IMAGE_NAME" \
|
||||
--compression none
|
||||
|
||||
echo "INFO: Success creating the base image. Deleting artifacts from the build process."
|
||||
incus delete -f "$BASE_IMAGE_VM_NAME" --project default
|
||||
|
||||
# # now let's get a snapshot of each of the blocks/chainstate directories.
|
||||
# for CHAIN in testnet mainnet; do
|
||||
# for DATA in blocks chainstate; do
|
||||
# if ! incus storage volume list ss-base -q --format csv -c n | grep -q "$CHAIN-$DATA/snap0"; then
|
||||
# echo "INFO: Creating a snapshot 'ss-base/$CHAIN-$DATA/snap0'."
|
||||
# incus storage volume snapshot ss-base --project default "$CHAIN-$DATA"
|
||||
# fi
|
||||
# done
|
||||
# done
|
|
@ -1,61 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
./stub_lxc_profile.sh sovereign-stack
|
||||
|
||||
# create the default storage pool if necessary
|
||||
if ! lxc storage list --format csv | grep -q "sovereign-stack"; then
|
||||
|
||||
if [ "$DISK_TO_USE" != loop ]; then
|
||||
# we omit putting a size here so, so LXD will consume the entire disk if '/dev/sdb' or partition if '/dev/sdb1'.
|
||||
# TODO do some sanity/resource checking on DISK_TO_USE.
|
||||
lxc storage create "sovereign-stack" zfs source="$DISK_TO_USE"
|
||||
|
||||
else
|
||||
# if a disk is the default 'loop', then we create a zfs storage pool
|
||||
# on top of the existing filesystem using a loop device, per LXD docs
|
||||
lxc storage create "sovereign-stack" zfs
|
||||
fi
|
||||
fi
|
||||
|
||||
# If our template doesn't exist, we create one.
|
||||
if ! lxc image list --format csv "$VM_NAME" | grep -q "$VM_NAME"; then
|
||||
|
||||
# If the lxc VM does exist, then we will delete it (so we can start fresh)
|
||||
if lxc list -q --format csv | grep -q "$VM_NAME"; then
|
||||
lxc delete "$VM_NAME" --force
|
||||
|
||||
# remove the ssh known endpoint else we get warnings.
|
||||
ssh-keygen -f "$SSH_HOME/known_hosts" -R "$VM_NAME"
|
||||
fi
|
||||
|
||||
# let's download our base image.
|
||||
if ! lxc image list --format csv --columns l | grep -q "ubuntu-base"; then
|
||||
# if the image doesn't exist, download it from Ubuntu's image server
|
||||
# TODO see if we can fetch this file from a more censorship-resistant source, e.g., ipfs
|
||||
# we don't really need to cache this locally since it gets continually updated upstream.
|
||||
lxc image copy "images:$BASE_LXC_IMAGE" "$CLUSTER_NAME": --alias "ubuntu-base" --public --vm
|
||||
fi
|
||||
|
||||
# this vm is used temperarily with
|
||||
lxc init --profile="sovereign-stack" "ubuntu-base" "$VM_NAME" --vm
|
||||
|
||||
# let's PIN the HW address for now so we don't exhaust IP
|
||||
# and so we can set DNS internally.
|
||||
|
||||
# TODO move this sovereign-stack-base construction VM to separate dedicated IP
|
||||
lxc config set "$VM_NAME" "volatile.enp5s0.hwaddr=$SOVEREIGN_STACK_MAC_ADDRESS"
|
||||
|
||||
lxc start "$VM_NAME"
|
||||
sleep 10
|
||||
|
||||
# let's wait for the LXC vm remote machine to get an IP address.
|
||||
./wait_for_lxc_ip.sh "$VM_NAME"
|
||||
|
||||
# stop the VM and get a snapshot.
|
||||
lxc stop "$VM_NAME"
|
||||
lxc publish "$CLUSTER_NAME:$VM_NAME" --alias "$VM_NAME" --public
|
||||
|
||||
fi
|
|
@ -0,0 +1,122 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -exu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
. ./base.sh
|
||||
|
||||
## This is a weird if clause since we need to LEFT-ALIGN the statement below.
|
||||
SSH_STRING="Host ${FQDN}"
|
||||
if ! grep -q "$SSH_STRING" "$SSH_HOME/config"; then
|
||||
|
||||
########## BEGIN
|
||||
cat >> "$SSH_HOME/config" <<-EOF
|
||||
|
||||
${SSH_STRING}
|
||||
HostName ${FQDN}
|
||||
User ubuntu
|
||||
EOF
|
||||
###
|
||||
|
||||
fi
|
||||
|
||||
# if the machine doesn't exist, we create it.
|
||||
if ! incus list --format csv | grep -q "$INCUS_VM_NAME"; then
|
||||
|
||||
# create a base image if needed and instantiate a VM.
|
||||
if [ -z "$MAC_ADDRESS_TO_PROVISION" ]; then
|
||||
echo "ERROR: You MUST define a MAC Address for all your machines in your project definition."
|
||||
echo "INFO: IMPORTANT! You MUST have DHCP Reservations for these MAC addresses. You also need records established the DNS."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# TODO ensure we are only GROWING the volume--never shrinking per zfs volume docs.
|
||||
BACKUP_DISK_SIZE_GB=
|
||||
SSDATA_DISK_SIZE_GB=
|
||||
DOCKER_DISK_SIZE_GB=
|
||||
if [ "$VIRTUAL_MACHINE" = www ]; then
|
||||
if [ "$SKIP_WWW_SERVER" = true ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
BACKUP_DISK_SIZE_GB="$WWW_BACKUP_DISK_SIZE_GB"
|
||||
SSDATA_DISK_SIZE_GB="$WWW_SSDATA_DISK_SIZE_GB"
|
||||
DOCKER_DISK_SIZE_GB="$WWW_DOCKER_DISK_SIZE_GB"
|
||||
fi
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" = btcpayserver ]; then
|
||||
if [ "$SKIP_BTCPAY_SERVER" = true ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
BACKUP_DISK_SIZE_GB="$BTCPAYSERVER_BACKUP_DISK_SIZE_GB"
|
||||
SSDATA_DISK_SIZE_GB="$BTCPAYSERVER_SSDATA_DISK_SIZE_GB"
|
||||
DOCKER_DISK_SIZE_GB="$BTCPAYSERVER_DOCKER_DISK_SIZE_GB"
|
||||
fi
|
||||
|
||||
SSDATA_VOLUME_NAME=
|
||||
BACKUP_VOLUME_NAME=
|
||||
if [ "$VIRTUAL_MACHINE" != lnplayserver ]; then
|
||||
DOCKER_VOLUME_NAME="$VIRTUAL_MACHINE-docker"
|
||||
if ! incus storage volume list ss-base | grep -q "$DOCKER_VOLUME_NAME"; then
|
||||
incus storage volume create ss-base "$DOCKER_VOLUME_NAME" --type=block
|
||||
incus storage volume set ss-base "$DOCKER_VOLUME_NAME" size="${DOCKER_DISK_SIZE_GB}GB"
|
||||
fi
|
||||
|
||||
SSDATA_VOLUME_NAME="$VIRTUAL_MACHINE-ss-data"
|
||||
if ! incus storage volume list ss-base | grep -q "$SSDATA_VOLUME_NAME"; then
|
||||
incus storage volume create ss-base "$SSDATA_VOLUME_NAME" --type=filesystem
|
||||
incus storage volume set ss-base "$SSDATA_VOLUME_NAME" size="${SSDATA_DISK_SIZE_GB}GB"
|
||||
fi
|
||||
|
||||
BACKUP_VOLUME_NAME="$VIRTUAL_MACHINE-backup"
|
||||
if ! incus storage volume list ss-base | grep -q "$BACKUP_VOLUME_NAME"; then
|
||||
incus storage volume create ss-base "$BACKUP_VOLUME_NAME" --type=filesystem
|
||||
incus storage volume set ss-base "$BACKUP_VOLUME_NAME" size="${BACKUP_DISK_SIZE_GB}GB"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
|
||||
bash -c "./stub_profile.sh --vm=$VIRTUAL_MACHINE --incus-hostname=$INCUS_VM_NAME --ss-volume-name=$SSDATA_VOLUME_NAME --backup-volume-name=$BACKUP_VOLUME_NAME"
|
||||
|
||||
INCUS_LNPLAYSERVER_IMAGE_NAME="lnplayserver-$DOMAIN_NAME"
|
||||
if ! incus image list -q --format csv | grep -q "$INCUS_LNPLAYSERVER_IMAGE_NAME"; then
|
||||
script -q -c "incus init -q $DOCKER_BASE_IMAGE_NAME $INCUS_VM_NAME --vm --profile=$INCUS_VM_NAME" /dev/null
|
||||
elif [ "$VIRTUAL_MACHINE" = lnplayserver ]; then
|
||||
script -q -c "incus init -q $INCUS_LNPLAYSERVER_IMAGE_NAME $INCUS_VM_NAME --vm --profile=$INCUS_VM_NAME" /dev/null
|
||||
fi
|
||||
|
||||
# let's PIN the HW address for now so we don't exhaust IP
|
||||
# and so we can set DNS internally.
|
||||
incus config set "$INCUS_VM_NAME" "volatile.enp5s0.hwaddr=$MAC_ADDRESS_TO_PROVISION"
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" != lnplayserver ]; then
|
||||
# attack the docker block device.
|
||||
incus storage volume attach ss-base "$DOCKER_VOLUME_NAME" "$INCUS_VM_NAME"
|
||||
fi
|
||||
|
||||
# if [ "$VIRTUAL_MACHINE" = btcpayserver ]; then
|
||||
# # attach any volumes
|
||||
# for CHAIN in testnet mainnet; do
|
||||
# for DATA in blocks chainstate; do
|
||||
# MOUNT_PATH="/$CHAIN-$DATA"
|
||||
# incus config device add "$INCUS_VM_NAME" "$CHAIN-$DATA" disk pool=ss-base source="$CHAIN-$DATA" path="$MOUNT_PATH"
|
||||
# done
|
||||
# done
|
||||
# fi
|
||||
|
||||
incus start "$INCUS_VM_NAME"
|
||||
sleep 15
|
||||
|
||||
bash -c "./wait_for_ip.sh --incus-name=$INCUS_VM_NAME"
|
||||
|
||||
# scan the remote machine and install it's identity in our SSH known_hosts file.
|
||||
ssh-keyscan -H "$FQDN" >> "$SSH_HOME/known_hosts"
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" != lnplayserver ]; then
|
||||
ssh "$FQDN" "sudo chown ubuntu:ubuntu $REMOTE_DATA_PATH"
|
||||
ssh "$FQDN" "sudo chown -R ubuntu:ubuntu $REMOTE_BACKUP_PATH"
|
||||
fi
|
||||
|
||||
fi
|
|
@ -1,70 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# let's make sure we have an ssh keypair. We just use $SSH_HOME/id_rsa
|
||||
# TODO convert this to SSH private key held on Trezor. THus trezor-T required for
|
||||
# login operations. This should be configurable of course.
|
||||
if [ ! -f "$SSH_HOME/id_rsa" ]; then
|
||||
# generate a new SSH key for the base vm image.
|
||||
ssh-keygen -f "$SSH_HOME/id_rsa" -t ecdsa -b 521 -N ""
|
||||
fi
|
||||
|
||||
## This is a weird if clause since we need to LEFT-ALIGN the statement below.
|
||||
SSH_STRING="Host ${FQDN}"
|
||||
if ! grep -q "$SSH_STRING" "$SSH_HOME/config"; then
|
||||
|
||||
########## BEGIN
|
||||
cat >> "$SSH_HOME/config" <<-EOF
|
||||
|
||||
${SSH_STRING}
|
||||
HostName ${FQDN}
|
||||
User ubuntu
|
||||
EOF
|
||||
###
|
||||
|
||||
fi
|
||||
|
||||
ssh-keygen -f "$SSH_HOME/known_hosts" -R "$FQDN"
|
||||
|
||||
# if the machine doesn't exist, we create it.
|
||||
if ! lxc list --format csv | grep -q "$LXD_VM_NAME"; then
|
||||
|
||||
# create a base image if needed and instantiate a VM.
|
||||
if [ -z "$MAC_ADDRESS_TO_PROVISION" ]; then
|
||||
echo "ERROR: You MUST define a MAC Address for all your machines by setting WWW_SERVER_MAC_ADDRESS, BTCPAYSERVER_MAC_ADDRESS in your site definition."
|
||||
echo "INFO: IMPORTANT! You MUST have DHCP Reservations for these MAC addresses. You also need records established the DNS."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
./stub_lxc_profile.sh "$LXD_VM_NAME"
|
||||
|
||||
# now let's create a new VM to work with.
|
||||
lxc init --profile="$LXD_VM_NAME" "$VM_NAME" "$LXD_VM_NAME" --vm
|
||||
|
||||
# let's PIN the HW address for now so we don't exhaust IP
|
||||
# and so we can set DNS internally.
|
||||
lxc config set "$LXD_VM_NAME" "volatile.enp5s0.hwaddr=$MAC_ADDRESS_TO_PROVISION"
|
||||
lxc config device override "$LXD_VM_NAME" root size="${ROOT_DISK_SIZE_GB}GB"
|
||||
|
||||
lxc start "$LXD_VM_NAME"
|
||||
|
||||
./wait_for_lxc_ip.sh "$LXD_VM_NAME"
|
||||
|
||||
fi
|
||||
|
||||
# scan the remote machine and install it's identity in our SSH known_hosts file.
|
||||
ssh-keyscan -H -t ecdsa "$FQDN" >> "$SSH_HOME/known_hosts"
|
||||
|
||||
# create a directory to store backup archives. This is on all new vms.
|
||||
ssh "$FQDN" mkdir -p "$REMOTE_HOME/backups"
|
||||
|
||||
# if this execution is for btcpayserver, then we run the stub/btcpay setup script
|
||||
# but only if it hasn't been executed before.
|
||||
if [ "$VIRTUAL_MACHINE" = btcpayserver ]; then
|
||||
if [ "$(ssh "$BTCPAY_FQDN" [[ ! -f "$REMOTE_HOME/btcpay.complete" ]]; echo $?)" -eq 0 ]; then
|
||||
./btcpayserver/stub_btcpay_setup.sh
|
||||
fi
|
||||
fi
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
# file paths
|
||||
export SSH_HOME="$HOME/.ssh"
|
||||
export PASS_HOME="$HOME/.password-store" #TODO
|
||||
export SS_ROOT_PATH="$HOME/ss"
|
||||
export REMOTES_PATH="$SS_ROOT_PATH/remotes"
|
||||
export PROJECTS_PATH="$SS_ROOT_PATH/projects"
|
||||
export SITES_PATH="$SS_ROOT_PATH/sites"
|
||||
export INCUS_CONFIG_PATH="$SS_ROOT_PATH/incus"
|
||||
export SS_CACHE_PATH="$SS_ROOT_PATH/cache"
|
||||
|
||||
export REMOTE_HOME="/home/ubuntu"
|
||||
export REMOTE_DATA_PATH="$REMOTE_HOME/ss-data"
|
||||
export REMOTE_DATA_PATH_LETSENCRYPT="$REMOTE_DATA_PATH/letsencrypt"
|
||||
export REMOTE_BACKUP_PATH="$REMOTE_HOME/backups"
|
||||
export BTCPAY_SERVER_APPPATH="$REMOTE_DATA_PATH/btcpayserver-docker"
|
||||
|
||||
export BITCOIN_CHAIN=regtest
|
||||
|
||||
# this space is for OS, docker images, etc
|
||||
# values here are fine for regtest generally. Later scripts adjust
|
||||
# these values based on testnet/mainnet
|
||||
export WWW_SSDATA_DISK_SIZE_GB=20
|
||||
export WWW_BACKUP_DISK_SIZE_GB=50
|
||||
export WWW_DOCKER_DISK_SIZE_GB=30
|
||||
|
||||
export BTCPAYSERVER_SSDATA_DISK_SIZE_GB=20
|
||||
export BTCPAYSERVER_BACKUP_DISK_SIZE_GB=20
|
||||
export BTCPAYSERVER_DOCKER_DISK_SIZE_GB=30
|
||||
|
||||
export WWW_HOSTNAME="www"
|
||||
export BTCPAY_SERVER_HOSTNAME="btcpayserver"
|
||||
export LNPLAY_SERVER_HOSTNAME="lnplayserver"
|
||||
export BTCPAY_HOSTNAME_IN_CERT="btcpay"
|
||||
export NEXTCLOUD_HOSTNAME="nextcloud"
|
||||
export GITEA_HOSTNAME="git"
|
||||
export NOSTR_HOSTNAME="relay"
|
||||
|
||||
export REGISTRY_URL="https://index.docker.io/v1"
|
||||
|
||||
export BTCPAY_SERVER_CPU_COUNT="4"
|
||||
export BTCPAY_SERVER_MEMORY_MB="4096"
|
||||
export WWW_SERVER_CPU_COUNT="4"
|
||||
export WWW_SERVER_MEMORY_MB="4096"
|
||||
export LNPLAY_SERVER_CPU_COUNT="4"
|
||||
export LNPLAY_SERVER_MEMORY_MB="4096"
|
||||
export DOCKER_IMAGE_CACHE_FQDN="registry-1.docker.io"
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -exu
|
||||
|
||||
# the DOMAIN_LIST is a complete list of all our domains. We often iterate over this list.
|
||||
DOMAIN_LIST="${PRIMARY_DOMAIN}"
|
||||
if [ -n "$OTHER_SITES_LIST" ]; then
|
||||
DOMAIN_LIST="${DOMAIN_LIST},${OTHER_SITES_LIST}"
|
||||
fi
|
||||
|
||||
export DOMAIN_LIST="$DOMAIN_LIST"
|
||||
export DOMAIN_COUNT=$(("$(echo "$DOMAIN_LIST" | tr -cd , | wc -c)"+1))
|
||||
export OTHER_SITES_LIST="$OTHER_SITES_LIST"
|
||||
|
||||
export PRIMARY_WWW_FQDN="$WWW_HOSTNAME.$PRIMARY_DOMAIN"
|
||||
export BTCPAY_SERVER_FQDN="$BTCPAY_SERVER_HOSTNAME.$PRIMARY_DOMAIN"
|
||||
export LNPLAY_SERVER_FQDN="$LNPLAY_SERVER_HOSTNAME.$PRIMARY_DOMAIN"
|
|
@ -0,0 +1,137 @@
|
|||
#!/bin/bash
|
||||
|
||||
# https://www.sovereign-stack.org/ss-down/
|
||||
|
||||
set -exu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
if incus remote get-default -q | grep -q "local"; then
|
||||
echo "ERROR: you are on the local incus remote. Nothing to take down"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
KEEP_ZFS_STORAGE_VOLUMES=true
|
||||
OTHER_SITES_LIST=
|
||||
SKIP_BTCPAY_SERVER=false
|
||||
SKIP_WWW_SERVER=false
|
||||
SKIP_LNPLAY_SERVER=false
|
||||
BACKUP_WWW_APPS=true
|
||||
|
||||
WWW_SERVER_MAC_ADDRESS=
|
||||
BTCPAY_SERVER_MAC_ADDRESS=
|
||||
LNPLAY_SERVER_MAC_ADDRESS=
|
||||
|
||||
# grab any modifications from the command line.
|
||||
for i in "$@"; do
|
||||
case $i in
|
||||
--purge)
|
||||
KEEP_ZFS_STORAGE_VOLUMES=false
|
||||
shift
|
||||
;;
|
||||
--skip-btcpayserver)
|
||||
SKIP_BTCPAY_SERVER=true
|
||||
shift
|
||||
;;
|
||||
--skip-wwwserver)
|
||||
SKIP_WWW_SERVER=true
|
||||
shift
|
||||
;;
|
||||
--skip-lnplayserver)
|
||||
SKIP_LNPLAY_SERVER=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unexpected option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
. ./deployment_defaults.sh
|
||||
|
||||
. ./remote_env.sh
|
||||
|
||||
. ./project_env.sh
|
||||
|
||||
# let's bring down services on the remote deployment if necessary.
|
||||
export DOMAIN_NAME="$PRIMARY_DOMAIN"
|
||||
export SITE_PATH="$SITES_PATH/$PRIMARY_DOMAIN"
|
||||
|
||||
source "$SITE_PATH/site.conf"
|
||||
source ./project/domain_env.sh
|
||||
|
||||
source ./domain_list.sh
|
||||
|
||||
|
||||
SERVERS=
|
||||
if [ "$SKIP_WWW_SERVER" = false ] && [ -n "$WWW_SERVER_MAC_ADDRESS" ]; then
|
||||
SERVERS="www $SERVERS"
|
||||
fi
|
||||
|
||||
if [ "$SKIP_BTCPAY_SERVER" = false ] && [ -n "$BTCPAY_SERVER_MAC_ADDRESS" ]; then
|
||||
SERVERS="$SERVERS btcpayserver"
|
||||
fi
|
||||
|
||||
if [ "$SKIP_LNPLAY_SERVER" = false ] && [ -n "$LNPLAY_SERVER_MAC_ADDRESS" ]; then
|
||||
SERVERS="$SERVERS lnplayserver"
|
||||
fi
|
||||
|
||||
for VIRTUAL_MACHINE in $SERVERS; do
|
||||
|
||||
INCUS_VM_NAME="$VIRTUAL_MACHINE-${PRIMARY_DOMAIN//./-}"
|
||||
|
||||
if incus list | grep -q "$INCUS_VM_NAME"; then
|
||||
bash -c "./stop.sh --server=$VIRTUAL_MACHINE"
|
||||
|
||||
incus stop "$INCUS_VM_NAME"
|
||||
|
||||
incus delete "$INCUS_VM_NAME"
|
||||
fi
|
||||
|
||||
# remove the ssh known endpoint else we get warnings.
|
||||
ssh-keygen -f "$SSH_HOME/known_hosts" -R "$VIRTUAL_MACHINE.$PRIMARY_DOMAIN" | exit
|
||||
|
||||
if incus profile list | grep -q "$INCUS_VM_NAME"; then
|
||||
incus profile delete "$INCUS_VM_NAME"
|
||||
fi
|
||||
|
||||
if [ "$KEEP_ZFS_STORAGE_VOLUMES" = false ]; then
|
||||
# d for docker; b for backup; s for ss-data
|
||||
for DATA in docker backup ss-data; do
|
||||
VOLUME_NAME="$VIRTUAL_MACHINE-$DATA"
|
||||
if incus storage volume list ss-base -q | grep -q "$VOLUME_NAME"; then
|
||||
RESPONSE=
|
||||
read -r -p "Are you sure you want to delete the '$VOLUME_NAME' volume intended for '$INCUS_VM_NAME'?": RESPONSE
|
||||
|
||||
if [ "$RESPONSE" = "y" ]; then
|
||||
incus storage volume delete ss-base "$VOLUME_NAME"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
BACKUP_WWW_APPS=true
|
||||
echo "BACKUP_WWW_APPS: $BACKUP_WWW_APPS"
|
||||
|
||||
|
||||
echo "SERVERS: $SERVERS"
|
||||
echo "BACKUP_WWW_APPS: $BACKUP_WWW_APPS"
|
||||
|
||||
|
||||
# let's grab a snapshot of the
|
||||
if [ "$BACKUP_WWW_APPS" = true ]; then
|
||||
SNAPSHOT_ID=$(cat /dev/urandom | tr -dc 'a-aA-Z' | fold -w 6 | head -n 1)
|
||||
incus storage volume snapshot create ss-base www-ss-data "$SNAPSHOT_ID"
|
||||
BACKUP_LOCATION="$HOME/ss/backups"
|
||||
mkdir -p "$BACKUP_LOCATION"
|
||||
#incus storage volume export ss-base "www-ss-data" "$BACKUP_LOCATION/project-$(incus project list --format csv | grep "(current)" | awk '{print $1}')_www-ss-data_""$(date +%s)"".tar.gz"
|
||||
#incus storage volume snapshot delete ss-base "www-ss-data" "$SNAPSHOT_ID"
|
||||
fi
|
||||
|
||||
if [[ "$SERVERS" == *"www"* && "$SERVERS" == *"btcpay"* ]]; then
|
||||
if incus network list -q | grep -q ss-ovn; then
|
||||
incus network delete ss-ovn
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
You are in the Sovereign Stack Management Environment (SSME). From here, you can issue several commands:
|
||||
|
||||
ss-remote - Take a remote SSH endpoint under management of Sovereign Stack.
|
||||
ss-reset - The opposite of ss-remote; de-provisions an existing remote.
|
||||
ss-up - Instantiate a deployment to your active project according to your
|
||||
various project.conf and site.conf files.
|
||||
ss-down - Reverses ss-up. Takes the active project down. Non-destructive of user data,
|
||||
unless you provide the --purge flag.
|
||||
ss-update - This is just ss-down then ss-up.
|
||||
ss-show - show the incus resources associated with the current remote.
|
||||
|
||||
For more infomation about all these topics, consult the Sovereign Stack website starting with:
|
||||
|
||||
- https://www.sovereign-stack.org/tag/deployment-management/
|
|
@ -0,0 +1 @@
|
|||
Subproject commit e8470d789a3811e2fe3f6818fd9a6fea859ba71c
|
|
@ -0,0 +1,65 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
PROJECT_NAME="$(incus info | grep "project:" | awk '{print $2}')"
|
||||
export PROJECT_NAME="$PROJECT_NAME"
|
||||
|
||||
if [ "$PROJECT_NAME" = default ]; then
|
||||
echo "ERROR: You are on the default project. Use 'incus project list' and 'incus project switch <project>'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export PROJECT_PATH="$PROJECTS_PATH/$PROJECT_NAME"
|
||||
|
||||
PROJECT_DEFINITION_PATH="$PROJECT_PATH/project.conf"
|
||||
|
||||
if [ ! -f "$PROJECT_DEFINITION_PATH" ]; then
|
||||
echo "ERROR: 'project.conf' not found $PROJECT_DEFINITION_PATH not found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$PROJECT_DEFINITION_PATH"
|
||||
|
||||
|
||||
export PRIMARY_SITE_DEFINITION_PATH="$SITES_PATH/$PRIMARY_DOMAIN/site.conf"
|
||||
|
||||
if [ -z "$PRIMARY_DOMAIN" ]; then
|
||||
echo "ERROR: The PRIMARY_DOMAIN is not specified. Check your remote definition at '$PRIMARY_SITE_DEFINITION_PATH'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SHASUM_OF_PRIMARY_DOMAIN="$(echo -n "$PRIMARY_DOMAIN" | sha256sum | awk '{print $1;}' )"
|
||||
export PRIMARY_DOMAIN_IDENTIFIER="${SHASUM_OF_PRIMARY_DOMAIN: -6}"
|
||||
|
||||
|
||||
# default values are already at regtest mode.
|
||||
if [ "$BITCOIN_CHAIN" = testnet ]; then
|
||||
|
||||
WWW_SSDATA_DISK_SIZE_GB=30
|
||||
WWW_BACKUP_DISK_SIZE_GB=30
|
||||
WWW_DOCKER_DISK_SIZE_GB=50
|
||||
|
||||
BTCPAYSERVER_SSDATA_DISK_SIZE_GB=30
|
||||
BTCPAYSERVER_BACKUP_DISK_SIZE_GB=30
|
||||
BTCPAYSERVER_DOCKER_DISK_SIZE_GB=100
|
||||
|
||||
elif [ "$BITCOIN_CHAIN" = mainnet ]; then
|
||||
|
||||
WWW_SSDATA_DISK_SIZE_GB=40
|
||||
WWW_BACKUP_DISK_SIZE_GB=40
|
||||
WWW_DOCKER_DISK_SIZE_GB=50
|
||||
|
||||
BTCPAYSERVER_SSDATA_DISK_SIZE_GB=30
|
||||
BTCPAYSERVER_BACKUP_DISK_SIZE_GB=30
|
||||
BTCPAYSERVER_DOCKER_DISK_SIZE_GB=300
|
||||
|
||||
fi
|
||||
|
||||
export WWW_SSDATA_DISK_SIZE_GB="$WWW_SSDATA_DISK_SIZE_GB"
|
||||
export WWW_BACKUP_DISK_SIZE_GB="$WWW_BACKUP_DISK_SIZE_GB"
|
||||
export WWW_DOCKER_DISK_SIZE_GB="$WWW_DOCKER_DISK_SIZE_GB"
|
||||
|
||||
export BTCPAYSERVER_SSDATA_DISK_SIZE_GB="$BTCPAYSERVER_SSDATA_DISK_SIZE_GB"
|
||||
export BTCPAYSERVER_BACKUP_DISK_SIZE_GB="$BTCPAYSERVER_BACKUP_DISK_SIZE_GB"
|
||||
export BTCPAYSERVER_DOCKER_DISK_SIZE_GB="$BTCPAYSERVER_DOCKER_DISK_SIZE_GB"
|
|
@ -0,0 +1,242 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -exu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# This script is meant to be executed on the management machine.
|
||||
# it reaches out to an SSH endpoint and provisions that machine
|
||||
# to use incus.
|
||||
|
||||
DATA_PLANE_MACVLAN_INTERFACE=
|
||||
DISK_TO_USE=
|
||||
|
||||
# override the remote name.
|
||||
REMOTE_NAME="${1:-}"
|
||||
if [ -z "$REMOTE_NAME" ]; then
|
||||
echo "ERROR: The remote name was not provided. Syntax is: 'ss-remote <remote_name> <remote01.domain.tld>'"
|
||||
echo " for example: 'ss-remote development clusterhost00.domain.tld"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
. ./deployment_defaults.sh
|
||||
|
||||
. ./base.sh
|
||||
|
||||
export REMOTE_PATH="$REMOTES_PATH/$REMOTE_NAME"
|
||||
REMOTE_DEFINITION="$REMOTE_PATH/remote.conf"
|
||||
export REMOTE_DEFINITION="$REMOTE_DEFINITION"
|
||||
|
||||
mkdir -p "$REMOTE_PATH"
|
||||
if [ ! -f "$REMOTE_DEFINITION" ]; then
|
||||
# stub out a remote.conf.
|
||||
cat >"$REMOTE_DEFINITION" <<EOL
|
||||
# https://www.sovereign-stack.org/ss-remote
|
||||
|
||||
# REGISTRY_URL=http://registry.domain.tld:5000
|
||||
|
||||
EOL
|
||||
|
||||
chmod 0744 "$REMOTE_DEFINITION"
|
||||
echo "We stubbed out a '$REMOTE_DEFINITION' file for you."
|
||||
echo "Use this file to customize your remote deployment;"
|
||||
echo "Check out 'https://www.sovereign-stack.org/ss-remote' for more information."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$REMOTE_DEFINITION"
|
||||
|
||||
if ! incus remote list | grep -q "$REMOTE_NAME"; then
|
||||
FQDN="${2:-}"
|
||||
|
||||
if [ -z "$FQDN" ]; then
|
||||
echo "ERROR: You MUST provide the FQDN of the remote host."
|
||||
exit
|
||||
fi
|
||||
|
||||
shift
|
||||
|
||||
if [ -z "$FQDN" ]; then
|
||||
echo "ERROR: The Fully Qualified Domain Name of the new remote member was not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# let's check to ensure we have SSH access to the specified host.
|
||||
if ! wait-for-it -t 5 "$FQDN:22"; then
|
||||
echo "ERROR: We can't get an SSH connection to '$FQDN:22'. Ensure you have the host set up correctly."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# grab any modifications from the command line.
|
||||
for i in "$@"; do
|
||||
case $i in
|
||||
--data-plane-interface=*)
|
||||
DATA_PLANE_MACVLAN_INTERFACE="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
--disk=*)
|
||||
DISK_TO_USE="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# first let's copy our ssh pubkey to the remote server so we don't have to login constantly.
|
||||
ssh-copy-id -i "$HOME/.ssh/id_rsa.pub" "ubuntu@$FQDN"
|
||||
|
||||
if [ -z "$DISK_TO_USE" ]; then
|
||||
if ! ssh "ubuntu@$FQDN" incus storage list -q | grep -q ss-base; then
|
||||
echo "INFO: It looks like the DISK_TO_USE has not been set. Enter it now."
|
||||
echo ""
|
||||
|
||||
ssh "ubuntu@$FQDN" lsblk --paths
|
||||
|
||||
echo "Please enter the disk or partition that Sovereign Stack will use to store data: "
|
||||
read -r DISK_TO_USE
|
||||
fi
|
||||
fi
|
||||
|
||||
else
|
||||
echo "ERROR: the remote already exists! You need to go delete your incus remote if you want to re-create your remote."
|
||||
echo " It's may also be helpful to reset/rename your remote path."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
#ssh "ubuntu@$FQDN" 'sudo echo "ubuntu ALL=(ALL) NOPASSWD: /bin/su - a" >> /etc/sudoers'
|
||||
|
||||
# if the disk is loop-based, then we assume the / path exists.
|
||||
if [ "$DISK_TO_USE" != loop ]; then
|
||||
# ensure we actually have that disk/partition on the system.
|
||||
if ! ssh "ubuntu@$FQDN" lsblk --paths | grep -q "$DISK_TO_USE"; then
|
||||
echo "ERROR: We could not findthe disk you specified. Please run this command again and supply a different disk."
|
||||
echo "NOTE: You can always specify on the command line by adding the '--disk=/dev/sdd', for example."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! command -v incus >/dev/null 2>&1; then
|
||||
if incus profile list --format csv | grep -q "$BASE_IMAGE_VM_NAME"; then
|
||||
incus profile delete "$BASE_IMAGE_VM_NAME"
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
if incus network list --format csv -q --project default | grep -q incusbr0; then
|
||||
incus network delete incusbr0 --project default
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
|
||||
if incus network list --format csv -q project default | grep -q incusbr1; then
|
||||
incus network delete incusbr1 --project default
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# install dependencies.
|
||||
ssh -t "ubuntu@$FQDN" 'sudo apt update && sudo apt upgrade -y && sudo apt install htop dnsutils nano zfsutils-linux -y'
|
||||
|
||||
REMOTE_SCRIPT_PATH="$REMOTE_HOME/install_incus.sh"
|
||||
scp ../install_incus.sh "ubuntu@$FQDN:$REMOTE_SCRIPT_PATH"
|
||||
ssh -t "ubuntu@$FQDN" "chmod +x $REMOTE_SCRIPT_PATH"
|
||||
ssh -t "ubuntu@$FQDN" "sudo bash -c $REMOTE_SCRIPT_PATH"
|
||||
ssh -t "ubuntu@$FQDN" "sudo adduser ubuntu incus-admin"
|
||||
|
||||
# install OVN for the project-specific bridge networks
|
||||
ssh -t "ubuntu@$FQDN" "sudo apt-get install -y ovn-host ovn-central && sudo ovs-vsctl set open_vswitch . external_ids:ovn-remote=unix:/var/run/ovn/ovnsb_db.sock external_ids:ovn-encap-type=geneve external_ids:ovn-encap-ip=127.0.0.1"
|
||||
|
||||
# if the user did not specify the interface, we just use whatever is used for the default route.
|
||||
if [ -z "$DATA_PLANE_MACVLAN_INTERFACE" ]; then
|
||||
DATA_PLANE_MACVLAN_INTERFACE="$(ssh ubuntu@"$FQDN" ip route | grep "default via" | awk '{print $5}')"
|
||||
fi
|
||||
|
||||
export DATA_PLANE_MACVLAN_INTERFACE="$DATA_PLANE_MACVLAN_INTERFACE"
|
||||
|
||||
MGMT_PLANE_IP="$(ssh ubuntu@"$FQDN" env | grep SSH_CONNECTION | cut -d " " -f 3)"
|
||||
IP_OF_MGMT_MACHINE="$(ssh ubuntu@"$FQDN" env | grep SSH_CLIENT | cut -d " " -f 1 )"
|
||||
IP_OF_MGMT_MACHINE="${IP_OF_MGMT_MACHINE#*=}"
|
||||
IP_OF_MGMT_MACHINE="$(echo "$IP_OF_MGMT_MACHINE" | cut -d: -f1)"
|
||||
|
||||
# run incus admin init on the remote server.
|
||||
cat <<EOF | ssh ubuntu@"$FQDN" incus admin init --preseed
|
||||
config:
|
||||
core.https_address: ${MGMT_PLANE_IP}:8443
|
||||
core.dns_address: ${MGMT_PLANE_IP}
|
||||
images.auto_update_interval: 15
|
||||
|
||||
networks:
|
||||
- name: incusbr0
|
||||
description: "ss-config,${DATA_PLANE_MACVLAN_INTERFACE:-error}"
|
||||
type: bridge
|
||||
config:
|
||||
ipv4.address: 10.9.9.1/24
|
||||
ipv4.dhcp.ranges: 10.9.9.10-10.9.9.127
|
||||
ipv4.nat: true
|
||||
ipv6.address: none
|
||||
dns.mode: managed
|
||||
- name: incusbr1
|
||||
description: "Non-natting bridge needed for ovn networks."
|
||||
type: bridge
|
||||
config:
|
||||
ipv4.address: 10.10.10.1/24
|
||||
ipv4.dhcp.ranges: 10.10.10.10-10.10.10.63
|
||||
ipv4.ovn.ranges: 10.10.10.64-10.10.10.254
|
||||
ipv4.nat: false
|
||||
ipv6.address: none
|
||||
profiles:
|
||||
- config: {}
|
||||
description: "default profile for sovereign-stack instances."
|
||||
devices:
|
||||
root:
|
||||
path: /
|
||||
pool: ss-base
|
||||
type: disk
|
||||
name: default
|
||||
EOF
|
||||
|
||||
ssh ubuntu@"$FQDN" incus project list -q >> /dev/null
|
||||
|
||||
# ensure the incus service is available over the network, then add a incus remote, then switch the active remote to it.
|
||||
if wait-for-it -t 20 "$FQDN:8443"; then
|
||||
# before we add the remote, we need a trust token from the incus server
|
||||
INCUS_CERT_TRUST_TOKEN=$(ssh ubuntu@"$FQDN" incus config trust add ss-mgmt | tail -n 1)
|
||||
|
||||
# now create a remote on your local incus client and switch to it.
|
||||
# the software will now target the new remote.
|
||||
incus remote add "$REMOTE_NAME" "$FQDN" --auth-type=tls --accept-certificate --token="$INCUS_CERT_TRUST_TOKEN"
|
||||
incus remote switch "$REMOTE_NAME"
|
||||
|
||||
echo "INFO: A new remote named '$REMOTE_NAME' has been created. Your incus client has been switched to it."
|
||||
else
|
||||
echo "ERROR: Could not detect the incus endpoint. Something went wrong."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# create the default storage pool if necessary
|
||||
if ! incus storage list --format csv | grep -q ss-base; then
|
||||
|
||||
if [ "$DISK_TO_USE" != loop ]; then
|
||||
# we omit putting a size here so, so incus will consume the entire disk if '/dev/sdb' or partition if '/dev/sdb1'.
|
||||
# TODO do some sanity/resource checking on DISK_TO_USE. Impelment full-disk encryption?
|
||||
incus storage create ss-base zfs source="$DISK_TO_USE"
|
||||
else
|
||||
# if a disk is the default 'loop', then we create a zfs storage pool
|
||||
# on top of the existing filesystem using a loop device, per incus docs
|
||||
incus storage create ss-base zfs
|
||||
fi
|
||||
|
||||
# # create the testnet/mainnet blocks/chainstate subvolumes.
|
||||
# for CHAIN in mainnet testnet; do
|
||||
# for DATA in blocks chainstate; do
|
||||
# if ! incus storage volume list ss-base | grep -q "$CHAIN-$DATA"; then
|
||||
# incus storage volume create ss-base "$CHAIN-$DATA" --type=filesystem
|
||||
# fi
|
||||
# done
|
||||
# done
|
||||
|
||||
fi
|
||||
|
||||
echo "INFO: completed remote.sh."
|
|
@ -0,0 +1,52 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
CURRENT_REMOTE="$(incus remote get-default)"
|
||||
DEPLOYMENT_STRING=
|
||||
|
||||
SS_ROOT_PATH="$HOME/ss"
|
||||
REMOTES_PATH="$SS_ROOT_PATH/remotes"
|
||||
PROJECTS_PATH="$SS_ROOT_PATH/projects"
|
||||
SITES_PATH="$SS_ROOT_PATH/sites"
|
||||
INCUS_CONFIG_PATH="$SS_ROOT_PATH/incus"
|
||||
SS_CACHE_PATH="$SS_ROOT_PATH/cache"
|
||||
|
||||
|
||||
|
||||
if echo "$CURRENT_REMOTE" | grep -q "prod"; then
|
||||
echo "WARNING: You are running a migration procedure on a production system."
|
||||
echo ""
|
||||
|
||||
|
||||
RESPONSE=
|
||||
read -r -p " Are you sure you want to continue (y) ": RESPONSE
|
||||
if [ "$RESPONSE" != "y" ]; then
|
||||
echo "STOPPING."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# check if there are any uncommited changes. It's dangerous to
|
||||
# alter production systems when you have commits to make or changes to stash.
|
||||
if git update-index --refresh | grep -q "needs update"; then
|
||||
echo "ERROR: You have uncommited changes! Better stash your work with 'git stash'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
. ./deployment_defaults.sh
|
||||
|
||||
export REMOTE_PATH="$REMOTES_PATH/$CURRENT_REMOTE"
|
||||
REMOTE_DEFINITION="$REMOTE_PATH/remote.conf"
|
||||
export REMOTE_DEFINITION="$REMOTE_DEFINITION"
|
||||
|
||||
# ensure the remote definition exists.
|
||||
if [ ! -f "$REMOTE_DEFINITION" ]; then
|
||||
echo "ERROR: The remote definition could not be found. You may need to run 'ss-remote'."
|
||||
echo "INFO: Consult https://www.sovereign-stack.org/ss-remote for more information."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$REMOTE_DEFINITION"
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
set -exu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
echo "WARNING: THIS SCRIPT NEEDS WORK"
|
||||
exit 1
|
||||
|
||||
PURGE_INCUS=false
|
||||
|
||||
# grab any modifications from the command line.
|
||||
for i in "$@"; do
|
||||
case $i in
|
||||
--purge)
|
||||
PURGE_INCUS=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unexpected option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
./down.sh
|
||||
|
||||
# these only get initialzed upon creation, so we MUST delete here so they get recreated.
|
||||
if incus profile list | grep -q "$BASE_IMAGE_VM_NAME"; then
|
||||
incus profile delete "$BASE_IMAGE_VM_NAME"
|
||||
fi
|
||||
|
||||
if incus image list | grep -q "$BASE_IMAGE_VM_NAME"; then
|
||||
incus image rm "$BASE_IMAGE_VM_NAME"
|
||||
fi
|
||||
|
||||
if incus image list | grep -q "$DOCKER_BASE_IMAGE_NAME"; then
|
||||
incus image rm "$DOCKER_BASE_IMAGE_NAME"
|
||||
fi
|
||||
|
||||
CURRENT_PROJECT="$(incus info | grep "project:" | awk '{print $2}')"
|
||||
if ! incus info | grep -q "project: default"; then
|
||||
incus project switch default
|
||||
incus project delete "$CURRENT_PROJECT"
|
||||
fi
|
||||
|
||||
|
||||
if [ "$PURGE_INCUS" = true ]; then
|
||||
|
||||
if incus profile show default | grep -q "root:"; then
|
||||
incus profile device remove default root
|
||||
fi
|
||||
|
||||
if incus profile show default| grep -q "eth0:"; then
|
||||
incus profile device remove default eth0
|
||||
fi
|
||||
|
||||
if incus network list --format csv -q --project default | grep -q incusbr0; then
|
||||
incus network delete incusbr0 --project default
|
||||
fi
|
||||
|
||||
if incus network list --format csv -q --project default | grep -q incusbr1; then
|
||||
incus network delete incusbr1 --project default
|
||||
fi
|
||||
|
||||
# # create the testnet/mainnet blocks/chainstate subvolumes.
|
||||
# for CHAIN in mainnet testnet; do
|
||||
# for DATA in blocks chainstate; do
|
||||
# if incus storage volume list ss-base | grep -q "$CHAIN-$DATA"; then
|
||||
# incus storage volume delete ss-base "$CHAIN-$DATA"
|
||||
# fi
|
||||
# done
|
||||
# done
|
||||
|
||||
echo "WARNING: ss-basae NOT DELETED. NEED TO TEST THIS SCRIPT"
|
||||
# if incus storage list --format csv | grep -q ss-base; then
|
||||
# incus storage delete ss-base
|
||||
# fi
|
||||
|
||||
CURRENT_REMOTE="$(incus remote get-default)"
|
||||
if ! incus remote get-default | grep -q "local"; then
|
||||
incus remote switch local
|
||||
incus remote remove "$CURRENT_REMOTE"
|
||||
|
||||
echo "INFO: The remote '$CURRENT_REMOTE' has been removed! You are now controlling your local instance."
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -exu
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
. ./deployment_defaults.sh
|
||||
|
||||
. ./remote_env.sh
|
||||
|
||||
echo "Global Settings:"
|
||||
|
||||
incus image list
|
||||
incus storage list
|
||||
|
||||
|
||||
echo
|
||||
echo
|
||||
|
||||
PROJECT_NAME="$(incus info | grep "project:" | awk '{print $2}')"
|
||||
export export="$PROJECT_NAME"
|
||||
export PROJECT_PATH="$PROJECTS_PATH/$PROJECT_NAME"
|
||||
|
||||
echo
|
||||
echo
|
||||
echo "Active project: $PROJECT_NAME"
|
||||
echo "----------------------------------------------------------"
|
||||
|
||||
echo " Networks:"
|
||||
incus network list
|
||||
|
||||
echo
|
||||
echo " Storage Volumes:"
|
||||
incus storage volume list ss-base
|
||||
|
||||
echo
|
||||
echo " Profiles:"
|
||||
incus profile list
|
||||
|
||||
|
||||
echo
|
||||
echo " Instances (VMs):"
|
||||
incus list
|
|
@ -0,0 +1,66 @@
|
|||
#!/bin/bash
|
||||
|
||||
# https://www.sovereign-stack.org/ss-down/
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
if incus remote get-default -q | grep -q "local"; then
|
||||
echo "ERROR: you are on the local incus remote. Nothing to take down"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SERVER_TO_STOP=
|
||||
OTHER_SITES_LIST=
|
||||
|
||||
# grab any modifications from the command line.
|
||||
for i in "$@"; do
|
||||
case $i in
|
||||
--server=*)
|
||||
SERVER_TO_STOP="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unexpected option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$SERVER_TO_STOP" ]; then
|
||||
echo "ERROR: you MUST specify a server to stop with '--server=www' for example."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
. ./deployment_defaults.sh
|
||||
|
||||
. ./remote_env.sh
|
||||
|
||||
. ./project_env.sh
|
||||
|
||||
# let's bring down services on the remote deployment if necessary.
|
||||
export DOMAIN_NAME="$PRIMARY_DOMAIN"
|
||||
export SITE_PATH="$SITES_PATH/$PRIMARY_DOMAIN"
|
||||
|
||||
source "$SITE_PATH/site.conf"
|
||||
source ./project/domain_env.sh
|
||||
|
||||
source ./domain_list.sh
|
||||
|
||||
if [ "$SERVER_TO_STOP" = www ]; then
|
||||
DOCKER_HOST="ssh://ubuntu@$PRIMARY_WWW_FQDN" ./project/www/stop_docker_stacks.sh
|
||||
fi
|
||||
|
||||
if [ "$SERVER_TO_STOP" = btcpayserver ]; then
|
||||
if wait-for-it -t 5 "$BTCPAY_SERVER_FQDN":22; then
|
||||
ssh "$BTCPAY_SERVER_FQDN" "bash -c $BTCPAY_SERVER_APPPATH/btcpay-down.sh"
|
||||
else
|
||||
echo "ERROR: the remote BTCPAY Server is not available on ssh."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$SERVER_TO_STOP" = lnplayserver ]; then
|
||||
DOCKER_HOST="ssh://ubuntu@$LNPLAY_SERVER_FQDN" ./project/lnplay/down.sh
|
||||
fi
|
|
@ -1,282 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
LXD_HOSTNAME="$1"
|
||||
|
||||
# generate the custom cloud-init file. Cloud init installs and configures sshd
|
||||
SSH_AUTHORIZED_KEY=$(<"$SSH_HOME/id_rsa.pub")
|
||||
eval "$(ssh-agent -s)"
|
||||
ssh-add "$SSH_HOME/id_rsa"
|
||||
export SSH_AUTHORIZED_KEY="$SSH_AUTHORIZED_KEY"
|
||||
|
||||
export FILENAME="$LXD_HOSTNAME.yml"
|
||||
mkdir -p "$PROJECT_PATH/cloud-init"
|
||||
YAML_PATH="$PROJECT_PATH/cloud-init/$FILENAME"
|
||||
|
||||
# If we are deploying the www, we attach the vm to the underlay via macvlan.
|
||||
cat > "$YAML_PATH" <<EOF
|
||||
config:
|
||||
EOF
|
||||
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" = www ]; then
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
limits.cpu: "${WWW_SERVER_CPU_COUNT}"
|
||||
limits.memory: "${WWW_SERVER_MEMORY_MB}MB"
|
||||
|
||||
EOF
|
||||
|
||||
else [ "$VIRTUAL_MACHINE" = btcpayserver ];
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
limits.cpu: "${BTCPAY_SERVER_CPU_COUNT}"
|
||||
limits.memory: "${BTCPAY_SERVER_MEMORY_MB}MB"
|
||||
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
# if VIRTUAL_MACHINE=sovereign-stack then we are building the base image.
|
||||
if [ "$LXD_HOSTNAME" = "sovereign-stack" ]; then
|
||||
# this is for the base image only...
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
user.vendor-data: |
|
||||
#cloud-config
|
||||
apt_mirror: http://us.archive.ubuntu.com/ubuntu/
|
||||
package_update: true
|
||||
package_upgrade: false
|
||||
package_reboot_if_required: false
|
||||
|
||||
preserve_hostname: false
|
||||
fqdn: sovereign-stack
|
||||
|
||||
packages:
|
||||
- curl
|
||||
- ssh-askpass
|
||||
- apt-transport-https
|
||||
- ca-certificates
|
||||
- gnupg-agent
|
||||
- software-properties-common
|
||||
- lsb-release
|
||||
- net-tools
|
||||
- htop
|
||||
- rsync
|
||||
- duplicity
|
||||
- sshfs
|
||||
- fswatch
|
||||
- jq
|
||||
- git
|
||||
- nano
|
||||
- wait-for-it
|
||||
- dnsutils
|
||||
- wget
|
||||
|
||||
groups:
|
||||
- docker
|
||||
|
||||
users:
|
||||
- name: ubuntu
|
||||
groups: docker
|
||||
shell: /bin/bash
|
||||
lock_passwd: false
|
||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||
ssh_authorized_keys:
|
||||
- ${SSH_AUTHORIZED_KEY}
|
||||
|
||||
|
||||
write_files:
|
||||
- path: /home/ubuntu/docker.asc
|
||||
content: |
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQINBFit2ioBEADhWpZ8/wvZ6hUTiXOwQHXMAlaFHcPH9hAtr4F1y2+OYdbtMuth
|
||||
lqqwp028AqyY+PRfVMtSYMbjuQuu5byyKR01BbqYhuS3jtqQmljZ/bJvXqnmiVXh
|
||||
38UuLa+z077PxyxQhu5BbqntTPQMfiyqEiU+BKbq2WmANUKQf+1AmZY/IruOXbnq
|
||||
L4C1+gJ8vfmXQt99npCaxEjaNRVYfOS8QcixNzHUYnb6emjlANyEVlZzeqo7XKl7
|
||||
UrwV5inawTSzWNvtjEjj4nJL8NsLwscpLPQUhTQ+7BbQXAwAmeHCUTQIvvWXqw0N
|
||||
cmhh4HgeQscQHYgOJjjDVfoY5MucvglbIgCqfzAHW9jxmRL4qbMZj+b1XoePEtht
|
||||
ku4bIQN1X5P07fNWzlgaRL5Z4POXDDZTlIQ/El58j9kp4bnWRCJW0lya+f8ocodo
|
||||
vZZ+Doi+fy4D5ZGrL4XEcIQP/Lv5uFyf+kQtl/94VFYVJOleAv8W92KdgDkhTcTD
|
||||
G7c0tIkVEKNUq48b3aQ64NOZQW7fVjfoKwEZdOqPE72Pa45jrZzvUFxSpdiNk2tZ
|
||||
XYukHjlxxEgBdC/J3cMMNRE1F4NCA3ApfV1Y7/hTeOnmDuDYwr9/obA8t016Yljj
|
||||
q5rdkywPf4JF8mXUW5eCN1vAFHxeg9ZWemhBtQmGxXnw9M+z6hWwc6ahmwARAQAB
|
||||
tCtEb2NrZXIgUmVsZWFzZSAoQ0UgZGViKSA8ZG9ja2VyQGRvY2tlci5jb20+iQI3
|
||||
BBMBCgAhBQJYrefAAhsvBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEI2BgDwO
|
||||
v82IsskP/iQZo68flDQmNvn8X5XTd6RRaUH33kXYXquT6NkHJciS7E2gTJmqvMqd
|
||||
tI4mNYHCSEYxI5qrcYV5YqX9P6+Ko+vozo4nseUQLPH/ATQ4qL0Zok+1jkag3Lgk
|
||||
jonyUf9bwtWxFp05HC3GMHPhhcUSexCxQLQvnFWXD2sWLKivHp2fT8QbRGeZ+d3m
|
||||
6fqcd5Fu7pxsqm0EUDK5NL+nPIgYhN+auTrhgzhK1CShfGccM/wfRlei9Utz6p9P
|
||||
XRKIlWnXtT4qNGZNTN0tR+NLG/6Bqd8OYBaFAUcue/w1VW6JQ2VGYZHnZu9S8LMc
|
||||
FYBa5Ig9PxwGQOgq6RDKDbV+PqTQT5EFMeR1mrjckk4DQJjbxeMZbiNMG5kGECA8
|
||||
g383P3elhn03WGbEEa4MNc3Z4+7c236QI3xWJfNPdUbXRaAwhy/6rTSFbzwKB0Jm
|
||||
ebwzQfwjQY6f55MiI/RqDCyuPj3r3jyVRkK86pQKBAJwFHyqj9KaKXMZjfVnowLh
|
||||
9svIGfNbGHpucATqREvUHuQbNnqkCx8VVhtYkhDb9fEP2xBu5VvHbR+3nfVhMut5
|
||||
G34Ct5RS7Jt6LIfFdtcn8CaSas/l1HbiGeRgc70X/9aYx/V/CEJv0lIe8gP6uDoW
|
||||
FPIZ7d6vH+Vro6xuWEGiuMaiznap2KhZmpkgfupyFmplh0s6knymuQINBFit2ioB
|
||||
EADneL9S9m4vhU3blaRjVUUyJ7b/qTjcSylvCH5XUE6R2k+ckEZjfAMZPLpO+/tF
|
||||
M2JIJMD4SifKuS3xck9KtZGCufGmcwiLQRzeHF7vJUKrLD5RTkNi23ydvWZgPjtx
|
||||
Q+DTT1Zcn7BrQFY6FgnRoUVIxwtdw1bMY/89rsFgS5wwuMESd3Q2RYgb7EOFOpnu
|
||||
w6da7WakWf4IhnF5nsNYGDVaIHzpiqCl+uTbf1epCjrOlIzkZ3Z3Yk5CM/TiFzPk
|
||||
z2lLz89cpD8U+NtCsfagWWfjd2U3jDapgH+7nQnCEWpROtzaKHG6lA3pXdix5zG8
|
||||
eRc6/0IbUSWvfjKxLLPfNeCS2pCL3IeEI5nothEEYdQH6szpLog79xB9dVnJyKJb
|
||||
VfxXnseoYqVrRz2VVbUI5Blwm6B40E3eGVfUQWiux54DspyVMMk41Mx7QJ3iynIa
|
||||
1N4ZAqVMAEruyXTRTxc9XW0tYhDMA/1GYvz0EmFpm8LzTHA6sFVtPm/ZlNCX6P1X
|
||||
zJwrv7DSQKD6GGlBQUX+OeEJ8tTkkf8QTJSPUdh8P8YxDFS5EOGAvhhpMBYD42kQ
|
||||
pqXjEC+XcycTvGI7impgv9PDY1RCC1zkBjKPa120rNhv/hkVk/YhuGoajoHyy4h7
|
||||
ZQopdcMtpN2dgmhEegny9JCSwxfQmQ0zK0g7m6SHiKMwjwARAQABiQQ+BBgBCAAJ
|
||||
BQJYrdoqAhsCAikJEI2BgDwOv82IwV0gBBkBCAAGBQJYrdoqAAoJEH6gqcPyc/zY
|
||||
1WAP/2wJ+R0gE6qsce3rjaIz58PJmc8goKrir5hnElWhPgbq7cYIsW5qiFyLhkdp
|
||||
YcMmhD9mRiPpQn6Ya2w3e3B8zfIVKipbMBnke/ytZ9M7qHmDCcjoiSmwEXN3wKYI
|
||||
mD9VHONsl/CG1rU9Isw1jtB5g1YxuBA7M/m36XN6x2u+NtNMDB9P56yc4gfsZVES
|
||||
KA9v+yY2/l45L8d/WUkUi0YXomn6hyBGI7JrBLq0CX37GEYP6O9rrKipfz73XfO7
|
||||
JIGzOKZlljb/D9RX/g7nRbCn+3EtH7xnk+TK/50euEKw8SMUg147sJTcpQmv6UzZ
|
||||
cM4JgL0HbHVCojV4C/plELwMddALOFeYQzTif6sMRPf+3DSj8frbInjChC3yOLy0
|
||||
6br92KFom17EIj2CAcoeq7UPhi2oouYBwPxh5ytdehJkoo+sN7RIWua6P2WSmon5
|
||||
U888cSylXC0+ADFdgLX9K2zrDVYUG1vo8CX0vzxFBaHwN6Px26fhIT1/hYUHQR1z
|
||||
VfNDcyQmXqkOnZvvoMfz/Q0s9BhFJ/zU6AgQbIZE/hm1spsfgvtsD1frZfygXJ9f
|
||||
irP+MSAI80xHSf91qSRZOj4Pl3ZJNbq4yYxv0b1pkMqeGdjdCYhLU+LZ4wbQmpCk
|
||||
SVe2prlLureigXtmZfkqevRz7FrIZiu9ky8wnCAPwC7/zmS18rgP/17bOtL4/iIz
|
||||
QhxAAoAMWVrGyJivSkjhSGx1uCojsWfsTAm11P7jsruIL61ZzMUVE2aM3Pmj5G+W
|
||||
9AcZ58Em+1WsVnAXdUR//bMmhyr8wL/G1YO1V3JEJTRdxsSxdYa4deGBBY/Adpsw
|
||||
24jxhOJR+lsJpqIUeb999+R8euDhRHG9eFO7DRu6weatUJ6suupoDTRWtr/4yGqe
|
||||
dKxV3qQhNLSnaAzqW/1nA3iUB4k7kCaKZxhdhDbClf9P37qaRW467BLCVO/coL3y
|
||||
Vm50dwdrNtKpMBh3ZpbB1uJvgi9mXtyBOMJ3v8RZeDzFiG8HdCtg9RvIt/AIFoHR
|
||||
H3S+U79NT6i0KPzLImDfs8T7RlpyuMc4Ufs8ggyg9v3Ae6cN3eQyxcK3w0cbBwsh
|
||||
/nQNfsA6uu+9H7NhbehBMhYnpNZyrHzCmzyXkauwRAqoCbGCNykTRwsur9gS41TQ
|
||||
M8ssD1jFheOJf3hODnkKU+HKjvMROl1DK7zdmLdNzA1cvtZH/nCC9KPj1z8QC47S
|
||||
xx+dTZSx4ONAhwbS/LN3PoKtn8LPjY9NP9uDWI+TWYquS2U+KHDrBDlsgozDbs/O
|
||||
jCxcpDzNmXpWQHEtHU7649OXHP7UeNST1mCUCH5qdank0V1iejF6/CfTFU4MfcrG
|
||||
YT90qFF93M3v01BbxP+EIY2/9tiIPbrd
|
||||
=0YYh
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
- path: /etc/ssh/ssh_config
|
||||
content: |
|
||||
Port 22
|
||||
ListenAddress 0.0.0.0
|
||||
Protocol 2
|
||||
ChallengeResponseAuthentication no
|
||||
PasswordAuthentication no
|
||||
UsePAM no
|
||||
LogLevel INFO
|
||||
|
||||
- path: /etc/docker/daemon.json
|
||||
content: |
|
||||
{
|
||||
"registry-mirrors": [
|
||||
"${REGISTRY_URL}"
|
||||
]
|
||||
}
|
||||
|
||||
runcmd:
|
||||
- cat /home/ubuntu/docker.asc | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
||||
- sudo rm /home/ubuntu/docker.asc
|
||||
- echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install -y docker-ce docker-ce-cli containerd.io
|
||||
- echo "alias ll='ls -lah'" >> /home/ubuntu/.bash_profile
|
||||
- echo "alias bitcoin-cli='bitcoin-cli.sh \$@'" >> /home/ubuntu/.bash_profile
|
||||
- echo "alias lightning-cli='bitcoin-lightning-cli.sh \$@'" >> /home/ubuntu/.bash_profile
|
||||
- sudo curl -s -L "https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
- sudo chmod +x /usr/local/bin/docker-compose
|
||||
- sudo apt-get install -y openssh-server
|
||||
|
||||
|
||||
EOF
|
||||
|
||||
else
|
||||
# all other machines.
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
user.vendor-data: |
|
||||
#cloud-config
|
||||
apt_mirror: http://us.archive.ubuntu.com/ubuntu/
|
||||
package_update: false
|
||||
package_upgrade: false
|
||||
package_reboot_if_required: false
|
||||
|
||||
preserve_hostname: false
|
||||
fqdn: ${FQDN}
|
||||
|
||||
user.network-config: |
|
||||
version: 2
|
||||
ethernets:
|
||||
enp5s0:
|
||||
dhcp4: true
|
||||
match:
|
||||
macaddress: ${MAC_ADDRESS_TO_PROVISION}
|
||||
set-name: enp5s0
|
||||
|
||||
enp6s0:
|
||||
dhcp4: false
|
||||
EOF
|
||||
|
||||
if [[ "$LXD_HOSTNAME" = $WWW_HOSTNAME-* ]]; then
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
addresses: [10.139.144.5/24]
|
||||
nameservers:
|
||||
addresses: [10.139.144.1]
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [[ "$LXD_HOSTNAME" = $BTCPAY_HOSTNAME-* ]]; then
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
addresses: [10.139.144.10/24]
|
||||
nameservers:
|
||||
addresses: [10.139.144.1]
|
||||
|
||||
EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
# If we are deploying the www, we attach the vm to the underlay via macvlan.
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
description: Default LXD profile for ${FILENAME}
|
||||
devices:
|
||||
root:
|
||||
path: /
|
||||
pool: sovereign-stack
|
||||
type: disk
|
||||
config:
|
||||
source: cloud-init:config
|
||||
type: disk
|
||||
EOF
|
||||
|
||||
# Stub out the network piece for the base image.
|
||||
if [ "$LXD_HOSTNAME" = sovereign-stack ] ; then
|
||||
|
||||
# If we are deploying the www, we attach the vm to the underlay via macvlan.
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
enp5s0:
|
||||
name: enp5s0
|
||||
nictype: macvlan
|
||||
parent: ${DATA_PLANE_MACVLAN_INTERFACE}
|
||||
type: nic
|
||||
name: ${FILENAME}
|
||||
EOF
|
||||
|
||||
else
|
||||
# If we are deploying the www, we attach the vm to the underlay via macvlan.
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
enp5s0:
|
||||
nictype: macvlan
|
||||
parent: ${DATA_PLANE_MACVLAN_INTERFACE}
|
||||
type: nic
|
||||
enp6s0:
|
||||
name: enp6s0
|
||||
network: lxdbrSS
|
||||
type: nic
|
||||
|
||||
name: ${FILENAME}
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
# let's create a profile for the BCM TYPE-1 VMs. This is per VM.
|
||||
if ! lxc profile list --format csv | grep -q "$LXD_HOSTNAME"; then
|
||||
lxc profile create "$LXD_HOSTNAME"
|
||||
|
||||
# configure the profile with our generated cloud-init.yml file.
|
||||
cat "$YAML_PATH" | lxc profile edit "$LXD_HOSTNAME"
|
||||
|
||||
fi
|
|
@ -0,0 +1,338 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -exu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
VIRTUAL_MACHINE=base
|
||||
INCUS_HOSTNAME=
|
||||
SSDATA_VOLUME_NAME=
|
||||
BACKUP_VOLUME_NAME=
|
||||
|
||||
# grab any modifications from the command line.
|
||||
for i in "$@"; do
|
||||
case $i in
|
||||
--incus-hostname=*)
|
||||
INCUS_HOSTNAME="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
--vm=*)
|
||||
VIRTUAL_MACHINE="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
--ss-volume-name=*)
|
||||
SSDATA_VOLUME_NAME="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
--backup-volume-name=*)
|
||||
BACKUP_VOLUME_NAME="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unexpected option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# generate the custom cloud-init file. Cloud init installs and configures sshd
|
||||
SSH_AUTHORIZED_KEY=$(<"$SSH_PUBKEY_PATH")
|
||||
eval "$(ssh-agent -s)" > /dev/null
|
||||
ssh-add "$SSH_HOME/id_rsa" > /dev/null
|
||||
export SSH_AUTHORIZED_KEY="$SSH_AUTHORIZED_KEY"
|
||||
|
||||
export FILENAME="$INCUS_HOSTNAME.yml"
|
||||
mkdir -p "$PROJECT_PATH/cloud-init"
|
||||
YAML_PATH="$PROJECT_PATH/cloud-init/$FILENAME"
|
||||
|
||||
# If we are deploying the www, we attach the vm to the underlay via macvlan.
|
||||
cat > "$YAML_PATH" <<EOF
|
||||
config:
|
||||
EOF
|
||||
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" = base ]; then
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
limits.cpu: 4
|
||||
limits.memory: 4096MB
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" = www ]; then
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
limits.cpu: "${WWW_SERVER_CPU_COUNT}"
|
||||
limits.memory: "${WWW_SERVER_MEMORY_MB}MB"
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" = btcpayserver ]; then
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
limits.cpu: "${BTCPAY_SERVER_CPU_COUNT}"
|
||||
limits.memory: "${BTCPAY_SERVER_MEMORY_MB}MB"
|
||||
|
||||
EOF
|
||||
|
||||
elif [ "$VIRTUAL_MACHINE" = lnplayserver ]; then
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
limits.cpu: "${LNPLAY_SERVER_CPU_COUNT}"
|
||||
limits.memory: "${LNPLAY_SERVER_MEMORY_MB}MB"
|
||||
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
# if VIRTUAL_MACHINE=base, then we doing the base image.
|
||||
if [ "$VIRTUAL_MACHINE" = base ]; then
|
||||
# this is for the base image only...
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
user.vendor-data: |
|
||||
#cloud-config
|
||||
package_update: true
|
||||
package_upgrade: false
|
||||
package_reboot_if_required: false
|
||||
|
||||
preserve_hostname: false
|
||||
fqdn: ${BASE_IMAGE_VM_NAME}
|
||||
|
||||
packages:
|
||||
- curl
|
||||
- ssh-askpass
|
||||
- apt-transport-https
|
||||
- ca-certificates
|
||||
- gnupg-agent
|
||||
- software-properties-common
|
||||
- lsb-release
|
||||
- net-tools
|
||||
- htop
|
||||
- rsync
|
||||
- duplicity
|
||||
- sshfs
|
||||
- fswatch
|
||||
- jq
|
||||
- git
|
||||
- nano
|
||||
- wait-for-it
|
||||
- dnsutils
|
||||
- wget
|
||||
|
||||
groups:
|
||||
- docker
|
||||
|
||||
users:
|
||||
- name: ubuntu
|
||||
groups: docker
|
||||
shell: /bin/bash
|
||||
lock_passwd: false
|
||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||
ssh_authorized_keys:
|
||||
- ${SSH_AUTHORIZED_KEY}
|
||||
|
||||
EOF
|
||||
|
||||
if [ "$REGISTRY_URL" != "https://index.docker.io/v1" ]; then
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
write_files:
|
||||
- path: /etc/docker/daemon.json
|
||||
permissions: 0644
|
||||
owner: root
|
||||
content: |
|
||||
{
|
||||
"registry-mirrors": [
|
||||
"${REGISTRY_URL}"
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" = base ]; then
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
runcmd:
|
||||
- sudo mkdir -m 0755 -p /etc/apt/keyrings
|
||||
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
- echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu jammy stable" | sudo tee /etc/apt/sources.list.d/docker.list
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
- sudo DEBIAN_FRONTEND=noninteractive apt-get install -y openssh-server
|
||||
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" != base ]; then
|
||||
# all other machines that are not the base image
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
user.vendor-data: |
|
||||
#cloud-config
|
||||
apt_mirror: http://us.archive.ubuntu.com/ubuntu/
|
||||
package_update: false
|
||||
package_upgrade: false
|
||||
package_reboot_if_required: false
|
||||
|
||||
preserve_hostname: true
|
||||
fqdn: ${FQDN}
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" = www ] || [ "$VIRTUAL_MACHINE" = btcpayserver ]; then
|
||||
# all other machines that are not the base image
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
resize_rootfs: false
|
||||
disk_setup:
|
||||
/dev/sdb:
|
||||
table_type: 'gpt'
|
||||
layout: true
|
||||
overwrite: false
|
||||
|
||||
fs_setup:
|
||||
- label: docker-data
|
||||
filesystem: 'ext4'
|
||||
device: '/dev/sdb1'
|
||||
overwrite: false
|
||||
|
||||
mounts:
|
||||
- [ sdb, /var/lib/docker ]
|
||||
|
||||
mount_default_fields: [ None, None, "auto", "defaults,nofail", "0", "2" ]
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" != base ]; then
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
user.network-config: |
|
||||
version: 2
|
||||
ethernets:
|
||||
enp5s0:
|
||||
dhcp4: true
|
||||
dhcp4-overrides:
|
||||
route-metric: 50
|
||||
match:
|
||||
macaddress: ${MAC_ADDRESS_TO_PROVISION}
|
||||
set-name: enp5s0
|
||||
EOF
|
||||
fi
|
||||
|
||||
# TODO try to get DHCP working reliably.
|
||||
if [ "$VIRTUAL_MACHINE" = btcpayserver ]; then
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
enp6s0:
|
||||
addresses:
|
||||
- 10.10.10.66/24
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" = www ]; then
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
enp6s0:
|
||||
addresses:
|
||||
- 10.10.10.65/24
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
# All profiles get a root disk and cloud-init config.
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
description: Default incus profile for ${FILENAME}
|
||||
devices:
|
||||
|
||||
EOF
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" = lnplayserver ]; then
|
||||
# All profiles get a root disk and cloud-init config.
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
root:
|
||||
path: /
|
||||
pool: ss-base
|
||||
type: disk
|
||||
size: 20GiB
|
||||
EOF
|
||||
else
|
||||
# All profiles get a root disk and cloud-init config.
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
root:
|
||||
path: /
|
||||
pool: ss-base
|
||||
type: disk
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
config:
|
||||
source: cloud-init:config
|
||||
type: disk
|
||||
EOF
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" = www ] || [ "$VIRTUAL_MACHINE" = btcpayserver ]; then
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
ss-data:
|
||||
path: ${REMOTE_DATA_PATH}
|
||||
pool: ss-base
|
||||
source: ${SSDATA_VOLUME_NAME}
|
||||
type: disk
|
||||
ss-backup:
|
||||
path: ${REMOTE_BACKUP_PATH}
|
||||
pool: ss-base
|
||||
source: ${BACKUP_VOLUME_NAME}
|
||||
type: disk
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Stub out the network piece for the base image.
|
||||
if [ "$VIRTUAL_MACHINE" = base ]; then
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
enp6s0:
|
||||
name: enp6s0
|
||||
network: incusbr0
|
||||
type: nic
|
||||
name: ${FILENAME}
|
||||
EOF
|
||||
|
||||
else
|
||||
|
||||
# all other vms attach to the network underlay
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
enp5s0:
|
||||
nictype: macvlan
|
||||
parent: ${DATA_PLANE_MACVLAN_INTERFACE}
|
||||
type: nic
|
||||
EOF
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" = www ] || [ "$VIRTUAL_MACHINE" = btcpayserver ]; then
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
enp6s0:
|
||||
name: enp6s0
|
||||
network: ss-ovn
|
||||
type: nic
|
||||
EOF
|
||||
fi
|
||||
|
||||
cat >> "$YAML_PATH" <<EOF
|
||||
name: ${PRIMARY_DOMAIN}
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" = base ]; then
|
||||
if ! incus profile list --format csv --project default | grep -q "$INCUS_HOSTNAME"; then
|
||||
incus profile create "$INCUS_HOSTNAME" --project default
|
||||
fi
|
||||
|
||||
# configure the profile with our generated cloud-init.yml file.
|
||||
incus profile edit "$INCUS_HOSTNAME" --project default < "$YAML_PATH"
|
||||
else
|
||||
if ! incus profile list --format csv | grep -q "$INCUS_HOSTNAME"; then
|
||||
incus profile create "$INCUS_HOSTNAME"
|
||||
fi
|
||||
|
||||
# configure the profile with our generated cloud-init.yml file.
|
||||
incus profile edit "$INCUS_HOSTNAME" < "$YAML_PATH"
|
||||
fi
|
|
@ -0,0 +1,478 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -exu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# check to ensure dependencies are met.
|
||||
for cmd in wait-for-it dig rsync sshfs incus; do
|
||||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||
echo "This script requires \"${cmd}\" to be installed. Please run 'install.sh'."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# do a spot check; if we are on production warn.
|
||||
if incus remote get-default | grep -q "production"; then
|
||||
echo "WARNING: You are running command against a production system!"
|
||||
echo ""
|
||||
|
||||
# check if there are any uncommited changes. It's dangerous to
|
||||
# alter production systems when you have commits to make or changes to stash.
|
||||
if git update-index --refresh | grep -q "needs update"; then
|
||||
echo "ERROR: You have uncommited changes! You MUST commit or stash all changes to continue."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RESPONSE=
|
||||
read -r -p " Are you sure you want to continue (y) ": RESPONSE
|
||||
if [ "$RESPONSE" != "y" ]; then
|
||||
echo "STOPPING."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
OTHER_SITES_LIST=
|
||||
PRIMARY_DOMAIN=
|
||||
RUN_CERT_RENEWAL=true
|
||||
SKIP_BASE_IMAGE_CREATION=false
|
||||
RESTORE_WWW=false
|
||||
RESTORE_CERTS=false
|
||||
BACKUP_CERTS=true
|
||||
BACKUP_BTCPAY=true
|
||||
SKIP_BTCPAY_SERVER=false
|
||||
SKIP_WWW_SERVER=false
|
||||
SKIP_LNPLAY_SERVER=false
|
||||
BACKUP_BTCPAY_ARCHIVE_PATH=
|
||||
RESTORE_BTCPAY=false
|
||||
UPDATE_BTCPAY=false
|
||||
REMOTE_NAME="$(incus remote get-default)"
|
||||
USER_SAYS_YES=false
|
||||
|
||||
WWW_SERVER_MAC_ADDRESS=
|
||||
BTCPAY_SERVER_MAC_ADDRESS=
|
||||
LNPLAY_SERVER_MAC_ADDRESS=
|
||||
LNPLAY_ENV_PATH=
|
||||
LNPLAY_VM_EXPIRATION_DATE=
|
||||
LNPLAY_ORDER_ID=
|
||||
|
||||
# grab any modifications from the command line.
|
||||
for i in "$@"; do
|
||||
case $i in
|
||||
--restore-certs)
|
||||
RESTORE_CERTS=true
|
||||
shift
|
||||
;;
|
||||
--restore-wwwserver)
|
||||
RESTORE_WWW=true
|
||||
shift
|
||||
;;
|
||||
--restore-btcpay)
|
||||
RESTORE_BTCPAY=true
|
||||
shift
|
||||
;;
|
||||
--skip-btcpayserver)
|
||||
SKIP_BTCPAY_SERVER=true
|
||||
shift
|
||||
;;
|
||||
--skip-wwwserver)
|
||||
SKIP_WWW_SERVER=true
|
||||
shift
|
||||
;;
|
||||
--skip-lnplayserver)
|
||||
SKIP_LNPLAY_SERVER=true
|
||||
shift
|
||||
;;
|
||||
--backup-btcpayserver)
|
||||
BACKUP_BTCPAY=true
|
||||
shift
|
||||
;;
|
||||
--backup-archive-path=*)
|
||||
BACKUP_BTCPAY_ARCHIVE_PATH="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
--update-btcpay)
|
||||
UPDATE_BTCPAY=true
|
||||
shift
|
||||
;;
|
||||
--skip-base-image)
|
||||
SKIP_BASE_IMAGE_CREATION=true
|
||||
shift
|
||||
;;
|
||||
--no-cert-renew)
|
||||
RUN_CERT_RENEWAL=false
|
||||
shift
|
||||
;;
|
||||
--lnplay-env-path=*)
|
||||
LNPLAY_ENV_PATH="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
--vm-expiration-date=*)
|
||||
LNPLAY_VM_EXPIRATION_DATE="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
--order-id=*)
|
||||
LNPLAY_ORDER_ID="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
-y)
|
||||
USER_SAYS_YES=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unexpected option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
if [ "$RESTORE_BTCPAY" = true ] && [ -z "$BACKUP_BTCPAY_ARCHIVE_PATH" ]; then
|
||||
echo "ERROR: Use the '--backup-archive-path=/path/to/btcpay/archive.tar.gz' option when restoring btcpay server."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$RESTORE_BTCPAY" = true ] && [ ! -f "$BACKUP_BTCPAY_ARCHIVE_PATH" ]; then
|
||||
echo "ERROR: The backup archive path you specified DOES NOT exist!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
. ./remote_env.sh
|
||||
|
||||
export REGISTRY_DOCKER_IMAGE="registry:2"
|
||||
export BACKUP_CERTS="$BACKUP_CERTS"
|
||||
export RESTORE_BTCPAY="$RESTORE_BTCPAY"
|
||||
export RESTORE_WWW="$RESTORE_WWW"
|
||||
export BACKUP_BTCPAY="$BACKUP_BTCPAY"
|
||||
export RUN_CERT_RENEWAL="$RUN_CERT_RENEWAL"
|
||||
export REMOTE_NAME="$REMOTE_NAME"
|
||||
export REMOTE_PATH="$REMOTES_PATH/$REMOTE_NAME"
|
||||
export USER_SAYS_YES="$USER_SAYS_YES"
|
||||
export BACKUP_BTCPAY_ARCHIVE_PATH="$BACKUP_BTCPAY_ARCHIVE_PATH"
|
||||
export RESTORE_CERTS="$RESTORE_CERTS"
|
||||
|
||||
# todo convert this to Trezor-T
|
||||
SSH_PUBKEY_PATH="$SSH_HOME/id_rsa.pub"
|
||||
export SSH_PUBKEY_PATH="$SSH_PUBKEY_PATH"
|
||||
|
||||
# ensure our remote path is created.
|
||||
mkdir -p "$REMOTE_PATH"
|
||||
|
||||
REMOTE_DEFINITION="$REMOTE_PATH/remote.conf"
|
||||
if [ ! -f "$REMOTE_DEFINITION" ]; then
|
||||
echo "ERROR: The remote definition could not be found. You may need to re-run 'ss-remote'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export REMOTE_DEFINITION="$REMOTE_DEFINITION"
|
||||
source "$REMOTE_DEFINITION"
|
||||
|
||||
|
||||
# this is our password generation mechanism. Relying on GPG for secure password generation
|
||||
# TODO see if this is a secure way to do it.
|
||||
function new_pass {
|
||||
gpg --gen-random --armor 1 25
|
||||
}
|
||||
|
||||
function stub_site_definition {
|
||||
mkdir -p "$SITE_PATH" "$PROJECT_PATH/sites"
|
||||
|
||||
# create a symlink from the PROJECT_PATH/sites/DOMAIN_NAME to the ss-sites/domain name
|
||||
DOMAIN_SYMLINK_PATH="$PROJECT_PATH/sites/$DOMAIN_NAME"
|
||||
if [ ! -L "$DOMAIN_SYMLINK_PATH" ]; then
|
||||
ln -r -s "$SITE_PATH" "$DOMAIN_SYMLINK_PATH"
|
||||
fi
|
||||
|
||||
if [ ! -f "$SITE_PATH/site.conf" ]; then
|
||||
# check to see if the enf file exists. exist if not.
|
||||
SITE_DEFINITION_PATH="$SITE_PATH/site.conf"
|
||||
if [ ! -f "$SITE_DEFINITION_PATH" ]; then
|
||||
|
||||
# stub out a site.conf with new passwords.
|
||||
cat >"$SITE_DEFINITION_PATH" <<EOL
|
||||
# https://www.sovereign-stack.org/ss-up/#siteconf
|
||||
|
||||
DOMAIN_NAME="${DOMAIN_NAME}"
|
||||
# BTCPAY_ALT_NAMES="tip,store,pay,send"
|
||||
SITE_LANGUAGE_CODES="en"
|
||||
DUPLICITY_BACKUP_PASSPHRASE="$(new_pass)"
|
||||
DEPLOY_GHOST=true
|
||||
|
||||
DEPLOY_NEXTCLOUD=false
|
||||
DEPLOY_NOSTR=false
|
||||
NOSTR_ACCOUNT_PUBKEY=
|
||||
DEPLOY_GITEA=false
|
||||
GHOST_MYSQL_PASSWORD="$(new_pass)"
|
||||
GHOST_MYSQL_ROOT_PASSWORD="$(new_pass)"
|
||||
NEXTCLOUD_MYSQL_PASSWORD="$(new_pass)"
|
||||
NEXTCLOUD_MYSQL_ROOT_PASSWORD="$(new_pass)"
|
||||
GITEA_MYSQL_PASSWORD="$(new_pass)"
|
||||
GITEA_MYSQL_ROOT_PASSWORD="$(new_pass)"
|
||||
|
||||
|
||||
#GHOST_DEPLOY_SMTP=true
|
||||
#MAILGUN_FROM_ADDRESS=false
|
||||
#MAILGUN_SMTP_USERNAME=
|
||||
#MAILGUN_SMTP_PASSWORD=
|
||||
|
||||
EOL
|
||||
|
||||
chmod 0744 "$SITE_DEFINITION_PATH"
|
||||
echo "INFO: we stubbed a new site.conf for you at '$SITE_DEFINITION_PATH'. Go update it!"
|
||||
exit 1
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
PROJECT_NAME="$(incus info | grep "project:" | awk '{print $2}')"
|
||||
export PROJECT_NAME="$PROJECT_NAME"
|
||||
export PROJECT_PATH="$PROJECTS_PATH/$PROJECT_NAME"
|
||||
export SKIP_BTCPAY_SERVER="$SKIP_BTCPAY_SERVER"
|
||||
export SKIP_WWW_SERVER="$SKIP_WWW_SERVER"
|
||||
export SKIP_LNPLAY_SERVER="$SKIP_LNPLAY_SERVER"
|
||||
|
||||
|
||||
mkdir -p "$PROJECT_PATH" "$REMOTE_PATH/projects"
|
||||
|
||||
# create a symlink from ./remotepath/projects/project
|
||||
PROJECT_SYMLINK="$REMOTE_PATH/projects/$PROJECT_NAME"
|
||||
if [ ! -L "$PROJECT_SYMLINK" ]; then
|
||||
ln -r -s "$PROJECT_PATH" "$PROJECT_SYMLINK"
|
||||
fi
|
||||
|
||||
# check to see if the enf file exists. exist if not.
|
||||
PROJECT_DEFINITION_PATH="$PROJECT_PATH/project.conf"
|
||||
if [ ! -f "$PROJECT_DEFINITION_PATH" ]; then
|
||||
|
||||
# stub out a project.conf
|
||||
cat >"$PROJECT_DEFINITION_PATH" <<EOL
|
||||
# see https://www.sovereign-stack.org/ss-up/#projectconf for more info.
|
||||
|
||||
PRIMARY_DOMAIN="domain0.tld"
|
||||
# OTHER_SITES_LIST="domain1.tld,domain2.tld,domain3.tld"
|
||||
|
||||
WWW_SERVER_MAC_ADDRESS=
|
||||
# WWW_SSDATA_DISK_SIZE_GB=100
|
||||
# WWW_SERVER_CPU_COUNT="6"
|
||||
# WWW_SERVER_MEMORY_MB="4096"
|
||||
|
||||
BTCPAY_SERVER_MAC_ADDRESS=
|
||||
# BTCPAY_SERVER_CPU_COUNT="4"
|
||||
# BTCPAY_SERVER_MEMORY_MB="4096"
|
||||
|
||||
LNPLAY_SERVER_MAC_ADDRESS=
|
||||
# LNPLAY_SERVER_CPU_COUNT="4"
|
||||
# LNPLAY_SERVER_MEMORY_MB="4096"
|
||||
|
||||
# BITCOIN_CHAIN=mainnet
|
||||
|
||||
EOL
|
||||
|
||||
chmod 0744 "$PROJECT_DEFINITION_PATH"
|
||||
echo "INFO: we stubbed a new project.conf for you at '$PROJECT_DEFINITION_PATH'. Go update it!"
|
||||
echo "INFO: Learn more at https://www.sovereign-stack.org/ss-up/"
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
. ./project_env.sh
|
||||
|
||||
if [ -z "$PRIMARY_DOMAIN" ]; then
|
||||
echo "ERROR: The PRIMARY_DOMAIN is not specified. Check your project.conf."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source ./domain_list.sh
|
||||
|
||||
# let's provision our primary domain first.
|
||||
export DOMAIN_NAME="$PRIMARY_DOMAIN"
|
||||
export PRIMARY_DOMAIN="$PRIMARY_DOMAIN"
|
||||
export BITCOIN_CHAIN="$BITCOIN_CHAIN"
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
export PRIMARY_SITE_PATH="$SITES_PATH/$PRIMARY_DOMAIN"
|
||||
|
||||
stub_site_definition
|
||||
|
||||
# bring the VMs up under the primary domain name.
|
||||
|
||||
export UPDATE_BTCPAY="$UPDATE_BTCPAY"
|
||||
|
||||
# iterate over all our server endpoints and provision them if needed.
|
||||
# www
|
||||
VPS_HOSTNAME=
|
||||
|
||||
. ./base.sh
|
||||
if ! incus image list --format csv | grep -q "$DOCKER_BASE_IMAGE_NAME"; then
|
||||
# create the incus base image.
|
||||
if [ "$SKIP_BASE_IMAGE_CREATION" = false ]; then
|
||||
./create_base.sh
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
VMS_TO_PROVISION=""
|
||||
if [ -n "$WWW_SERVER_MAC_ADDRESS" ] && [ "$SKIP_WWW_SERVER" = false ]; then
|
||||
VMS_TO_PROVISION="www"
|
||||
fi
|
||||
|
||||
if [ -n "$BTCPAY_SERVER_MAC_ADDRESS" ] && [ "$SKIP_BTCPAY_SERVER" = false ]; then
|
||||
VMS_TO_PROVISION="$VMS_TO_PROVISION btcpayserver"
|
||||
fi
|
||||
|
||||
if [ -n "$LNPLAY_SERVER_MAC_ADDRESS" ] || [ "$SKIP_LNPLAY_SERVER" = false ]; then
|
||||
VMS_TO_PROVISION="$VMS_TO_PROVISION lnplayserver"
|
||||
fi
|
||||
|
||||
for VIRTUAL_MACHINE in $VMS_TO_PROVISION; do
|
||||
|
||||
export VIRTUAL_MACHINE="$VIRTUAL_MACHINE"
|
||||
FQDN=
|
||||
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
|
||||
source "$SITE_PATH/site.conf"
|
||||
source ./project/domain_env.sh
|
||||
|
||||
# VALIDATE THE INPUT from the ENVFILE
|
||||
if [ -z "$DOMAIN_NAME" ]; then
|
||||
echo "ERROR: DOMAIN_NAME not specified in your site.conf."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Goal is to get the macvlan interface.
|
||||
INCUS_SS_CONFIG_LINE=
|
||||
if incus network list --format csv --project default | grep incusbr0 | grep -q "ss-config"; then
|
||||
INCUS_SS_CONFIG_LINE="$(incus network list --format csv --project default | grep incusbr0 | grep ss-config)"
|
||||
fi
|
||||
|
||||
if [ -z "$INCUS_SS_CONFIG_LINE" ]; then
|
||||
echo "ERROR: the MACVLAN interface has not been specified. You may need to run 'ss-remote' again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CONFIG_ITEMS="$(echo "$INCUS_SS_CONFIG_LINE" | awk -F'"' '{print $2}')"
|
||||
DATA_PLANE_MACVLAN_INTERFACE="$(echo "$CONFIG_ITEMS" | cut -d ',' -f2)"
|
||||
export DATA_PLANE_MACVLAN_INTERFACE="$DATA_PLANE_MACVLAN_INTERFACE"
|
||||
|
||||
|
||||
# Now let's switch to the new project to ensure new resources are created under the project scope.
|
||||
if ! incus info | grep "project:" | grep -q "$PROJECT_NAME"; then
|
||||
incus project switch "$PROJECT_NAME"
|
||||
fi
|
||||
|
||||
# check if the OVN network exists in this project.
|
||||
if ! incus network list | grep -q "ss-ovn"; then
|
||||
incus network create ss-ovn --type=ovn network=incusbr1 ipv6.address=none
|
||||
fi
|
||||
|
||||
export MAC_ADDRESS_TO_PROVISION=
|
||||
export VPS_HOSTNAME="$VPS_HOSTNAME"
|
||||
export FQDN="$VPS_HOSTNAME.$DOMAIN_NAME"
|
||||
|
||||
if [ "$VIRTUAL_MACHINE" = www ] && [ -n "$WWW_SERVER_MAC_ADDRESS" ]; then
|
||||
FQDN="$WWW_HOSTNAME.$DOMAIN_NAME"
|
||||
VPS_HOSTNAME="$WWW_HOSTNAME"
|
||||
MAC_ADDRESS_TO_PROVISION="$WWW_SERVER_MAC_ADDRESS"
|
||||
|
||||
elif [ "$VIRTUAL_MACHINE" = btcpayserver ] && [ -n "$BTCPAY_SERVER_MAC_ADDRESS" ]; then
|
||||
FQDN="$BTCPAY_SERVER_HOSTNAME.$DOMAIN_NAME"
|
||||
VPS_HOSTNAME="$BTCPAY_SERVER_HOSTNAME"
|
||||
MAC_ADDRESS_TO_PROVISION="$BTCPAY_SERVER_MAC_ADDRESS"
|
||||
|
||||
elif [ "$VIRTUAL_MACHINE" = lnplayserver ] && [ -n "$LNPLAY_SERVER_MAC_ADDRESS" ]; then
|
||||
FQDN="$LNPLAY_SERVER_HOSTNAME.$DOMAIN_NAME"
|
||||
VPS_HOSTNAME="$LNPLAY_SERVER_HOSTNAME"
|
||||
MAC_ADDRESS_TO_PROVISION="$LNPLAY_SERVER_MAC_ADDRESS"
|
||||
|
||||
elif [ "$VIRTUAL_MACHINE" = "$BASE_IMAGE_VM_NAME" ]; then
|
||||
FQDN="$BASE_IMAGE_VM_NAME"
|
||||
fi
|
||||
|
||||
export FQDN="$FQDN"
|
||||
export INCUS_VM_NAME="${FQDN//./-}"
|
||||
export MAC_ADDRESS_TO_PROVISION="$MAC_ADDRESS_TO_PROVISION"
|
||||
export PROJECT_PATH="$PROJECT_PATH"
|
||||
|
||||
./deploy_vm.sh
|
||||
|
||||
done
|
||||
|
||||
# let's stub out the rest of our site definitions, if any.
|
||||
for DOMAIN_NAME in ${OTHER_SITES_LIST//,/ }; do
|
||||
export DOMAIN_NAME="$DOMAIN_NAME"
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
|
||||
# stub out the site_defition if it's doesn't exist.
|
||||
stub_site_definition
|
||||
done
|
||||
|
||||
if [ "$SKIP_BTCPAY_SERVER" = false ]; then
|
||||
if [ -n "$BTCPAY_SERVER_MAC_ADDRESS" ]; then
|
||||
export DOCKER_HOST="ssh://ubuntu@$BTCPAY_SERVER_FQDN"
|
||||
./project/btcpayserver/go.sh
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$SKIP_WWW_SERVER" = false ]; then
|
||||
# now let's run the www and btcpay-specific provisioning scripts.
|
||||
if [ -n "$WWW_SERVER_MAC_ADDRESS" ]; then
|
||||
export DOCKER_HOST="ssh://ubuntu@$WWW_FQDN"
|
||||
|
||||
# enable docker swarm mode so we can support docker stacks.
|
||||
if docker info | grep -q "Swarm: inactive"; then
|
||||
docker swarm init --advertise-addr enp6s0
|
||||
fi
|
||||
|
||||
./project/www/go.sh
|
||||
fi
|
||||
fi
|
||||
|
||||
# don't run lnplay stuff if user specifies --skip-lnplay
|
||||
if [ "$SKIP_LNPLAY_SERVER" = false ]; then
|
||||
# now let's run the www and btcpay-specific provisioning scripts.
|
||||
if [ -n "$LNPLAY_SERVER_MAC_ADDRESS" ]; then
|
||||
export DOCKER_HOST="ssh://ubuntu@$LNPLAY_SERVER_FQDN"
|
||||
|
||||
LNPLAY_ENV_FILE="$PRIMARY_SITE_PATH/$LNPLAY_SERVER_FQDN/lnplay.conf"
|
||||
if [ ! -f "$LNPLAY_ENV_FILE" ]; then
|
||||
# and we have to set our environment file as well.
|
||||
cat > "$LNPLAY_ENV_FILE" <<EOL
|
||||
DOCKER_HOST=ssh://ubuntu@${LNPLAY_SERVER_FQDN}
|
||||
BACKEND_FQDN=lnplay.${PRIMARY_DOMAIN}
|
||||
FRONTEND_FQDN=remote.${PRIMARY_DOMAIN}
|
||||
ENABLE_TLS=true
|
||||
BTC_CHAIN=${BITCOIN_CHAIN}
|
||||
CHANNEL_SETUP=none
|
||||
LNPLAY_SERVER_PATH=${SITES_PATH}/${PRIMARY_DOMAIN}/lnplayserver
|
||||
DEPLOY_PRISM_PLUGIN=true
|
||||
EOL
|
||||
|
||||
fi
|
||||
|
||||
INCUS_LNPLAYSERVER_IMAGE_NAME="lnplayserver-$DOMAIN_NAME"
|
||||
if ! incus image list -q --format csv | grep -q "$INCUS_LNPLAYSERVER_IMAGE_NAME"; then
|
||||
|
||||
# do all the docker image creation steps, but don't run services.
|
||||
bash -c "./project/lnplay/up.sh -y --no-services --lnplay-conf-path=$LNPLAY_ENV_FILE"
|
||||
|
||||
# stop the instance so we can get an image yo
|
||||
INCUS_VM_NAME="${LNPLAY_SERVER_FQDN//./-}"
|
||||
|
||||
incus stop "$INCUS_VM_NAME"
|
||||
|
||||
# create the incus image.
|
||||
incus publish -q --public "$INCUS_VM_NAME" --alias="$INCUS_LNPLAYSERVER_IMAGE_NAME" --compression none
|
||||
|
||||
incus start "$INCUS_VM_NAME"
|
||||
sleep 10
|
||||
|
||||
bash -c "./wait_for_ip.sh --incus-name=$INCUS_VM_NAME"
|
||||
sleep 3
|
||||
fi
|
||||
|
||||
# bring up lnplay services.
|
||||
bash -c "./project/lnplay/up.sh -y --lnplay-conf-path=$LNPLAY_ENV_FILE"
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,51 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
INCUS_INSTANCE_NAME=
|
||||
|
||||
# grab any modifications from the command line.
|
||||
for i in "$@"; do
|
||||
case $i in
|
||||
--incus-name=*)
|
||||
INCUS_INSTANCE_NAME="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unexpected option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# if the invoker did not set the instance name, throw an error.
|
||||
if [ -z "$INCUS_INSTANCE_NAME" ]; then
|
||||
echo "ERROR: The instance name was not specified. Use '--incus-name' when calling wait_for_ip.sh."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! incus list --format csv | grep -q "$INCUS_INSTANCE_NAME"; then
|
||||
echo "ERROR: the instance '$INCUS_INSTANCE_NAME' does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_V4_ADDRESS=
|
||||
while true; do
|
||||
IP_V4_ADDRESS="$(incus list "$INCUS_INSTANCE_NAME" --format csv --columns=4 | grep enp5s0 | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')" || true
|
||||
export IP_V4_ADDRESS="$IP_V4_ADDRESS"
|
||||
if [ -n "$IP_V4_ADDRESS" ]; then
|
||||
# give the machine extra time to spin up.
|
||||
wait-for-it -t 300 "$IP_V4_ADDRESS:22"
|
||||
break
|
||||
else
|
||||
sleep 1
|
||||
printf '.'
|
||||
fi
|
||||
done
|
||||
|
||||
# wait for cloud-init to complet before returning.
|
||||
while incus exec "$INCUS_INSTANCE_NAME" -- [ ! -f /var/lib/cloud/instance/boot-finished ]; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
sleep 1
|
|
@ -1,28 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
LXC_INSTANCE_NAME="$1"
|
||||
IP_V4_ADDRESS=
|
||||
while true; do
|
||||
IP_V4_ADDRESS="$(lxc list "$LXC_INSTANCE_NAME" --format csv --columns=4 | grep enp5s0 | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')" || true
|
||||
export IP_V4_ADDRESS="$IP_V4_ADDRESS"
|
||||
if [ -n "$IP_V4_ADDRESS" ]; then
|
||||
# give the machine extra time to spin up.
|
||||
wait-for-it -t 300 "$IP_V4_ADDRESS:22"
|
||||
echo ""
|
||||
break
|
||||
else
|
||||
sleep 1
|
||||
printf '.'
|
||||
fi
|
||||
done
|
||||
|
||||
# Let's remove any entry in our known_hosts, then add it back.
|
||||
# we are using IP address here so we don't have to rely on external DNS
|
||||
# configuration for the base image preparataion.
|
||||
ssh-keygen -R "$IP_V4_ADDRESS"
|
||||
|
||||
ssh-keyscan -H -t ecdsa "$IP_V4_ADDRESS" >> "$SSH_HOME/known_hosts"
|
||||
|
||||
ssh "ubuntu@$IP_V4_ADDRESS" sudo chown -R ubuntu:ubuntu /home/ubuntu
|
|
@ -1,36 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# TODO: We are using extra space on the remote VPS at the moment for the duplicity backup files.
|
||||
# we could eliminate that and simply save duplicity backups to the management machine running the script
|
||||
# this could be done by using a local path and mounting it on the remote VPS.
|
||||
# maybe something like https://superuser.com/questions/616182/how-to-mount-local-directory-to-remote-like-sshfs
|
||||
|
||||
# step 1: run duplicity on the remote system to backup all files to the remote system.
|
||||
# --allow-source-mismatch
|
||||
|
||||
# if the source files to backup don't exist on the remote host, we return.
|
||||
if ! ssh "$PRIMARY_WWW_FQDN" "[ -d $REMOTE_SOURCE_BACKUP_PATH ]"; then
|
||||
echo "INFO: The path to backup does not exist. There's nothing to backup! That's ok, execution will continue."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ssh "$PRIMARY_WWW_FQDN" sudo PASSPHRASE="$DUPLICITY_BACKUP_PASSPHRASE" duplicity "$REMOTE_SOURCE_BACKUP_PATH" "file://$REMOTE_BACKUP_PATH"
|
||||
ssh "$PRIMARY_WWW_FQDN" sudo chown -R ubuntu:ubuntu "$REMOTE_BACKUP_PATH"
|
||||
|
||||
SSHFS_PATH="/tmp/sshfs_temp"
|
||||
mkdir -p "$SSHFS_PATH"
|
||||
|
||||
# now let's pull down the latest files from the backup directory.
|
||||
# create a temp directory to serve as the mountpoint for the remote machine backups directory
|
||||
sshfs "$PRIMARY_WWW_FQDN:$REMOTE_BACKUP_PATH" "$SSHFS_PATH"
|
||||
|
||||
# rsync the files from the remote server to our local backup path.
|
||||
rsync -av "$SSHFS_PATH/" "$LOCAL_BACKUP_PATH/"
|
||||
|
||||
# step 4: unmount the SSHFS filesystem and cleanup.
|
||||
umount "$SSHFS_PATH"
|
||||
rm -rf "$SSHFS_PATH"
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
|
||||
# let's do a refresh of the certificates. Let's Encrypt will not run if it's not time.
|
||||
docker pull certbot/certbot:latest
|
||||
|
||||
# iterate over each domain and call certbot
|
||||
for DOMAIN_NAME in ${DOMAIN_LIST//,/ }; do
|
||||
export DOMAIN_NAME="$DOMAIN_NAME"
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
|
||||
# source the site path so we know what features it has.
|
||||
source "$RESPOSITORY_PATH/reset_env.sh"
|
||||
source "$SITE_PATH/site_definition"
|
||||
source "$RESPOSITORY_PATH/domain_env.sh"
|
||||
|
||||
# with the lxd side, we are trying to expose ALL OUR services from one IP address, which terminates
|
||||
# at a cachehing reverse proxy that runs nginx.
|
||||
|
||||
ssh "$PRIMARY_WWW_FQDN" sudo mkdir -p "$REMOTE_HOME/letsencrypt/$DOMAIN_NAME/_logs"
|
||||
|
||||
# this is minimum required; www and btcpay.
|
||||
DOMAIN_STRING="-d $DOMAIN_NAME -d $WWW_FQDN -d $BTCPAY_USER_FQDN"
|
||||
if [ "$DEPLOY_NEXTCLOUD" = true ]; then DOMAIN_STRING="$DOMAIN_STRING -d $NEXTCLOUD_FQDN"; fi
|
||||
if [ "$DEPLOY_GITEA" = true ]; then DOMAIN_STRING="$DOMAIN_STRING -d $GITEA_FQDN"; fi
|
||||
if [ "$DEPLOY_NOSTR_RELAY" = true ]; then DOMAIN_STRING="$DOMAIN_STRING -d $NOSTR_FQDN"; fi
|
||||
|
||||
# if BTCPAY_ALT_NAMES has been set by the admin, iterate over the list
|
||||
# and append the domain names to the certbot request
|
||||
if [ -n "$BTCPAY_ALT_NAMES" ]; then
|
||||
# let's stub out the rest of our site definitions, if any.
|
||||
for ALT_NAME in ${BTCPAY_ALT_NAMES//,/ }; do
|
||||
DOMAIN_STRING="$DOMAIN_STRING -d $ALT_NAME.$DOMAIN_NAME"
|
||||
done
|
||||
fi
|
||||
|
||||
GENERATE_CERT_STRING="docker run -it --rm --name certbot -p 80:80 -p 443:443 -v $REMOTE_HOME/letsencrypt/$DOMAIN_NAME:/etc/letsencrypt -v /var/lib/letsencrypt:/var/lib/letsencrypt -v $REMOTE_HOME/letsencrypt/$DOMAIN_NAME/_logs:/var/log/letsencrypt certbot/certbot certonly -v --noninteractive --agree-tos --key-type ecdsa --standalone --expand ${DOMAIN_STRING} --email $CERTIFICATE_EMAIL_ADDRESS"
|
||||
|
||||
# execute the certbot command that we dynamically generated.
|
||||
eval "$GENERATE_CERT_STRING"
|
||||
done
|
|
@ -1,153 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Create the nginx config file which covers all domains.
|
||||
bash -c ./stub/nginx_config.sh
|
||||
|
||||
# redirect all docker commands to the remote host.
|
||||
export DOCKER_HOST="ssh://ubuntu@$PRIMARY_WWW_FQDN"
|
||||
|
||||
for DOMAIN_NAME in ${DOMAIN_LIST//,/ }; do
|
||||
export DOMAIN_NAME="$DOMAIN_NAME"
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
|
||||
# source the site path so we know what features it has.
|
||||
source "$RESPOSITORY_PATH/reset_env.sh"
|
||||
source "$SITE_PATH/site_definition"
|
||||
source "$RESPOSITORY_PATH/domain_env.sh"
|
||||
|
||||
|
||||
### Let's check to ensure all the requiredsettings are set.
|
||||
if [ "$DEPLOY_GHOST" = true ]; then
|
||||
if [ -z "$GHOST_MYSQL_PASSWORD" ]; then
|
||||
echo "ERROR: Ensure GHOST_MYSQL_PASSWORD is configured in your site_definition."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$GHOST_MYSQL_ROOT_PASSWORD" ]; then
|
||||
echo "ERROR: Ensure GHOST_MYSQL_ROOT_PASSWORD is configured in your site_definition."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$DEPLOY_GITEA" = true ]; then
|
||||
if [ -z "$GITEA_MYSQL_PASSWORD" ]; then
|
||||
echo "ERROR: Ensure GITEA_MYSQL_PASSWORD is configured in your site_definition."
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$GITEA_MYSQL_ROOT_PASSWORD" ]; then
|
||||
echo "ERROR: Ensure GITEA_MYSQL_ROOT_PASSWORD is configured in your site_definition."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$DEPLOY_NEXTCLOUD" = true ]; then
|
||||
if [ -z "$NEXTCLOUD_MYSQL_ROOT_PASSWORD" ]; then
|
||||
echo "ERROR: Ensure NEXTCLOUD_MYSQL_ROOT_PASSWORD is configured in your site_definition."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$NEXTCLOUD_MYSQL_PASSWORD" ]; then
|
||||
echo "ERROR: Ensure NEXTCLOUD_MYSQL_PASSWORD is configured in your site_definition."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$DEPLOY_NOSTR_RELAY" = true ]; then
|
||||
if [ -z "$NOSTR_ACCOUNT_PUBKEY" ]; then
|
||||
echo "ERROR: Ensure NOSTR_ACCOUNT_PUBKEY is configured in your site_definition."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$DUPLICITY_BACKUP_PASSPHRASE" ]; then
|
||||
echo "ERROR: Ensure DUPLICITY_BACKUP_PASSPHRASE is configured in your site_definition."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$DOMAIN_NAME" ]; then
|
||||
echo "ERROR: Ensure DOMAIN_NAME is configured in your site_definition."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$NOSTR_ACCOUNT_PUBKEY" ]; then
|
||||
echo "ERROR: You MUST specify a Nostr public key. This is how you get all your social features."
|
||||
echo "INFO: Go to your site_definition file and set the NOSTR_ACCOUNT_PUBKEY variable."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TOR_CONFIG_PATH=
|
||||
|
||||
done
|
||||
|
||||
./stop_docker_stacks.sh
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# if [ "$DEPLOY_ONION_SITE" = true ]; then
|
||||
# # ensure the tor image is built
|
||||
# docker build -t tor:latest ./tor
|
||||
|
||||
# # if the tor folder doesn't exist, we provision a new one. Otherwise you need to restore.
|
||||
# # this is how we generate a new torv3 endpoint.
|
||||
# if ! ssh "$PRIMARY_WWW_FQDN" "[ -d $REMOTE_HOME/tor/www ]"; then
|
||||
# ssh "$PRIMARY_WWW_FQDN" "mkdir -p $REMOTE_HOME/tor"
|
||||
# TOR_CONFIG_PATH="$(pwd)/tor/torrc-init"
|
||||
# export TOR_CONFIG_PATH="$TOR_CONFIG_PATH"
|
||||
# docker stack deploy -c ./tor.yml torstack
|
||||
# sleep 20
|
||||
# docker stack rm torstack
|
||||
# sleep 20
|
||||
# fi
|
||||
|
||||
# ONION_ADDRESS="$(ssh "$PRIMARY_WWW_FQDN" sudo cat "${REMOTE_HOME}"/tor/www/hostname)"
|
||||
# export ONION_ADDRESS="$ONION_ADDRESS"
|
||||
|
||||
# # # Since we run a separate ghost process, we create a new directory and symlink it to the original
|
||||
# # if ! ssh "$PRIMARY_WWW_FQDN" "[ -L $REMOTE_HOME/tor_ghost ]"; then
|
||||
# # ssh "$PRIMARY_WWW_FQDN" ln -s "$REMOTE_HOME/ghost_site/themes $REMOTE_HOME/tor_ghost/themes"
|
||||
# # fi
|
||||
# fi
|
||||
|
||||
# nginx gets deployed first since it "owns" the docker networks of downstream services.
|
||||
./stub/nginx_yml.sh
|
||||
|
||||
# next run our application stub logic. These deploy the apps too if configured to do so.
|
||||
./stub/ghost_yml.sh
|
||||
./stub/nextcloud_yml.sh
|
||||
./stub/gitea_yml.sh
|
||||
./stub/nostr_yml.sh
|
||||
|
||||
# # start a browser session; point it to port 80 to ensure HTTPS redirect.
|
||||
# # WWW_FQDN is in our certificate, so we resolve to that.
|
||||
# wait-for-it -t 320 "$WWW_FQDN:80"
|
||||
# wait-for-it -t 320 "$WWW_FQDN:443"
|
||||
|
||||
# # open bowser tabs.
|
||||
# if [ "$DEPLOY_GHOST" = true ]; then
|
||||
# xdg-open "http://$WWW_FQDN" > /dev/null 2>&1
|
||||
# fi
|
||||
|
||||
# if [ "$DEPLOY_NEXTCLOUD" = true ]; then
|
||||
# xdg-open "http://$NEXTCLOUD_FQDN" > /dev/null 2>&1
|
||||
# fi
|
||||
|
||||
# if [ "$DEPLOY_GITEA" = true ]; then
|
||||
# xdg-open "http://$GITEA_FQDN" > /dev/null 2>&1
|
||||
# fi
|
||||
|
||||
# if [ "$DEPLOY_BTCPAY_SERVER" = true ]; then
|
||||
# xdg-open "http://$BTCPAY_USER_FQDN" > /dev/null 2>&1
|
||||
# fi
|
|
@ -1,38 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eux
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
FILE_COUNT="$(find "$LOCAL_BACKUP_PATH" -type f | wc -l)"
|
||||
if [ "$FILE_COUNT" = 0 ]; then
|
||||
echo "ERROR: there are no files in the local backup path '$LOCAL_BACKUP_PATH'."
|
||||
echo "We're going to continue with execution."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# if the user said -y at the cli, we can skip this.
|
||||
if [ "$USER_SAYS_YES" = false ]; then
|
||||
|
||||
RESPONSE=
|
||||
read -r -p "Are you sure you want to restore the local path '$LOCAL_BACKUP_PATH' to the remote server at '$PRIMARY_WWW_FQDN' (y/n)": RESPONSE
|
||||
if [ "$RESPONSE" != "y" ]; then
|
||||
echo "STOPPING."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# delete the target backup path so we can push restoration files from the management machine.
|
||||
ssh "$PRIMARY_WWW_FQDN" sudo rm -rf "$REMOTE_SOURCE_BACKUP_PATH"
|
||||
|
||||
# scp our local backup directory to the remote machine
|
||||
ssh "$PRIMARY_WWW_FQDN" sudo mkdir -p "$REMOTE_BACKUP_PATH"
|
||||
ssh "$PRIMARY_WWW_FQDN" sudo chown ubuntu:ubuntu "$REMOTE_BACKUP_PATH"
|
||||
|
||||
scp -r "$LOCAL_BACKUP_PATH" "$PRIMARY_WWW_FQDN:$REMOTE_BACKUP_PATH"
|
||||
|
||||
# now we run duplicity to restore the archive.
|
||||
ssh "$PRIMARY_WWW_FQDN" sudo PASSPHRASE="$DUPLICITY_BACKUP_PASSPHRASE" duplicity --force restore "file://$REMOTE_BACKUP_PATH/$APP" "$REMOTE_SOURCE_BACKUP_PATH/"
|
||||
|
||||
# reset folder owner to ubuntu
|
||||
ssh "$PRIMARY_WWW_FQDN" sudo chown ubuntu:ubuntu "$REMOTE_HOME/$APP"
|
|
@ -1,98 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# bring down ghost instances.
|
||||
for DOMAIN_NAME in ${DOMAIN_LIST//,/ }; do
|
||||
export DOMAIN_NAME="$DOMAIN_NAME"
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
|
||||
# source the site path so we know what features it has.
|
||||
source "$RESPOSITORY_PATH/reset_env.sh"
|
||||
source "$SITE_PATH/site_definition"
|
||||
source "$RESPOSITORY_PATH/domain_env.sh"
|
||||
|
||||
### Stop all services.
|
||||
for APP in ghost nextcloud gitea nostr; do
|
||||
# backup each language for each app.
|
||||
for LANGUAGE_CODE in ${SITE_LANGUAGE_CODES//,/ }; do
|
||||
STACK_NAME="$DOMAIN_IDENTIFIER-$APP-$LANGUAGE_CODE"
|
||||
|
||||
if docker stack list --format "{{.Name}}" | grep -q "$STACK_NAME"; then
|
||||
docker stack rm "$STACK_NAME"
|
||||
sleep 2
|
||||
fi
|
||||
|
||||
# these variable are used by both backup/restore scripts.
|
||||
export APP="$APP"
|
||||
export REMOTE_BACKUP_PATH="$REMOTE_HOME/backups/www/$APP/$DOMAIN_IDENTIFIER-$LANGUAGE_CODE"
|
||||
export REMOTE_SOURCE_BACKUP_PATH="$REMOTE_HOME/$APP/$DOMAIN_NAME"
|
||||
|
||||
# ensure our local backup path exists so we can pull down the duplicity archive to the management machine.
|
||||
export LOCAL_BACKUP_PATH="$SITE_PATH/backups/www/$APP"
|
||||
|
||||
# ensure our local backup path exists.
|
||||
if [ ! -d "$LOCAL_BACKUP_PATH" ]; then
|
||||
mkdir -p "$LOCAL_BACKUP_PATH"
|
||||
fi
|
||||
|
||||
if [ "$RESTORE_WWW" = true ]; then
|
||||
./restore_path.sh
|
||||
#ssh "$PRIMARY_WWW_FQDN" sudo chown ubuntu:ubuntu "$REMOTE_HOME/$APP"
|
||||
else
|
||||
# if we're not restoring, then we may or may not back up.
|
||||
./backup_path.sh
|
||||
fi
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
if [ "$RESTART_FRONT_END" = true ]; then
|
||||
# remove the nginx stack
|
||||
if docker stack list --format "{{.Name}}" | grep -q reverse-proxy; then
|
||||
sleep 2
|
||||
|
||||
docker stack rm reverse-proxy
|
||||
|
||||
# wait for all docker containers to stop.
|
||||
# TODO see if there's a way to check for this.
|
||||
sleep 15
|
||||
|
||||
fi
|
||||
|
||||
# generate the certs and grab a backup
|
||||
if [ "$RUN_CERT_RENEWAL" = true ]; then
|
||||
./generate_certs.sh
|
||||
fi
|
||||
|
||||
# let's backup all our letsencrypt certs
|
||||
export APP="letsencrypt"
|
||||
for DOMAIN_NAME in ${DOMAIN_LIST//,/ }; do
|
||||
export DOMAIN_NAME="$DOMAIN_NAME"
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
|
||||
# source the site path so we know what features it has.
|
||||
source "$RESPOSITORY_PATH/reset_env.sh"
|
||||
source "$SITE_PATH/site_definition"
|
||||
source "$RESPOSITORY_PATH/domain_env.sh"
|
||||
|
||||
# these variable are used by both backup/restore scripts.
|
||||
export REMOTE_BACKUP_PATH="$REMOTE_HOME/backups/www/$APP/$DOMAIN_IDENTIFIER"
|
||||
export REMOTE_SOURCE_BACKUP_PATH="$REMOTE_HOME/$APP/$DOMAIN_NAME"
|
||||
|
||||
# ensure our local backup path exists so we can pull down the duplicity archive to the management machine.
|
||||
export LOCAL_BACKUP_PATH="$SITE_PATH/backups/www/$APP"
|
||||
mkdir -p "$LOCAL_BACKUP_PATH"
|
||||
|
||||
if [ "$RESTORE_WWW" = true ]; then
|
||||
sleep 5
|
||||
echo "STARTING restore_path.sh for letsencrypt."
|
||||
./restore_path.sh
|
||||
#ssh "$PRIMARY_WWW_FQDN" sudo chown ubuntu:ubuntu "$REMOTE_HOME/$APP"
|
||||
elif [ "$BACKUP_APPS" = true ]; then
|
||||
# if we're not restoring, then we may or may not back up.
|
||||
./backup_path.sh
|
||||
fi
|
||||
done
|
||||
fi
|
|
@ -1,113 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
for DOMAIN_NAME in ${DOMAIN_LIST//,/ }; do
|
||||
export DOMAIN_NAME="$DOMAIN_NAME"
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
|
||||
# source the site path so we know what features it has.
|
||||
source "$RESPOSITORY_PATH/reset_env.sh"
|
||||
source "$SITE_PATH/site_definition"
|
||||
source "$RESPOSITORY_PATH/domain_env.sh"
|
||||
|
||||
# for each language specified in the site_definition, we spawn a separate ghost container
|
||||
# at https://www.domain.com/$LANGUAGE_CODE
|
||||
for LANGUAGE_CODE in ${SITE_LANGUAGE_CODES//,/ }; do
|
||||
|
||||
STACK_NAME="$DOMAIN_IDENTIFIER-$LANGUAGE_CODE"
|
||||
|
||||
# ensure directories on remote host exist so we can mount them into the containers.
|
||||
ssh "$PRIMARY_WWW_FQDN" mkdir -p "$REMOTE_HOME/ghost/$DOMAIN_NAME"
|
||||
ssh "$PRIMARY_WWW_FQDN" mkdir -p "$REMOTE_HOME/ghost/$DOMAIN_NAME/$LANGUAGE_CODE/ghost" "$REMOTE_HOME/ghost/$DOMAIN_NAME/$LANGUAGE_CODE/db"
|
||||
|
||||
export GHOST_STACK_TAG="ghost-$STACK_NAME"
|
||||
export GHOST_DB_STACK_TAG="ghostdb-$STACK_NAME"
|
||||
|
||||
# todo append domain number or port number.
|
||||
WEBSTACK_PATH="$SITE_PATH/webstack"
|
||||
mkdir -p "$WEBSTACK_PATH"
|
||||
export DOCKER_YAML_PATH="$WEBSTACK_PATH/ghost-$LANGUAGE_CODE.yml"
|
||||
|
||||
# here's the NGINX config. We support ghost and nextcloud.
|
||||
cat > "$DOCKER_YAML_PATH" <<EOL
|
||||
version: "3.8"
|
||||
services:
|
||||
|
||||
EOL
|
||||
# This is the ghost for HTTPS (not over Tor)
|
||||
cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
${GHOST_STACK_TAG}:
|
||||
image: ${GHOST_IMAGE}
|
||||
networks:
|
||||
- ghostnet-${DOMAIN_IDENTIFIER}-${LANGUAGE_CODE}
|
||||
- ghostdbnet-${DOMAIN_IDENTIFIER}-${LANGUAGE_CODE}
|
||||
volumes:
|
||||
- ${REMOTE_HOME}/ghost/${DOMAIN_NAME}/${LANGUAGE_CODE}/ghost:/var/lib/ghost/content
|
||||
environment:
|
||||
EOL
|
||||
if [ "$LANGUAGE_CODE" = "en" ]; then
|
||||
cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
- url=https://${WWW_FQDN}
|
||||
EOL
|
||||
else
|
||||
cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
- url=https://${WWW_FQDN}/${LANGUAGE_CODE}
|
||||
EOL
|
||||
fi
|
||||
|
||||
cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
- database__client=mysql
|
||||
- database__connection__host=${GHOST_DB_STACK_TAG}
|
||||
- database__connection__user=ghost
|
||||
- database__connection__password=\${GHOST_MYSQL_PASSWORD}
|
||||
- database__connection__database=ghost
|
||||
- database__pool__min=0
|
||||
- privacy__useStructuredData=true
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
|
||||
${GHOST_DB_STACK_TAG}:
|
||||
image: ${GHOST_DB_IMAGE}
|
||||
networks:
|
||||
- ghostdbnet-${DOMAIN_IDENTIFIER}-${LANGUAGE_CODE}
|
||||
volumes:
|
||||
- ${REMOTE_HOME}/ghost/${DOMAIN_NAME}/${LANGUAGE_CODE}/db:/var/lib/mysql
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=\${GHOST_MYSQL_ROOT_PASSWORD}
|
||||
- MYSQL_DATABASE=ghost
|
||||
- MYSQL_USER=ghost
|
||||
- MYSQL_PASSWORD=\${GHOST_MYSQL_PASSWORD}
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
|
||||
EOL
|
||||
|
||||
cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
networks:
|
||||
EOL
|
||||
|
||||
if [ "$DEPLOY_GHOST" = true ]; then
|
||||
GHOSTNET_NAME="ghostnet-$DOMAIN_IDENTIFIER-$LANGUAGE_CODE"
|
||||
GHOSTDBNET_NAME="ghostdbnet-$DOMAIN_IDENTIFIER-$LANGUAGE_CODE"
|
||||
|
||||
cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
${GHOSTNET_NAME}:
|
||||
name: "reverse-proxy_ghostnet-$DOMAIN_IDENTIFIER-$LANGUAGE_CODE"
|
||||
external: true
|
||||
|
||||
${GHOSTDBNET_NAME}:
|
||||
EOL
|
||||
fi
|
||||
|
||||
if [ "$STOP_SERVICES" = false ]; then
|
||||
docker stack deploy -c "$DOCKER_YAML_PATH" "$DOMAIN_IDENTIFIER-ghost-$LANGUAGE_CODE"
|
||||
sleep 2
|
||||
fi
|
||||
|
||||
done # language code
|
||||
|
||||
done # domain list
|
|
@ -1,89 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
for DOMAIN_NAME in ${DOMAIN_LIST//,/ }; do
|
||||
export DOMAIN_NAME="$DOMAIN_NAME"
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
|
||||
# source the site path so we know what features it has.
|
||||
source "$RESPOSITORY_PATH/reset_env.sh"
|
||||
source "$SITE_PATH/site_definition"
|
||||
source "$RESPOSITORY_PATH/domain_env.sh"
|
||||
|
||||
if [ "$DEPLOY_GITEA" = true ]; then
|
||||
GITEA_PATH="$REMOTE_GITEA_PATH/$DOMAIN_NAME/${LANGUAGE_CODE}"
|
||||
|
||||
ssh "$PRIMARY_WWW_FQDN" mkdir -p "$GITEA_PATH/data" "$GITEA_PATH/db"
|
||||
|
||||
STACK_NAME="$DOMAIN_IDENTIFIER-$LANGUAGE_CODE"
|
||||
|
||||
export STACK_TAG="gitea-$STACK_NAME"
|
||||
export DB_STACK_TAG="giteadb-$STACK_NAME"
|
||||
export DOCKER_YAML_PATH="$SITE_PATH/webstack/gitea-en.yml"
|
||||
|
||||
NET_NAME="giteanet-$DOMAIN_IDENTIFIER"
|
||||
DBNET_NAME="giteadbnet-$DOMAIN_IDENTIFIER"
|
||||
|
||||
# here's the NGINX config. We support ghost and nextcloud.
|
||||
echo "" > "$DOCKER_YAML_PATH"
|
||||
cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
version: "3.8"
|
||||
services:
|
||||
|
||||
${STACK_TAG}:
|
||||
image: ${GITEA_IMAGE}
|
||||
volumes:
|
||||
- ${GITEA_PATH}/data:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- ROOT_URL=https://${GITEA_FQDN}
|
||||
- GITEA__database__DB_TYPE=mysql
|
||||
- GITEA__database__HOST=${DB_STACK_TAG}:3306
|
||||
- GITEA__database__NAME=gitea
|
||||
- GITEA__database__USER=gitea
|
||||
- GITEA__PASSWD=\${GITEA_MYSQL_PASSWORD}
|
||||
networks:
|
||||
- ${NET_NAME}
|
||||
- ${DBNET_NAME}
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
|
||||
${DB_STACK_TAG}:
|
||||
image: ${GITEA_DB_IMAGE}
|
||||
networks:
|
||||
- ${DBNET_NAME}
|
||||
volumes:
|
||||
- ${GITEA_PATH}/db:/var/lib/mysql
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=\${GITEA_MYSQL_ROOT_PASSWORD}
|
||||
- MYSQL_PASSWORD=\${GITEA_MYSQL_PASSWORD}
|
||||
- MYSQL_DATABASE=gitea
|
||||
- MYSQL_USER=gitea
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
|
||||
networks:
|
||||
EOL
|
||||
|
||||
cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
${NET_NAME}:
|
||||
name: "reverse-proxy_${NET_NAME}-${LANGUAGE_CODE}"
|
||||
external: true
|
||||
|
||||
${DBNET_NAME}:
|
||||
EOL
|
||||
|
||||
if [ "$STOP_SERVICES" = false ]; then
|
||||
docker stack deploy -c "$DOCKER_YAML_PATH" "$DOMAIN_IDENTIFIER-gitea-$LANGUAGE_CODE"
|
||||
sleep 1
|
||||
fi
|
||||
fi
|
||||
|
||||
done
|
|
@ -1,82 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
for DOMAIN_NAME in ${DOMAIN_LIST//,/ }; do
|
||||
export DOMAIN_NAME="$DOMAIN_NAME"
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
|
||||
# source the site path so we know what features it has.
|
||||
source "$RESPOSITORY_PATH/reset_env.sh"
|
||||
source "$SITE_PATH/site_definition"
|
||||
source "$RESPOSITORY_PATH/domain_env.sh"
|
||||
|
||||
# ensure remote directories exist
|
||||
if [ "$DEPLOY_NEXTCLOUD" = true ]; then
|
||||
|
||||
ssh "$PRIMARY_WWW_FQDN" "mkdir -p $REMOTE_NEXTCLOUD_PATH/$DOMAIN_NAME/en/db"
|
||||
ssh "$PRIMARY_WWW_FQDN" "mkdir -p $REMOTE_NEXTCLOUD_PATH/$DOMAIN_NAME/en/html"
|
||||
|
||||
sleep 2
|
||||
|
||||
WEBSTACK_PATH="$SITE_PATH/webstack"
|
||||
mkdir -p "$WEBSTACK_PATH"
|
||||
export DOCKER_YAML_PATH="$WEBSTACK_PATH/nextcloud-en.yml"
|
||||
|
||||
# here's the NGINX config. We support ghost and nextcloud.
|
||||
cat > "$DOCKER_YAML_PATH" <<EOL
|
||||
version: "3.8"
|
||||
services:
|
||||
|
||||
${NEXTCLOUD_STACK_TAG}:
|
||||
image: ${NEXTCLOUD_IMAGE}
|
||||
networks:
|
||||
- nextcloud-${DOMAIN_IDENTIFIER}-en
|
||||
- nextclouddb-${DOMAIN_IDENTIFIER}-en
|
||||
volumes:
|
||||
- ${REMOTE_HOME}/nextcloud/${DOMAIN_NAME}/en/html:/var/www/html
|
||||
environment:
|
||||
- MYSQL_PASSWORD=\${NEXTCLOUD_MYSQL_PASSWORD}
|
||||
- MYSQL_DATABASE=nextcloud
|
||||
- MYSQL_USER=nextcloud
|
||||
- MYSQL_HOST=${NEXTCLOUD_DB_STACK_TAG}
|
||||
- NEXTCLOUD_TRUSTED_DOMAINS=${DOMAIN_NAME}
|
||||
- OVERWRITEHOST=${NEXTCLOUD_FQDN}
|
||||
- OVERWRITEPROTOCOL=https
|
||||
- SERVERNAME=${NEXTCLOUD_FQDN}
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
|
||||
${NEXTCLOUD_DB_STACK_TAG}:
|
||||
image: ${NEXTCLOUD_DB_IMAGE}
|
||||
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --innodb_read_only_compressed=OFF
|
||||
networks:
|
||||
- nextclouddb-${DOMAIN_IDENTIFIER}-en
|
||||
volumes:
|
||||
- ${REMOTE_HOME}/nextcloud/${DOMAIN_NAME}/en/db:/var/lib/mysql
|
||||
environment:
|
||||
- MARIADB_ROOT_PASSWORD=\${NEXTCLOUD_MYSQL_ROOT_PASSWORD}
|
||||
- MYSQL_PASSWORD=\${NEXTCLOUD_MYSQL_PASSWORD}
|
||||
- MYSQL_DATABASE=nextcloud
|
||||
- MYSQL_USER=nextcloud
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
|
||||
networks:
|
||||
nextcloud-${DOMAIN_IDENTIFIER}-en:
|
||||
name: "reverse-proxy_nextcloudnet-$DOMAIN_IDENTIFIER-$LANGUAGE_CODE"
|
||||
external: true
|
||||
|
||||
nextclouddb-${DOMAIN_IDENTIFIER}-en:
|
||||
|
||||
EOL
|
||||
|
||||
if [ "$STOP_SERVICES" = false ]; then
|
||||
docker stack deploy -c "$DOCKER_YAML_PATH" "$DOMAIN_IDENTIFIER-nextcloud-en"
|
||||
sleep 1
|
||||
fi
|
||||
fi
|
||||
done
|
|
@ -1,507 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
|
||||
# here's the NGINX config. We support ghost and nextcloud.
|
||||
NGINX_CONF_PATH="$PROJECT_PATH/nginx.conf"
|
||||
|
||||
# clear the existing nginx config.
|
||||
echo "" > "$NGINX_CONF_PATH"
|
||||
|
||||
# iterate over all our domains and create the nginx config file.
|
||||
iteration=0
|
||||
echo "DOMAIN_LIST: $DOMAIN_LIST"
|
||||
|
||||
for DOMAIN_NAME in ${DOMAIN_LIST//,/ }; do
|
||||
export DOMAIN_NAME="$DOMAIN_NAME"
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
export CONTAINER_TLS_PATH="/etc/letsencrypt/${DOMAIN_NAME}/live/${DOMAIN_NAME}"
|
||||
|
||||
# source the site path so we know what features it has.
|
||||
source "$RESPOSITORY_PATH/reset_env.sh"
|
||||
source "$SITE_PATH/site_definition"
|
||||
source "$RESPOSITORY_PATH/domain_env.sh"
|
||||
|
||||
if [ $iteration = 0 ]; then
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
client_max_body_size 100m;
|
||||
server_tokens off;
|
||||
|
||||
# next two sets commands and connection_upgrade block come from https://docs.btcpayserver.org/FAQ/Deployment/#can-i-use-an-existing-nginx-server-as-a-reverse-proxy-with-ssl-termination
|
||||
# Needed to allow very long URLs to prevent issues while signing PSBTs
|
||||
server_names_hash_bucket_size 128;
|
||||
proxy_buffer_size 128k;
|
||||
proxy_buffers 4 256k;
|
||||
proxy_busy_buffers_size 256k;
|
||||
client_header_buffer_size 500k;
|
||||
large_client_header_buffers 4 500k;
|
||||
|
||||
# Needed websocket support (used by Ledger hardware wallets)
|
||||
map \$http_upgrade \$connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
# return 403 for all non-explicit hostnames
|
||||
server {
|
||||
listen 80 default_server;
|
||||
return 301 https://${WWW_FQDN}\$request_uri;
|
||||
}
|
||||
|
||||
EOL
|
||||
fi
|
||||
|
||||
# ghost http to https redirects.
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# http://${DOMAIN_NAME} redirect to https://${WWW_FQDN}
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
server_name ${DOMAIN_NAME};
|
||||
|
||||
location / {
|
||||
# request MAY get another redirect at https://domain.tld for www.
|
||||
return 301 https://${DOMAIN_NAME}\$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
EOL
|
||||
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# http://${WWW_FQDN} redirect to https://${WWW_FQDN}
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name ${WWW_FQDN};
|
||||
return 301 https://${WWW_FQDN}\$request_uri;
|
||||
}
|
||||
|
||||
EOL
|
||||
|
||||
# nextcloud http-to-https redirect
|
||||
if [ "$DEPLOY_NEXTCLOUD" = true ]; then
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# http://${NEXTCLOUD_FQDN} redirect to https://${NEXTCLOUD_FQDN}
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name ${NEXTCLOUD_FQDN};
|
||||
return 301 https://${NEXTCLOUD_FQDN}\$request_uri;
|
||||
}
|
||||
|
||||
EOL
|
||||
fi
|
||||
|
||||
# gitea http to https redirect.
|
||||
if [ "$DEPLOY_GITEA" = true ]; then
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# http://${GITEA_FQDN} redirect to https://${GITEA_FQDN}
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name ${GITEA_FQDN};
|
||||
return 301 https://${GITEA_FQDN}\$request_uri;
|
||||
}
|
||||
|
||||
EOL
|
||||
fi
|
||||
|
||||
# let's iterate over BTCPAY_ALT_NAMES and generate our SERVER_NAMES for btcpay server.
|
||||
BTCPAY_SERVER_NAMES="$BTCPAY_USER_FQDN"
|
||||
if [ -n "$BTCPAY_ALT_NAMES" ]; then
|
||||
# let's stub out the rest of our site definitions, if any.
|
||||
for ALT_NAME in ${BTCPAY_ALT_NAMES//,/ }; do
|
||||
BTCPAY_SERVER_NAMES="$BTCPAY_SERVER_NAMES $ALT_NAME.$DOMAIN_NAME"
|
||||
done
|
||||
fi
|
||||
|
||||
# BTCPAY server http->https redirect
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# http://${BTCPAY_USER_FQDN} redirect to https://${BTCPAY_USER_FQDN}
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name ${BTCPAY_SERVER_NAMES};
|
||||
return 301 https://${BTCPAY_USER_FQDN}\$request_uri;
|
||||
}
|
||||
|
||||
EOL
|
||||
|
||||
if [ "$iteration" = 0 ]; then
|
||||
# TLS config for ghost.
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# global TLS settings
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_protocols TLSv1.3;
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
|
||||
ssl_session_tickets off;
|
||||
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
resolver 198.54.117.10;
|
||||
# TODO change resolver to local DNS resolver, or inherit from system.
|
||||
|
||||
|
||||
# default server if hostname not specified.
|
||||
server {
|
||||
listen 443 default_server;
|
||||
|
||||
ssl_certificate $CONTAINER_TLS_PATH/fullchain.pem;
|
||||
ssl_certificate_key $CONTAINER_TLS_PATH/privkey.pem;
|
||||
ssl_trusted_certificate $CONTAINER_TLS_PATH/fullchain.pem;
|
||||
|
||||
return 403;
|
||||
}
|
||||
|
||||
# maybe helps with Twitter cards.
|
||||
#map \$http_user_agent \$og_prefix {
|
||||
# ~*(googlebot|twitterbot)/ /open-graph;
|
||||
#}
|
||||
|
||||
# this map allows us to route the clients request to the correct Ghost instance
|
||||
# based on the clients browser language setting.
|
||||
map \$http_accept_language \$lang {
|
||||
default "";
|
||||
~es es;
|
||||
}
|
||||
|
||||
EOL
|
||||
fi
|
||||
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# https://${DOMAIN_NAME} redirect to https://${WWW_FQDN}
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
|
||||
ssl_certificate $CONTAINER_TLS_PATH/fullchain.pem;
|
||||
ssl_certificate_key $CONTAINER_TLS_PATH/privkey.pem;
|
||||
ssl_trusted_certificate $CONTAINER_TLS_PATH/fullchain.pem;
|
||||
|
||||
server_name ${DOMAIN_NAME};
|
||||
|
||||
EOL
|
||||
|
||||
if [ "$DEPLOY_NOSTR_RELAY" = true ]; then
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# We return a JSON object with name/pubkey mapping per NIP05.
|
||||
# https://www.reddit.com/r/nostr/comments/rrzk76/nip05_mapping_usernames_to_dns_domains_by_fiatjaf/sssss
|
||||
# TODO I'm not sure about the security of this Access-Control-Allow-Origin. Read up and restrict it if possible.
|
||||
location = /.well-known/nostr.json {
|
||||
add_header Content-Type application/json;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
return 200 '{ "names": { "_": "${NOSTR_ACCOUNT_PUBKEY}" } }';
|
||||
}
|
||||
|
||||
EOL
|
||||
fi
|
||||
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
|
||||
# catch all; send request to ${WWW_FQDN}
|
||||
location / {
|
||||
return 301 https://${WWW_FQDN}\$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
#access_log /var/log/nginx/ghost-access.log;
|
||||
#error_log /var/log/nginx/ghost-error.log;
|
||||
|
||||
EOL
|
||||
|
||||
if [ "$DEPLOY_NOSTR_RELAY" = true ]; then
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# wss://$NOSTR_FQDN server block
|
||||
server {
|
||||
listen 443 ssl;
|
||||
|
||||
server_name ${NOSTR_FQDN};
|
||||
|
||||
ssl_certificate $CONTAINER_TLS_PATH/fullchain.pem;
|
||||
ssl_certificate_key $CONTAINER_TLS_PATH/privkey.pem;
|
||||
ssl_trusted_certificate $CONTAINER_TLS_PATH/fullchain.pem;
|
||||
|
||||
keepalive_timeout 70;
|
||||
|
||||
location / {
|
||||
# redirect all HTTP traffic to btcpay server
|
||||
proxy_pass http://nostr-${DOMAIN_IDENTIFIER}:8080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade \$http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Host \$host;
|
||||
}
|
||||
}
|
||||
|
||||
EOL
|
||||
fi
|
||||
|
||||
|
||||
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# https server block for https://${BTCPAY_SERVER_NAMES}
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
|
||||
ssl_certificate $CONTAINER_TLS_PATH/fullchain.pem;
|
||||
ssl_certificate_key $CONTAINER_TLS_PATH/privkey.pem;
|
||||
ssl_trusted_certificate $CONTAINER_TLS_PATH/fullchain.pem;
|
||||
|
||||
server_name ${BTCPAY_SERVER_NAMES};
|
||||
|
||||
# Route everything to the real BTCPay server
|
||||
location / {
|
||||
# URL of BTCPay Server
|
||||
proxy_pass http://10.139.144.10:80;
|
||||
proxy_set_header Host \$http_host;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
|
||||
# For websockets (used by Ledger hardware wallets)
|
||||
proxy_set_header Upgrade \$http_upgrade;
|
||||
}
|
||||
}
|
||||
|
||||
EOL
|
||||
|
||||
echo " # set up cache paths for nginx caching" >>"$NGINX_CONF_PATH"
|
||||
for LANGUAGE_CODE in ${SITE_LANGUAGE_CODES//,/ }; do
|
||||
STACK_NAME="$DOMAIN_IDENTIFIER-$LANGUAGE_CODE"
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
proxy_cache_path /tmp/${STACK_NAME} levels=1:2 keys_zone=${STACK_NAME}:600m max_size=100m inactive=24h;
|
||||
EOL
|
||||
done
|
||||
|
||||
|
||||
# the open server block for the HTTPS listener for ghost
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
|
||||
# Main HTTPS listener for https://${WWW_FQDN}
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
|
||||
ssl_certificate $CONTAINER_TLS_PATH/fullchain.pem;
|
||||
ssl_certificate_key $CONTAINER_TLS_PATH/privkey.pem;
|
||||
ssl_trusted_certificate $CONTAINER_TLS_PATH/fullchain.pem;
|
||||
|
||||
server_name ${WWW_FQDN};
|
||||
|
||||
# Set the crawler policy.
|
||||
location = /robots.txt {
|
||||
add_header Content-Type text/plain;
|
||||
return 200 "User-Agent: *\\nAllow: /\\n";
|
||||
}
|
||||
|
||||
EOL
|
||||
|
||||
# # add the Onion-Location header if specifed.
|
||||
# if [ "$DEPLOY_ONION_SITE" = true ]; then
|
||||
# cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# add_header Onion-Location https://${ONION_ADDRESS}\$request_uri;
|
||||
|
||||
# EOL
|
||||
# fi
|
||||
|
||||
for LANGUAGE_CODE in ${SITE_LANGUAGE_CODES//,/ }; do
|
||||
STACK_NAME="$DOMAIN_IDENTIFIER-$LANGUAGE_CODE"
|
||||
|
||||
if [ "$LANGUAGE_CODE" = en ]; then
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
location ~ ^/(ghost/|p/|private/) {
|
||||
EOL
|
||||
else
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
location ~ ^/${LANGUAGE_CODE}/(ghost/|p/|private/) {
|
||||
EOL
|
||||
fi
|
||||
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header Host \$http_host;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
proxy_intercept_errors on;
|
||||
proxy_pass http://ghost-${STACK_NAME}:2368;
|
||||
}
|
||||
|
||||
EOL
|
||||
|
||||
done
|
||||
|
||||
ROOT_SITE_LANGUAGE_CODES="$SITE_LANGUAGE_CODES"
|
||||
for LANGUAGE_CODE in ${ROOT_SITE_LANGUAGE_CODES//,/ }; do
|
||||
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# Location block to back https://${WWW_FQDN}/${LANGUAGE_CODE} or https://${WWW_FQDN}/ if english.
|
||||
EOL
|
||||
|
||||
if [ "$LANGUAGE_CODE" = en ]; then
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
location / {
|
||||
EOL
|
||||
if (( "$LANGUAGE_CODE_COUNT" > 1 )); then
|
||||
# we only need this clause if we know there is more than once lanuage being rendered.
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# Redirect the user to the correct language using the map above.
|
||||
if ( \$http_accept_language !~* '^en(.*)\$' ) {
|
||||
#rewrite (.*) \$1/\$lang;
|
||||
return 302 https://${WWW_FQDN}/\$lang;
|
||||
}
|
||||
|
||||
EOL
|
||||
fi
|
||||
|
||||
else
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
location /${LANGUAGE_CODE} {
|
||||
EOL
|
||||
fi
|
||||
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header Host \$http_host;
|
||||
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
proxy_intercept_errors on;
|
||||
proxy_pass http://ghost-${DOMAIN_IDENTIFIER}-${LANGUAGE_CODE}:2368;
|
||||
|
||||
# https://stanislas.blog/2019/08/ghost-nginx-cache/ for nginx caching instructions
|
||||
# Remove cookies which are useless for anonymous visitor and prevent caching
|
||||
proxy_ignore_headers Set-Cookie Cache-Control;
|
||||
proxy_hide_header Set-Cookie;
|
||||
|
||||
# Add header for cache status (miss or hit)
|
||||
add_header X-Cache-Status \$upstream_cache_status;
|
||||
proxy_cache ${DOMAIN_IDENTIFIER}-${LANGUAGE_CODE};
|
||||
|
||||
# Default TTL: 1 day
|
||||
proxy_cache_valid 5s;
|
||||
|
||||
# Cache 404 pages for 1h
|
||||
proxy_cache_valid 404 1h;
|
||||
|
||||
# use conditional GET requests to refresh the content from origin servers
|
||||
proxy_cache_revalidate on;
|
||||
proxy_buffering on;
|
||||
|
||||
# Allows starting a background subrequest to update an expired cache item,
|
||||
# while a stale cached response is returned to the client.
|
||||
proxy_cache_background_update on;
|
||||
|
||||
# Bypass cache for errors
|
||||
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
|
||||
}
|
||||
|
||||
EOL
|
||||
|
||||
done
|
||||
|
||||
# this is the closing server block for the ghost HTTPS segment
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
|
||||
}
|
||||
|
||||
EOL
|
||||
|
||||
|
||||
if [ "$DEPLOY_NEXTCLOUD" = true ]; then
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# TLS listener for ${NEXTCLOUD_FQDN}
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
|
||||
ssl_certificate $CONTAINER_TLS_PATH/fullchain.pem;
|
||||
ssl_certificate_key $CONTAINER_TLS_PATH/privkey.pem;
|
||||
ssl_trusted_certificate $CONTAINER_TLS_PATH/fullchain.pem;
|
||||
|
||||
server_name ${NEXTCLOUD_FQDN};
|
||||
|
||||
location / {
|
||||
proxy_headers_hash_max_size 512;
|
||||
proxy_headers_hash_bucket_size 64;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
proxy_set_header X-NginX-Proxy true;
|
||||
|
||||
proxy_pass http://${NEXTCLOUD_STACK_TAG}:80;
|
||||
}
|
||||
|
||||
# https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/reverse_proxy_configuration.html
|
||||
location /.well-known/carddav {
|
||||
return 301 \$scheme://\$host/remote.php/dav;
|
||||
}
|
||||
|
||||
location /.well-known/caldav {
|
||||
return 301 \$scheme://\$host/remote.php/dav;
|
||||
}
|
||||
}
|
||||
EOL
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
# TODO this MIGHT be part of the solution for Twitter Cards.
|
||||
# location /contents {
|
||||
# resolver 127.0.0.11 ipv6=off valid=5m;
|
||||
# proxy_set_header X-Real-IP \$remote_addr;
|
||||
# proxy_set_header Host \$http_host;
|
||||
# proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
# proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
# proxy_intercept_errors on;
|
||||
# proxy_pass http://ghost-${DOMAIN_IDENTIFIER}-${SITE_LANGUAGE_CODES}::2368\$og_prefix\$request_uri;
|
||||
# }
|
||||
# this piece is for GITEA.
|
||||
|
||||
if [ "$DEPLOY_GITEA" = true ]; then
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# TLS listener for ${GITEA_FQDN}
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
|
||||
ssl_certificate $CONTAINER_TLS_PATH/fullchain.pem;
|
||||
ssl_certificate_key $CONTAINER_TLS_PATH/privkey.pem;
|
||||
ssl_trusted_certificate $CONTAINER_TLS_PATH/fullchain.pem;
|
||||
|
||||
server_name ${GITEA_FQDN};
|
||||
|
||||
location / {
|
||||
proxy_headers_hash_max_size 512;
|
||||
proxy_headers_hash_bucket_size 64;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
proxy_set_header X-NginX-Proxy true;
|
||||
|
||||
proxy_pass http://gitea-${DOMAIN_IDENTIFIER}-en:3000;
|
||||
}
|
||||
}
|
||||
|
||||
EOL
|
||||
fi
|
||||
|
||||
iteration=$((iteration+1))
|
||||
done
|
||||
|
||||
# add the closing brace.
|
||||
cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
}
|
||||
EOL
|
|
@ -1,137 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
#https://github.com/fiatjaf/expensive-relay
|
||||
# NOSTR RELAY WHICH REQUIRES PAYMENTS.
|
||||
DOCKER_YAML_PATH="$PROJECT_PATH/nginx.yml"
|
||||
cat > "$DOCKER_YAML_PATH" <<EOL
|
||||
version: "3.8"
|
||||
services:
|
||||
|
||||
nginx:
|
||||
image: ${NGINX_IMAGE}
|
||||
ports:
|
||||
- 0.0.0.0:443:443
|
||||
- 0.0.0.0:80:80
|
||||
networks:
|
||||
EOL
|
||||
|
||||
for DOMAIN_NAME in ${DOMAIN_LIST//,/ }; do
|
||||
export DOMAIN_NAME="$DOMAIN_NAME"
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
|
||||
# source the site path so we know what features it has.
|
||||
source "$RESPOSITORY_PATH/reset_env.sh"
|
||||
source "$SITE_PATH/site_definition"
|
||||
source "$RESPOSITORY_PATH/domain_env.sh"
|
||||
|
||||
|
||||
for LANGUAGE_CODE in ${SITE_LANGUAGE_CODES//,/ }; do
|
||||
# We create another ghost instance under /
|
||||
cat >> "$DOCKER_YAML_PATH" <<EOL
|
||||
- ghostnet-$DOMAIN_IDENTIFIER-$LANGUAGE_CODE
|
||||
EOL
|
||||
|
||||
if [ "$LANGUAGE_CODE" = en ]; then
|
||||
if [ "$DEPLOY_GITEA" = "true" ]; then
|
||||
cat >> "$DOCKER_YAML_PATH" <<EOL
|
||||
- giteanet-$DOMAIN_IDENTIFIER-en
|
||||
EOL
|
||||
fi
|
||||
|
||||
if [ "$DEPLOY_NEXTCLOUD" = "true" ]; then
|
||||
cat >> "$DOCKER_YAML_PATH" <<EOL
|
||||
- nextcloudnet-$DOMAIN_IDENTIFIER-en
|
||||
EOL
|
||||
fi
|
||||
|
||||
if [ "$DEPLOY_NOSTR_RELAY" = "true" ]; then
|
||||
cat >> "$DOCKER_YAML_PATH" <<EOL
|
||||
- nostrnet-$DOMAIN_IDENTIFIER-en
|
||||
EOL
|
||||
fi
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
done
|
||||
|
||||
cat >> "$DOCKER_YAML_PATH" <<EOL
|
||||
volumes:
|
||||
- ${REMOTE_HOME}/letsencrypt:/etc/letsencrypt:ro
|
||||
configs:
|
||||
- source: nginx-config
|
||||
target: /etc/nginx/nginx.conf
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
|
||||
configs:
|
||||
nginx-config:
|
||||
file: ${PROJECT_PATH}/nginx.conf
|
||||
|
||||
EOL
|
||||
|
||||
|
||||
|
||||
################ NETWORKS SECTION
|
||||
|
||||
cat >> "$DOCKER_YAML_PATH" <<EOL
|
||||
networks:
|
||||
EOL
|
||||
|
||||
|
||||
for DOMAIN_NAME in ${DOMAIN_LIST//,/ }; do
|
||||
export DOMAIN_NAME="$DOMAIN_NAME"
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
|
||||
# source the site path so we know what features it has.
|
||||
source "$RESPOSITORY_PATH/reset_env.sh"
|
||||
source "$SITE_PATH/site_definition"
|
||||
source "$RESPOSITORY_PATH/domain_env.sh"
|
||||
|
||||
# for each language specified in the site_definition, we spawn a separate ghost container
|
||||
# at https://www.domain.com/$LANGUAGE_CODE
|
||||
for LANGUAGE_CODE in ${SITE_LANGUAGE_CODES//,/ }; do
|
||||
cat >> "$DOCKER_YAML_PATH" <<EOL
|
||||
ghostnet-$DOMAIN_IDENTIFIER-$LANGUAGE_CODE:
|
||||
attachable: true
|
||||
|
||||
EOL
|
||||
|
||||
if [ "$LANGUAGE_CODE" = en ]; then
|
||||
if [ "$DEPLOY_GITEA" = true ]; then
|
||||
cat >> "$DOCKER_YAML_PATH" <<EOL
|
||||
giteanet-$DOMAIN_IDENTIFIER-en:
|
||||
attachable: true
|
||||
|
||||
EOL
|
||||
fi
|
||||
|
||||
if [ "$DEPLOY_NEXTCLOUD" = true ]; then
|
||||
cat >> "$DOCKER_YAML_PATH" <<EOL
|
||||
nextcloudnet-$DOMAIN_IDENTIFIER-en:
|
||||
attachable: true
|
||||
|
||||
EOL
|
||||
fi
|
||||
|
||||
if [ "$DEPLOY_NOSTR_RELAY" = true ]; then
|
||||
cat >> "$DOCKER_YAML_PATH" <<EOL
|
||||
nostrnet-$DOMAIN_IDENTIFIER-en:
|
||||
attachable: true
|
||||
|
||||
EOL
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
|
||||
if [ "$STOP_SERVICES" = false ]; then
|
||||
docker stack deploy -c "$DOCKER_YAML_PATH" "reverse-proxy"
|
||||
# iterate over all our domains and create the nginx config file.
|
||||
sleep 1
|
||||
fi
|
|
@ -1,85 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
docker pull "$NOSTR_RELAY_IMAGE"
|
||||
|
||||
for DOMAIN_NAME in ${DOMAIN_LIST//,/ }; do
|
||||
export DOMAIN_NAME="$DOMAIN_NAME"
|
||||
export SITE_PATH="$SITES_PATH/$DOMAIN_NAME"
|
||||
|
||||
# source the site path so we know what features it has.
|
||||
source "$RESPOSITORY_PATH/reset_env.sh"
|
||||
source "$SITE_PATH/site_definition"
|
||||
source "$RESPOSITORY_PATH/domain_env.sh"
|
||||
|
||||
if [ "$DEPLOY_NOSTR_RELAY" = true ]; then
|
||||
REMOTE_NOSTR_PATH="$REMOTE_HOME/nostr"
|
||||
NOSTR_PATH="$REMOTE_NOSTR_PATH/$DOMAIN_NAME"
|
||||
NOSTR_CONFIG_PATH="$SITE_PATH/webstack/nostr.config"
|
||||
|
||||
ssh "$PRIMARY_WWW_FQDN" mkdir -p "$NOSTR_PATH/data" "$NOSTR_PATH/db"
|
||||
|
||||
export STACK_TAG="nostr-$DOMAIN_IDENTIFIER"
|
||||
export DOCKER_YAML_PATH="$SITE_PATH/webstack/nostr.yml"
|
||||
|
||||
NET_NAME="nostrnet-$DOMAIN_IDENTIFIER"
|
||||
DBNET_NAME="nostrdbnet-$DOMAIN_IDENTIFIER"
|
||||
|
||||
# here's the NGINX config. We support ghost and nextcloud.
|
||||
echo "" > "$DOCKER_YAML_PATH"
|
||||
cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
version: "3.8"
|
||||
services:
|
||||
|
||||
${STACK_TAG}:
|
||||
image: ${NOSTR_RELAY_IMAGE}
|
||||
volumes:
|
||||
- ${NOSTR_PATH}/data:/usr/src/app/db
|
||||
# environment:
|
||||
# - USER_UID=1000
|
||||
networks:
|
||||
- ${NET_NAME}
|
||||
configs:
|
||||
- source: nostr-config
|
||||
target: /usr/src/app/config.toml
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
|
||||
networks:
|
||||
${NET_NAME}:
|
||||
name: "reverse-proxy_${NET_NAME}-en"
|
||||
external: true
|
||||
|
||||
configs:
|
||||
nostr-config:
|
||||
file: ${NOSTR_CONFIG_PATH}
|
||||
EOL
|
||||
|
||||
# documentation: https://git.sr.ht/~gheartsfield/nostr-rs-relay/tree/0.7.0/item/config.toml
|
||||
cat >>"$NOSTR_CONFIG_PATH" <<EOL
|
||||
[info]
|
||||
relay_url = "wss://${NOSTR_FQDN}/"
|
||||
name = "${DOMAIN_NAME}"
|
||||
|
||||
# administrative contact pubkey TODO
|
||||
#pubkey = ""
|
||||
|
||||
[options]
|
||||
reject_future_seconds = 1800
|
||||
|
||||
[limits]
|
||||
messages_per_sec = 3
|
||||
#max_event_bytes = 131072
|
||||
EOL
|
||||
|
||||
if [ "$STOP_SERVICES" = false ]; then
|
||||
docker stack deploy -c "$DOCKER_YAML_PATH" "$DOMAIN_IDENTIFIER-nostr-$LANGUAGE_CODE"
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
done
|
|
@ -1,23 +0,0 @@
|
|||
|
||||
# # tor config
|
||||
# if [ "$DEPLOY_ONION_SITE" = true ]; then
|
||||
# cat >>"$NGINX_CONF_PATH" <<EOL
|
||||
# # server listener for tor v3 onion endpoint
|
||||
# server {
|
||||
# listen 443 ssl http2;
|
||||
# listen [::]:443 ssl http2;
|
||||
# server_name ${ONION_ADDRESS};
|
||||
# #access_log /var/log/nginx/tor-www.log;
|
||||
|
||||
# # administration not allowed over tor interface.
|
||||
# location /ghost { deny all; }
|
||||
# location / {
|
||||
# proxy_set_header X-Forwarded-For 1.1.1.1;
|
||||
# proxy_set_header X-Forwarded-Proto https;
|
||||
# proxy_set_header X-Real-IP 1.1.1.1;
|
||||
# proxy_set_header Host \$http_host;
|
||||
# proxy_pass http://tor-ghost:2368;
|
||||
# }
|
||||
# }
|
||||
# EOL
|
||||
# fi
|
|
@ -1,149 +0,0 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# if [ "$DEPLOY_NEXTCLOUD" = true ]; then
|
||||
# cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
# nextcloud-db:
|
||||
# image: ${NEXTCLOUD_DB_IMAGE}
|
||||
# command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --log-bin --innodb_read_only_compressed=OFF
|
||||
# networks:
|
||||
# - nextclouddb-net
|
||||
# volumes:
|
||||
# - ${REMOTE_HOME}/nextcloud/db/data:/var/lib/mysql
|
||||
# environment:
|
||||
# - MARIADB_ROOT_PASSWORD=\${NEXTCLOUD_MYSQL_ROOT_PASSWORD}
|
||||
# - MYSQL_PASSWORD=\${NEXTCLOUD_MYSQL_PASSWORD}
|
||||
# - MYSQL_DATABASE=nextcloud
|
||||
# - MYSQL_USER=nextcloud
|
||||
# deploy:
|
||||
# restart_policy:
|
||||
# condition: on-failure
|
||||
|
||||
# nextcloud:
|
||||
# image: ${NEXTCLOUD_IMAGE}
|
||||
# networks:
|
||||
# - nextclouddb-net
|
||||
# - nextcloud-net
|
||||
# volumes:
|
||||
# - ${REMOTE_HOME}/nextcloud/html:/var/www/html
|
||||
# environment:
|
||||
# - MYSQL_PASSWORD=\${NEXTCLOUD_MYSQL_PASSWORD}
|
||||
# - MYSQL_DATABASE=nextcloud
|
||||
# - MYSQL_USER=nextcloud
|
||||
# - MYSQL_HOST=nextcloud-db
|
||||
# - NEXTCLOUD_TRUSTED_DOMAINS=${DOMAIN_NAME}
|
||||
# - OVERWRITEHOST=${NEXTCLOUD_FQDN}
|
||||
# - OVERWRITEPROTOCOL=https
|
||||
# - SERVERNAME=${NEXTCLOUD_FQDN}
|
||||
# deploy:
|
||||
# restart_policy:
|
||||
# condition: on-failure
|
||||
|
||||
# EOL
|
||||
# fi
|
||||
|
||||
|
||||
|
||||
# if [ "$DEPLOY_ONION_SITE" = true ]; then
|
||||
# cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
# # a hidden service that routes to the nginx container at http://onionurl.onion server block
|
||||
# tor-onion:
|
||||
# image: tor:latest
|
||||
# networks:
|
||||
# - tor-net
|
||||
# volumes:
|
||||
# - ${REMOTE_HOME}/tor:/var/lib/tor
|
||||
# - tor-logs:/var/log/tor
|
||||
# configs:
|
||||
# - source: tor-config
|
||||
# target: /etc/tor/torrc
|
||||
# mode: 0644
|
||||
# deploy:
|
||||
# mode: replicated
|
||||
# replicas: 1
|
||||
# restart_policy:
|
||||
# condition: on-failure
|
||||
|
||||
# tor-ghost:
|
||||
# image: ${GHOST_IMAGE}
|
||||
# networks:
|
||||
# - ghostdb-net
|
||||
# - ghost-net
|
||||
# volumes:
|
||||
# - ${REMOTE_HOME}/tor_ghost:/var/lib/ghost/content
|
||||
# environment:
|
||||
# - url=https://${ONION_ADDRESS}
|
||||
# - database__client=mysql
|
||||
# - database__connection__host=ghostdb
|
||||
# - database__connection__user=ghost
|
||||
# - database__connection__password=\${GHOST_MYSQL_PASSWORD}
|
||||
# - database__connection__database=ghost
|
||||
# deploy:
|
||||
# restart_policy:
|
||||
# condition: on-failure
|
||||
|
||||
# EOL
|
||||
# fi
|
||||
|
||||
|
||||
# if [ "$DEPLOY_ONION_SITE" = true ]; then
|
||||
# cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
# - torghost-net
|
||||
# EOL
|
||||
# fi
|
||||
|
||||
# if [ "$DEPLOY_NEXTCLOUD" = true ]; then
|
||||
# cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
# - nextcloud-net
|
||||
# EOL
|
||||
# fi
|
||||
|
||||
|
||||
# if [ "$DEPLOY_ONION_SITE" = true ]; then
|
||||
# cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
# - tor-net
|
||||
# EOL
|
||||
# fi
|
||||
|
||||
# if [ "$DEPLOY_ONION_SITE" = true ]; then
|
||||
# cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
|
||||
# volumes:
|
||||
# tor-data:
|
||||
# tor-logs:
|
||||
|
||||
# EOL
|
||||
# fi
|
||||
# #-------------------------
|
||||
|
||||
|
||||
|
||||
# if [ "$DEPLOY_NEXTCLOUD" = true ]; then
|
||||
# cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
# nextclouddb-net:
|
||||
# nextcloud-net:
|
||||
# EOL
|
||||
# fi
|
||||
|
||||
|
||||
# if [ "$DEPLOY_ONION_SITE" = true ]; then
|
||||
# cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
# tor-net:
|
||||
# torghost-net:
|
||||
# EOL
|
||||
# fi
|
||||
# # -------------------------------
|
||||
|
||||
|
||||
# if [ "$DEPLOY_ONION_SITE" = true ]; then
|
||||
# cat >>"$DOCKER_YAML_PATH" <<EOL
|
||||
# tor-config:
|
||||
# file: $(pwd)/tor/torrc
|
||||
# EOL
|
||||
# fi
|
||||
# # -----------------------------
|
|
@ -1,11 +0,0 @@
|
|||
FROM ubuntu:22.04
|
||||
RUN apt-get update && apt-get install -y tor
|
||||
#COPY ./torrc /etc/tor/torrc
|
||||
#RUN chown root:root /etc/tor/torrc
|
||||
#RUN chmod 0644 /etc/tor/torrc
|
||||
|
||||
#RUN mkdir /data
|
||||
#VOLUME /data
|
||||
# RUN chown 1000:1000 -R /data
|
||||
#USER 1000:1000
|
||||
CMD tor -f /etc/tor/torrc
|
|
@ -1,8 +0,0 @@
|
|||
# we configure a hidden service that listens on onion:80 and redirects to nginx:80 at the at the torv3 onion address
|
||||
SocksPort 0
|
||||
|
||||
HiddenServiceDir /var/lib/tor/www
|
||||
HiddenServiceVersion 3
|
||||
HiddenServicePort 443 nginx:443
|
||||
|
||||
Log info file /var/log/tor/tor.log
|
|
@ -1,5 +0,0 @@
|
|||
HiddenServiceDir /var/lib/tor/www
|
||||
HiddenServiceVersion 3
|
||||
HiddenServicePort 443 127.0.0.1:443
|
||||
|
||||
Log info file /var/log/tor/tor.log
|
|
@ -1,27 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
export NEXTCLOUD_FQDN="$NEXTCLOUD_HOSTNAME.$DOMAIN_NAME"
|
||||
export BTCPAY_FQDN="$BTCPAY_HOSTNAME.$DOMAIN_NAME"
|
||||
export BTCPAY_USER_FQDN="$BTCPAY_HOSTNAME_IN_CERT.$DOMAIN_NAME"
|
||||
export WWW_FQDN="$WWW_HOSTNAME.$DOMAIN_NAME"
|
||||
export GITEA_FQDN="$GITEA_HOSTNAME.$DOMAIN_NAME"
|
||||
export NOSTR_FQDN="$NOSTR_HOSTNAME.$DOMAIN_NAME"
|
||||
export ADMIN_ACCOUNT_USERNAME="info"
|
||||
export CERTIFICATE_EMAIL_ADDRESS="$ADMIN_ACCOUNT_USERNAME@$DOMAIN_NAME"
|
||||
export REMOTE_NEXTCLOUD_PATH="$REMOTE_HOME/nextcloud"
|
||||
export REMOTE_GITEA_PATH="$REMOTE_HOME/gitea"
|
||||
export BTC_CHAIN="$BTC_CHAIN"
|
||||
export BTCPAY_ADDITIONAL_HOSTNAMES="$BTCPAY_ADDITIONAL_HOSTNAMES"
|
||||
|
||||
|
||||
SHASUM_OF_DOMAIN="$(echo -n "$DOMAIN_NAME" | sha256sum | awk '{print $1;}' )"
|
||||
export DOMAIN_IDENTIFIER="${SHASUM_OF_DOMAIN: -6}"
|
||||
echo "$DOMAIN_IDENTIFIER" > "$SITE_PATH/domain_id"
|
||||
|
||||
export LANGUAGE_CODE_COUNT=$(("$(echo "$SITE_LANGUAGE_CODES" | tr -cd , | wc -c)"+1))
|
||||
|
||||
STACK_NAME="$DOMAIN_IDENTIFIER-en"
|
||||
export NEXTCLOUD_STACK_TAG="nextcloud-$STACK_NAME"
|
||||
export NEXTCLOUD_DB_STACK_TAG="nextclouddb-$STACK_NAME"
|
|
@ -0,0 +1,14 @@
|
|||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mFIEAAAAABMIKoZIzj0DAQcCAwQ3hQeRT8HLyQEtKJ5C3dKilfWhSpqkPFtfuE0I
|
||||
i+MNLavAM7tL9gShij7tEcyZe0Iy2hc38TizSlQJciIdgtHUtCJEZXJlayBTbWl0
|
||||
aCA8ZGVyZWtAZmFyc2NhcGlhbi5jb20+iIAEExMIABwFAgAAAAACCwkCGwMEFQgJ
|
||||
CgQWAgMBAheAAh4BABYJELRD5TChThyQCxpUUkVaT1ItR1BHXMcA/2k4QtiV0eNQ
|
||||
299XW4Wvoac1Be6+WTPRIaC/PYnd0pR7AP4hi5ou6uyKtqkfhLtRQHN/9ny3MBEG
|
||||
whGxb/bCIzOdILhWBAAAAAASCCqGSM49AwEHAgMEI0VBpCTeIpfdH2UcWiSPYGAJ
|
||||
Z1Rsp0uKf6HzZnpGRAdCTNgCh+pVBibP0Cz0pNdM7IfHSfS+OP4/Lb1B5N9BSAMB
|
||||
CAeIbQQYEwgACQUCAAAAAAIbDAAWCRC0Q+UwoU4ckAsaVFJFWk9SLUdQRxM4AQCw
|
||||
m24svH13uNAebQurOloy/1qZgNdXANBQQ05oi1tEyAD/eGFFVdgs5L6Hpg/GJLvo
|
||||
X8bd1+1sa2d9TldbgfNfRA0=
|
||||
=vZGY
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
243
install.sh
243
install.sh
|
@ -1,65 +1,214 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
set -exu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# let's check to ensure the management machine is on the Baseline ubuntu 21.04
|
||||
if ! lsb_release -d | grep -q "Ubuntu 22.04 LTS"; then
|
||||
echo "ERROR: Your machine is not running the Ubuntu 22.04 LTS baseline OS on your management machine."
|
||||
# https://www.sovereign-stack.org/install/
|
||||
|
||||
# this script is not meant to be executed from the SSME; Let's let's check and abort if so.
|
||||
if [ "$(hostname)" = ss-mgmt ]; then
|
||||
echo "ERROR: This command is meant to be executed from the bare metal management machine -- not the SSME."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f /usr/share/keyrings/docker-archive-keyring.gpg ]; then
|
||||
cat ./certs/docker.gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
||||
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
fi
|
||||
# ensure the iptables forward policy is set to ACCEPT so your host can act as a router
|
||||
# Note this is necessary if docker is running (or has been previuosly installed) on the
|
||||
# same host running incus.
|
||||
sudo iptables -F FORWARD
|
||||
sudo iptables -P FORWARD ACCEPT
|
||||
|
||||
sudo apt-get update
|
||||
# run the incus install script.
|
||||
sudo bash -c ./install_incus.sh
|
||||
|
||||
# TODO REVIEW management machine software requirements
|
||||
# to a host on SERVERS LAN so that it can operate
|
||||
# TODO document which dependencies are required by what software, e.g., trezor, docker, etc.
|
||||
# virt-manager allows us to run type-1 vms desktop version. We use remote viewer to get a GUI for the VM
|
||||
sudo apt-get install -y wait-for-it dnsutils rsync sshfs curl gnupg \
|
||||
apt-transport-https ca-certificates lsb-release docker-ce-cli \
|
||||
python3-pip python3-dev libusb-1.0-0-dev libudev-dev pinentry-curses \
|
||||
libcanberra-gtk-module virt-manager pass
|
||||
# run incus init
|
||||
cat <<EOF | sudo incus admin init --preseed
|
||||
config: {}
|
||||
networks:
|
||||
- config:
|
||||
ipv4.address: auto
|
||||
ipv4.dhcp: true
|
||||
ipv6.address: none
|
||||
description: "Default network bridge for ss-mgmt outbound network access."
|
||||
name: incusbr0
|
||||
type: bridge
|
||||
project: default
|
||||
storage_pools:
|
||||
- config:
|
||||
size: 30GiB
|
||||
description: ""
|
||||
name: sovereign-stack
|
||||
driver: zfs
|
||||
profiles:
|
||||
- config: {}
|
||||
description: "Default profile for ss-mgmt."
|
||||
devices:
|
||||
enp5s0:
|
||||
name: enp5s0
|
||||
network: incusbr0
|
||||
type: nic
|
||||
root:
|
||||
path: /
|
||||
pool: sovereign-stack
|
||||
type: disk
|
||||
name: default
|
||||
projects: []
|
||||
cluster: null
|
||||
|
||||
EOF
|
||||
|
||||
|
||||
# for trezor installation
|
||||
pip3 install setuptools wheel
|
||||
pip3 install trezor_agent
|
||||
. ./deployment/deployment_defaults.sh
|
||||
|
||||
if [ ! -f /etc/udev/rules.d/51-trezor.rules ]; then
|
||||
sudo cp ./51-trezor.rules /etc/udev/rules.d/51-trezor.rules
|
||||
fi
|
||||
|
||||
# TODO initialize pass here; need to first initialize Trezor-T certificates.
|
||||
. ./deployment/base.sh
|
||||
|
||||
|
||||
# install lxd as a snap if it's not installed. We only really use the client part of this package
|
||||
# on the management machine.
|
||||
if ! snap list | grep -q lxd; then
|
||||
sudo snap install lxd --candidate
|
||||
|
||||
# initialize the daemon for auto use. Most of the time on the management machine,
|
||||
# we only use the LXC client -- not the daemon. HOWEVER, there are circustances where
|
||||
# you might want to run the management machine in a LXD-based VM. We we init the lxd daemon
|
||||
# after havning installed it so it'll be available for use.
|
||||
# see https://www.sovereign-stack.org/management/
|
||||
sudo lxd init --auto --storage-pool=default --storage-create-loop=50 --storage-backend=zfs
|
||||
fi
|
||||
|
||||
# make the Sovereign Stack commands available to the user via ~/.bashrc
|
||||
# we use ~/.bashrc
|
||||
ADDED_COMMAND=false
|
||||
for SS_COMMAND in deploy cluster; do
|
||||
if ! < "$HOME/.bashrc" grep -q "ss-$SS_COMMAND"; then
|
||||
echo "alias ss-${SS_COMMAND}='$(pwd)/${SS_COMMAND}.sh \$@'" >> "$HOME/.bashrc"
|
||||
ADDED_COMMAND=true
|
||||
# we need to get the base image. IMport it if it's cached, else download it then cache it.
|
||||
if ! incus image list | grep -q "$UBUNTU_BASE_IMAGE_NAME"; then
|
||||
# if the image if cached locally, import it from disk, otherwise download it from ubuntu
|
||||
IMAGE_PATH="$HOME/ss/cache/ss-ubuntu-jammy"
|
||||
IMAGE_IDENTIFIER=$(find "$IMAGE_PATH" | grep ".qcow2" | head -n1 | cut -d "." -f1)
|
||||
METADATA_FILE="$IMAGE_PATH/meta-$IMAGE_IDENTIFIER.tar.xz"
|
||||
IMAGE_FILE="$IMAGE_PATH/$IMAGE_IDENTIFIER.qcow2"
|
||||
if [ -d "$IMAGE_PATH" ] && [ -f "$METADATA_FILE" ] && [ -f "$IMAGE_FILE" ]; then
|
||||
incus image import "$METADATA_FILE" "$IMAGE_FILE" --alias "$UBUNTU_BASE_IMAGE_NAME"
|
||||
else
|
||||
incus image copy "images:$BASE_INCUS_IMAGE" local: --alias "$UBUNTU_BASE_IMAGE_NAME" --vm --auto-update
|
||||
mkdir -p "$IMAGE_PATH"
|
||||
incus image export "$UBUNTU_BASE_IMAGE_NAME" "$IMAGE_PATH" --vm
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# if the ss-mgmt doesn't exist, create it.
|
||||
SSH_PATH="$HOME/.ssh"
|
||||
SSH_PRIVKEY_PATH="$SSH_PATH/id_rsa"
|
||||
SSH_PUBKEY_PATH="$SSH_PRIVKEY_PATH.pub"
|
||||
|
||||
if [ ! -f "$SSH_PRIVKEY_PATH" ]; then
|
||||
ssh-keygen -f "$SSH_PRIVKEY_PATH" -t rsa -b 4096
|
||||
fi
|
||||
|
||||
# add SSH_PUBKEY_PATH to authorized_keys
|
||||
grep -qxF "$(cat "$SSH_PUBKEY_PATH")" "$SSH_PATH/authorized_keys" || cat "$SSH_PUBKEY_PATH" >> "$SSH_PATH/authorized_keys"
|
||||
|
||||
FROM_BUILT_IMAGE=false
|
||||
if ! incus list --format csv | grep -q ss-mgmt; then
|
||||
|
||||
# TODO check to see if there's an existing ss-mgmt image to spawn from, otherwise do this.
|
||||
if incus image list | grep -q ss-mgmt; then
|
||||
FROM_BUILT_IMAGE=true
|
||||
incus init ss-mgmt ss-mgmt --vm -c limits.cpu=4 -c limits.memory=4GiB --profile=default
|
||||
else
|
||||
incus init "images:$BASE_INCUS_IMAGE" ss-mgmt --vm -c limits.cpu=4 -c limits.memory=4GiB --profile=default
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# mount the pre-verified sovereign stack git repo into the new vm
|
||||
if ! incus config device show ss-mgmt | grep -q ss-code; then
|
||||
incus config device add ss-mgmt ss-code disk source="$(pwd)" path=/home/ubuntu/sovereign-stack
|
||||
fi
|
||||
|
||||
# create the ~/ss path and mount it into the vm.
|
||||
source ./deployment/deployment_defaults.sh
|
||||
source ./deployment/base.sh
|
||||
|
||||
mkdir -p "$SS_ROOT_PATH"
|
||||
|
||||
if ! incus config device show ss-mgmt | grep -q ss-root; then
|
||||
incus config device add ss-mgmt ss-root disk source="$SS_ROOT_PATH" path=/home/ubuntu/ss
|
||||
fi
|
||||
|
||||
# if a ~/.bitcoin/testnet3/blocks direrectory exists, mount it in.
|
||||
BITCOIN_DIR="$HOME/.bitcoin"
|
||||
REMOTE_BITCOIN_CACHE_PATH="/home/ubuntu/ss/cache/bitcoin"
|
||||
BITCOIN_TESTNET_BLOCKS_PATH="$BITCOIN_DIR/testnet3/blocks"
|
||||
if [ -d "$BITCOIN_TESTNET_BLOCKS_PATH" ]; then
|
||||
if ! incus config device show ss-mgmt | grep -q ss-testnet-blocks; then
|
||||
incus config device add ss-mgmt ss-testnet-blocks disk source="$BITCOIN_TESTNET_BLOCKS_PATH" path=$REMOTE_BITCOIN_CACHE_PATH/testnet/blocks
|
||||
fi
|
||||
fi
|
||||
|
||||
# if a ~/.bitcoin/testnet3/blocks direrectory exists, mount it in.
|
||||
BITCOIN_TESTNET_CHAINSTATE_PATH="$BITCOIN_DIR/testnet3/chainstate"
|
||||
if [ -d "$BITCOIN_TESTNET_CHAINSTATE_PATH" ]; then
|
||||
if ! incus config device show ss-mgmt | grep -q ss-testnet-chainstate; then
|
||||
incus config device add ss-mgmt ss-testnet-chainstate disk source="$BITCOIN_TESTNET_CHAINSTATE_PATH" path="$REMOTE_BITCOIN_CACHE_PATH/testnet/chainstate"
|
||||
fi
|
||||
fi
|
||||
|
||||
# if a ~/.bitcoin/blocks dir exists, mount it in.
|
||||
BITCOIN_MAINNET_BLOCKS_PATH="$BITCOIN_DIR/blocks"
|
||||
if [ -d "$BITCOIN_MAINNET_BLOCKS_PATH" ]; then
|
||||
if ! incus config device show ss-mgmt | grep -q ss-mainnet-blocks; then
|
||||
incus config device add ss-mgmt ss-mainnet-blocks disk source="$BITCOIN_MAINNET_BLOCKS_PATH" path="$REMOTE_BITCOIN_CACHE_PATH/mainnet/blocks"
|
||||
fi
|
||||
fi
|
||||
|
||||
# if a ~/.bitcoin/testnet3/blocks direrectory exists, mount it in.
|
||||
BITCOIN_MAINNET_CHAINSTATE_PATH="$BITCOIN_DIR/chainstate"
|
||||
if [ -d "$BITCOIN_MAINNET_CHAINSTATE_PATH" ]; then
|
||||
if ! incus config device show ss-mgmt | grep -q ss-mainnet-blocks; then
|
||||
incus config device add ss-mgmt ss-mainnet-chainstate disk source="$BITCOIN_MAINNET_CHAINSTATE_PATH" path="$REMOTE_BITCOIN_CACHE_PATH/mainnet/chainstate"
|
||||
fi
|
||||
fi
|
||||
|
||||
# mount the ssh directory in there.
|
||||
if [ -f "$SSH_PUBKEY_PATH" ]; then
|
||||
if ! incus config device show ss-mgmt | grep -q ss-ssh; then
|
||||
incus config device add ss-mgmt ss-ssh disk source="$HOME/.ssh" path=/home/ubuntu/.ssh
|
||||
fi
|
||||
fi
|
||||
|
||||
# start the vm if it's not already running
|
||||
if incus list --format csv | grep -q "ss-mgmt,STOPPED"; then
|
||||
incus start ss-mgmt
|
||||
sleep 10
|
||||
fi
|
||||
|
||||
# wait for the vm to have an IP address
|
||||
. ./management/wait_for_ip.sh
|
||||
|
||||
# do some other preparations for user experience
|
||||
incus file push ./management/bash_aliases ss-mgmt/home/ubuntu/.bash_aliases
|
||||
incus file push ./management/bash_profile ss-mgmt/home/ubuntu/.bash_profile
|
||||
incus file push ./management/bashrc ss-mgmt/home/ubuntu/.bashrc
|
||||
incus file push ./management/motd ss-mgmt/etc/update-motd.d/sovereign-stack
|
||||
|
||||
# install SSH
|
||||
incus exec ss-mgmt apt-get update
|
||||
incus exec ss-mgmt -- apt-get install -y openssh-server
|
||||
incus file push ./management/sshd_config ss-mgmt/etc/ssh/sshd_config
|
||||
incus exec ss-mgmt -- sudo systemctl restart sshd
|
||||
|
||||
# add 'ss-manage' to the bare metal ~/.bashrc
|
||||
ADDED_COMMAND=false
|
||||
if ! < "$HOME/.bashrc" grep -q "ss-manage"; then
|
||||
echo "alias ss-manage='$(pwd)/manage.sh \$@'" >> "$HOME/.bashrc"
|
||||
ADDED_COMMAND=true
|
||||
fi
|
||||
|
||||
# Let's remove any entry in our known_hosts, then add it back.
|
||||
# we are using IP address here so we don't have to rely on external DNS
|
||||
# configuration for the base image preparataion.
|
||||
ssh-keygen -R "$IP_V4_ADDRESS"
|
||||
|
||||
ssh-keyscan -H "$IP_V4_ADDRESS" >> "$SSH_HOME/known_hosts"
|
||||
|
||||
ssh "ubuntu@$IP_V4_ADDRESS" sudo chown -R ubuntu:ubuntu /home/ubuntu
|
||||
|
||||
if [ "$FROM_BUILT_IMAGE" = false ]; then
|
||||
ssh "ubuntu@$IP_V4_ADDRESS" /home/ubuntu/sovereign-stack/management/provision.sh
|
||||
|
||||
incus stop ss-mgmt
|
||||
|
||||
if ! incus image list | grep -q "ss-mgmt"; then
|
||||
echo "Publishing image. Please wait, this may take a while..."
|
||||
incus publish ss-mgmt --alias=ss-mgmt
|
||||
fi
|
||||
|
||||
incus start ss-mgmt
|
||||
fi
|
||||
|
||||
if [ "$ADDED_COMMAND" = true ]; then
|
||||
echo "WARNING! You need to run 'source ~/.bashrc' before continuing."
|
||||
echo "NOTICE! You need to run 'source ~/.bashrc' before continuing. After that, type 'ss-manage' to enter your management environment."
|
||||
fi
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -exu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
if [ $UID -ne 0 ]; then
|
||||
echo "ERROR: run with sudo."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# put the zabbly key in there.
|
||||
mkdir -p /etc/apt/keyrings/
|
||||
cat <<EOF > /etc/apt/keyrings/zabbly.asc
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQGNBGTlYcIBDACYQoVXVyQ6Y3Of14GwEaiv/RstQ8jWnH441OtvDbD/VVT8yF0P
|
||||
pUfypWjQS8aq0g32Qgb9H9+b8UAAKojA2W0szjJFlmmSq19YDMMmNC4AnfeZlKYM
|
||||
61Zonna7fPaXmlsTlSiUeo/PGvmAXrkFURC9S8FbhZdWEcUpf9vcKAoEzV8qGA4J
|
||||
xbKlj8EOjSkdq3OQ1hHjP8gynbbzMhZQwjbnWqoiPj35ed9EMn+0QcX+GmynGq6T
|
||||
hBXdRdeQjZC6rmXzNF2opCyxqx3BJ0C7hUtpHegmeoH34wnJHCqGYkEKFAjlRLoW
|
||||
tOzHY9J7OFvB6U7ENtnquj7lg2VQK+hti3uiHW+oide06QgjVw2irucCblQzphgo
|
||||
iX5QJs7tgFFDsA9Ee0DZP6cu83hNFdDcXEZBc9MT5Iu0Ijvj7Oeym3DJpkCuIWgk
|
||||
SeP56sp7333zrg73Ua7YZsZHRayAe/4YdNUua+90P4GD12TpTtJa4iRWRd7bis6m
|
||||
tSkKRj7kxyTsxpEAEQEAAbQmWmFiYmx5IEtlcm5lbCBCdWlsZHMgPGluZm9AemFi
|
||||
Ymx5LmNvbT6JAdQEEwEKAD4WIQRO/FkGlssVuHxzo62CzIeXyDjc/QUCZOVhwgIb
|
||||
AwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRCCzIeXyDjc/W05C/4n
|
||||
lGRTlyOETF2K8oWbjtan9wlttQ+pwymJCnP8T+JJDycGL8dPsGdG1ldHdorVZpFi
|
||||
1P+Bem9bbiW73TpbX+WuCfP1g3WN7AVa2mYRfSVhsLNeBAMRgWgNW9JYsmg99lmY
|
||||
aPsRYZdGu/PB+ffMIyWhjL3CKCbYS6lV5N5Mi4Lobyz/I1Euxpk2vJhhUqh786nJ
|
||||
pQpDnvEl1CRANS6JD9bIvEdfatlAhFlrz1TTf6R7SlppyYI7tme4I/G3dnnHWYSG
|
||||
cGRaLwpwobTq0UNSO71g7+at9eY8dh5nn2lZUvvxZvlbXoOoPxKUoeGVXqoq5F7S
|
||||
QcMVAogYtyNlnLnsUfSPw6YFRaQ5o00h30bR3hk+YmJ47AJCRY9GIc/IEdSnd/Z5
|
||||
Ea7CrP2Bo4zxPgcl8fe311FQRTRoWr19l5PXZgGjzy6siXTrYQi6GjLtqVB5SjJf
|
||||
rrIIy1vZRyDL96WPu6fS+XQMpjsSygj+DBFk8OAvHhQhMCXHgT4BMyg4D5GE0665
|
||||
AY0EZOVhwgEMAMIztf6WlRsweysb0tzktYE5E/GxIK1lwcD10Jzq3ovJJPa2Tg2t
|
||||
J6ZBmMQfwU4OYO8lJxlgm7t6MYh41ZZaRhySCtbJiAXqK08LP9Gc1iWLRvKuMzli
|
||||
NFSiFDFGT1D6kwucVfL/THxvZlQ559kK+LB4iXEKXz37r+MCX1K9uiv0wn63Vm0K
|
||||
gD3HDgfXWYJcNyXXfJBe3/T5AhuSBOQcpa7Ow5n8zJ+OYg3FFKWHDBTSSZHpbJFr
|
||||
ArMIGARz5/f+EVj9XGY4W/+ZJlxNh8FzrTLeRArmCWqKLPRG/KF36dTY7MDpOzlw
|
||||
vu7frv+cgiXHZ2NfPrkH8oOl4L+ufze5KBGcN0QwFDcuwCkv/7Ft9Ta7gVaIBsK7
|
||||
12oHInUJ6EkBovxpuaLlHlP8IfmZLZbbHzR2gR0e6IhLtrzd7urB+gXUtp6+wCL+
|
||||
kWD14TTJhSQ+SFU8ajvUah7/1m2bxdjZNp9pzOPGkr/jEjCM0CpZiCY62SeIJqVc
|
||||
4/ID9NYLAGmSIwARAQABiQG8BBgBCgAmFiEETvxZBpbLFbh8c6OtgsyHl8g43P0F
|
||||
AmTlYcICGwwFCQPCZwAACgkQgsyHl8g43P0wEgv+LuknyXHpYpiUcJOl9Q5yLokd
|
||||
o7tJwJ+9Fu7EDAfM7mPgyBj7Ad/v9RRP+JKWHqIYEjyrRnz9lmzciU+LT/CeoQu/
|
||||
MgpU8wRI4gVtLkX2238amrTKKlVjQUUNHf7cITivUs/8e5W21JfwvcSzu5z4Mxyw
|
||||
L6vMlBUAixtzZSXD6O7MO9uggHUZMt5gDSPXG2RcIgWm0Bd1yTHL7jZt67xBgZ4d
|
||||
hUoelMN2XIDLv4SY78jbHAqVN6CLLtWrz0f5YdaeYj8OT6Ohr/iJQdlfVaiY4ikp
|
||||
DzagLi0LvG9/GuB9eO6yLuojg45JEH8DC7NW5VbdUITxQe9NQ/j5kaRKTEq0fyZ+
|
||||
qsrryTyvXghxK8oMUcI10l8d41qXDDPCA40kruuspCZSAle3zdqpYqiu6bglrgWr
|
||||
Zr2Nm9ecm/kkqMIcyJ8e2mlkuufq5kVem0Oez+GIDegvwnK3HAqWQ9lzdWKvnLiE
|
||||
gNkvg3bqIwZ/WoHBnSwOwwAzwarJl/gn8OG6CIeP
|
||||
=8Uc6
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
EOF
|
||||
|
||||
sh -c 'cat <<EOF > /etc/apt/sources.list.d/zabbly-incus-stable.sources
|
||||
Enabled: yes
|
||||
Types: deb
|
||||
URIs: https://pkgs.zabbly.com/incus/stable
|
||||
Suites: $(. /etc/os-release && echo ${VERSION_CODENAME})
|
||||
Components: main
|
||||
Architectures: $(dpkg --print-architecture)
|
||||
Signed-By: /etc/apt/keyrings/zabbly.asc
|
||||
|
||||
EOF'
|
||||
|
||||
apt-get update
|
||||
|
||||
# we || true this here because installing incus fails.
|
||||
# TODO see if this can be fixed by installing JUST the incus client.
|
||||
# none of the systemd/daemon stuff is needed necessarily.
|
||||
apt-get install incus -y
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#!/bin/bash
|
||||
|
||||
# https://www.sovereign-stack.org/ss-manage/
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# check to ensure dependencies are met.
|
||||
if ! command -v incus >/dev/null 2>&1; then
|
||||
echo "This script requires incus to be installed. Please run 'install.sh'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! incus remote get-default | grep -q "local"; then
|
||||
incus remote switch "local"
|
||||
fi
|
||||
|
||||
if ! incus list -q --format csv | grep -q ss-mgmt; then
|
||||
echo "ERROR: the 'ss-mgmt' VM does not exist. You may need to run install.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# if the mgmt machine doesn't exist, then warn the user to perform ./install.sh
|
||||
if ! incus list --format csv | grep -q "ss-mgmt"; then
|
||||
echo "ERROR: the management machine VM does not exist. You probably need to run './install.sh'."
|
||||
echo "INFO: check out https://www.sovereign-stack.org/tag/code-lifecycle-management/ for more information."
|
||||
fi
|
||||
|
||||
# if the machine does exist, let's make sure it's RUNNING.
|
||||
if incus list --format csv | grep -q "ss-mgmt,STOPPED"; then
|
||||
echo "INFO: The SSME was in a STOPPED state. Starting the environment. Please wait."
|
||||
incus start ss-mgmt
|
||||
sleep 30
|
||||
fi
|
||||
|
||||
. ./management/wait_for_ip.sh
|
||||
|
||||
# let's ensure ~/.ssh/ssh_config is using the correct IP address for ss-mgmt.
|
||||
ssh ubuntu@"$IP_V4_ADDRESS"
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
alias ss-help='cat /home/ubuntu/sovereign-stack/deployment/help.txt'
|
||||
alias ss-show='/home/ubuntu/sovereign-stack/deployment/show.sh $@'
|
||||
alias ss-remote='/home/ubuntu/sovereign-stack/deployment/remote.sh $@'
|
||||
alias ss-up='/home/ubuntu/sovereign-stack/deployment/up.sh $@'
|
||||
alias ss-down='/home/ubuntu/sovereign-stack/deployment/down.sh $@'
|
||||
alias ss-reset='/home/ubuntu/sovereign-stack/deployment/reset.sh $@'
|
||||
alias ss-stop='/home/ubuntu/sovereign-stack/deployment/stop.sh $@'
|
||||
alias ss-start='/home/ubuntu/sovereign-stack/deployment/start.sh $@'
|
||||
alias ss-restore='/home/ubuntu/sovereign-stack/deployment/restore.sh $@'
|
||||
|
||||
alias ll='ls -lah'
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
# this wires up the aliases for remote ssh sessions.
|
||||
if [ -f ~/.bashrc ]; then
|
||||
. ~/.bashrc
|
||||
fi
|
|
@ -0,0 +1,117 @@
|
|||
# ~/.bashrc: executed by bash(1) for non-login shells.
|
||||
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
|
||||
# for examples
|
||||
|
||||
# If not running interactively, don't do anything
|
||||
case $- in
|
||||
*i*) ;;
|
||||
*) return;;
|
||||
esac
|
||||
|
||||
# don't put duplicate lines or lines starting with space in the history.
|
||||
# See bash(1) for more options
|
||||
HISTCONTROL=ignoreboth
|
||||
|
||||
# append to the history file, don't overwrite it
|
||||
shopt -s histappend
|
||||
|
||||
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
|
||||
HISTSIZE=1000
|
||||
HISTFILESIZE=2000
|
||||
|
||||
# check the window size after each command and, if necessary,
|
||||
# update the values of LINES and COLUMNS.
|
||||
shopt -s checkwinsize
|
||||
|
||||
# If set, the pattern "**" used in a pathname expansion context will
|
||||
# match all files and zero or more directories and subdirectories.
|
||||
#shopt -s globstar
|
||||
|
||||
# make less more friendly for non-text input files, see lesspipe(1)
|
||||
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
|
||||
|
||||
# set variable identifying the chroot you work in (used in the prompt below)
|
||||
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
|
||||
debian_chroot=$(cat /etc/debian_chroot)
|
||||
fi
|
||||
|
||||
# set a fancy prompt (non-color, unless we know we "want" color)
|
||||
case "$TERM" in
|
||||
xterm-color|*-256color) color_prompt=yes;;
|
||||
esac
|
||||
|
||||
# uncomment for a colored prompt, if the terminal has the capability; turned
|
||||
# off by default to not distract the user: the focus in a terminal window
|
||||
# should be on the output of commands, not on the prompt
|
||||
#force_color_prompt=yes
|
||||
|
||||
if [ -n "$force_color_prompt" ]; then
|
||||
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
|
||||
# We have color support; assume it's compliant with Ecma-48
|
||||
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
|
||||
# a case would tend to support setf rather than setaf.)
|
||||
color_prompt=yes
|
||||
else
|
||||
color_prompt=
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$color_prompt" = yes ]; then
|
||||
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
|
||||
else
|
||||
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
|
||||
fi
|
||||
unset color_prompt force_color_prompt
|
||||
|
||||
# If this is an xterm set the title to user@host:dir
|
||||
case "$TERM" in
|
||||
xterm*|rxvt*)
|
||||
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
# enable color support of ls and also add handy aliases
|
||||
if [ -x /usr/bin/dircolors ]; then
|
||||
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
|
||||
alias ls='ls --color=auto'
|
||||
#alias dir='dir --color=auto'
|
||||
#alias vdir='vdir --color=auto'
|
||||
|
||||
alias grep='grep --color=auto'
|
||||
alias fgrep='fgrep --color=auto'
|
||||
alias egrep='egrep --color=auto'
|
||||
fi
|
||||
|
||||
# colored GCC warnings and errors
|
||||
export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
|
||||
|
||||
# some more ls aliases
|
||||
alias ll='ls -alF'
|
||||
alias la='ls -A'
|
||||
alias l='ls -CF'
|
||||
|
||||
# Add an "alert" alias for long running commands. Use like so:
|
||||
# sleep 10; alert
|
||||
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
|
||||
|
||||
# Alias definitions.
|
||||
# You may want to put all your additions into a separate file like
|
||||
# ~/.bash_aliases, instead of adding them here directly.
|
||||
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
|
||||
|
||||
if [ -f ~/.bash_aliases ]; then
|
||||
. ~/.bash_aliases
|
||||
fi
|
||||
|
||||
# enable programmable completion features (you don't need to enable
|
||||
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
|
||||
# sources /etc/bash.bashrc).
|
||||
if ! shopt -oq posix; then
|
||||
if [ -f /usr/share/bash-completion/bash_completion ]; then
|
||||
. /usr/share/bash-completion/bash_completion
|
||||
elif [ -f /etc/bash_completion ]; then
|
||||
. /etc/bash_completion
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo "Welcome to the management environment. Run 'ss-help' to get started."
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# NOTE! This script MUST be executed as root.
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ca-certificates curl gnupg lsb-release jq bc
|
||||
|
||||
sudo mkdir -m 0755 -p /etc/apt/keyrings
|
||||
|
||||
# add the docker gpg key to keyring for docker-ce-cli
|
||||
if [ ! -f /etc/apt/keyrings/docker.gpg ]; then
|
||||
cat /home/ubuntu/sovereign-stack/certs/docker.gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
# TODO REVIEW mgmt software requirements
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y wait-for-it dnsutils rsync sshfs apt-transport-https docker-ce-cli libcanberra-gtk-module nano git gridsite-clients
|
||||
|
||||
sudo bash -c "$HOME/sovereign-stack/install_incus.sh"
|
||||
|
||||
sudo incus admin init --minimal
|
||||
|
||||
# add docker group
|
||||
if ! grep -q "^docker:" /etc/group; then
|
||||
sudo groupadd docker
|
||||
fi
|
||||
|
||||
# add incus-admin group
|
||||
if ! grep -q "^incus-admin:" /etc/group; then
|
||||
sudo groupadd incus-admin
|
||||
fi
|
||||
|
||||
if ! groups ubuntu | grep -q "\bdocker\b"; then
|
||||
sudo usermod -aG docker ubuntu
|
||||
fi
|
||||
|
||||
if ! groups ubuntu | grep -q "\bincus-admin\b"; then
|
||||
sudo usermod -aG incus-admin ubuntu
|
||||
fi
|
|
@ -0,0 +1,116 @@
|
|||
# This is the sshd server system-wide configuration file. See
|
||||
# sshd_config(5) for more information.
|
||||
|
||||
# This sshd was compiled with PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
|
||||
|
||||
# The strategy used for options in the default sshd_config shipped with
|
||||
# OpenSSH is to specify options with their default value where
|
||||
# possible, but leave them commented. Uncommented options override the
|
||||
# default value.
|
||||
|
||||
Include /etc/ssh/sshd_config.d/*.conf
|
||||
|
||||
Port 22
|
||||
#AddressFamily any
|
||||
ListenAddress 0.0.0.0
|
||||
#ListenAddress ::
|
||||
|
||||
#HostKey /etc/ssh/ssh_host_rsa_key
|
||||
#HostKey /etc/ssh/ssh_host_ecdsa_key
|
||||
#HostKey /etc/ssh/ssh_host_ed25519_key
|
||||
|
||||
# Ciphers and keying
|
||||
#RekeyLimit default none
|
||||
|
||||
# Logging
|
||||
#SyslogFacility AUTH
|
||||
#LogLevel INFO
|
||||
|
||||
# Authentication:
|
||||
|
||||
#LoginGraceTime 2m
|
||||
#PermitRootLogin prohibit-password
|
||||
#StrictModes yes
|
||||
#MaxAuthTries 6
|
||||
#MaxSessions 10
|
||||
|
||||
#PubkeyAuthentication yes
|
||||
|
||||
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
|
||||
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
|
||||
|
||||
#AuthorizedPrincipalsFile none
|
||||
|
||||
#AuthorizedKeysCommand none
|
||||
#AuthorizedKeysCommandUser nobody
|
||||
|
||||
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
|
||||
#HostbasedAuthentication no
|
||||
# Change to yes if you don't trust ~/.ssh/known_hosts for
|
||||
# HostbasedAuthentication
|
||||
#IgnoreUserKnownHosts no
|
||||
# Don't read the user's ~/.rhosts and ~/.shosts files
|
||||
#IgnoreRhosts yes
|
||||
|
||||
# To disable tunneled clear text passwords, change to no here!
|
||||
#PasswordAuthentication yes
|
||||
#PermitEmptyPasswords no
|
||||
|
||||
# Change to yes to enable challenge-response passwords (beware issues with
|
||||
# some PAM modules and threads)
|
||||
KbdInteractiveAuthentication no
|
||||
|
||||
# Kerberos options
|
||||
#KerberosAuthentication no
|
||||
#KerberosOrLocalPasswd yes
|
||||
#KerberosTicketCleanup yes
|
||||
#KerberosGetAFSToken no
|
||||
|
||||
# GSSAPI options
|
||||
#GSSAPIAuthentication no
|
||||
#GSSAPICleanupCredentials yes
|
||||
#GSSAPIStrictAcceptorCheck yes
|
||||
#GSSAPIKeyExchange no
|
||||
|
||||
# Set this to 'yes' to enable PAM authentication, account processing,
|
||||
# and session processing. If this is enabled, PAM authentication will
|
||||
# be allowed through the KbdInteractiveAuthentication and
|
||||
# PasswordAuthentication. Depending on your PAM configuration,
|
||||
# PAM authentication via KbdInteractiveAuthentication may bypass
|
||||
# the setting of "PermitRootLogin without-password".
|
||||
# If you just want the PAM account and session checks to run without
|
||||
# PAM authentication, then enable this but set PasswordAuthentication
|
||||
# and KbdInteractiveAuthentication to 'no'.
|
||||
UsePAM yes
|
||||
|
||||
#AllowAgentForwarding yes
|
||||
#AllowTcpForwarding yes
|
||||
#GatewayPorts no
|
||||
X11Forwarding yes
|
||||
#X11DisplayOffset 10
|
||||
#X11UseLocalhost yes
|
||||
#PermitTTY yes
|
||||
#PrintMotd no
|
||||
#PrintLastLog yes
|
||||
#TCPKeepAlive yes
|
||||
#PermitUserEnvironment no
|
||||
#Compression delayed
|
||||
#ClientAliveInterval 0
|
||||
#ClientAliveCountMax 3
|
||||
#UseDNS no
|
||||
#PidFile /run/sshd.pid
|
||||
#MaxStartups 10:30:100
|
||||
#PermitTunnel no
|
||||
#ChrootDirectory none
|
||||
#VersionAddendum none
|
||||
|
||||
# no default banner path
|
||||
#Banner none
|
||||
|
||||
# Allow client to pass locale environment variables
|
||||
AcceptEnv LANG LC_*
|
||||
|
||||
# override default of no subsystems
|
||||
Subsystem sftp /usr/lib/openssh/sftp-server
|
||||
|
||||
PrintMotd yes
|
|
@ -0,0 +1,32 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
IP_V4_ADDRESS=
|
||||
while true; do
|
||||
# wait for
|
||||
if incus list ss-mgmt | grep -q enp5s0; then
|
||||
break;
|
||||
else
|
||||
sleep 1
|
||||
fi
|
||||
done
|
||||
|
||||
while true; do
|
||||
IP_V4_ADDRESS=$(incus list ss-mgmt --format csv --columns=4 | grep enp5s0 | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
|
||||
if [ -n "$IP_V4_ADDRESS" ]; then
|
||||
# give the machine extra time to spin up.
|
||||
break;
|
||||
else
|
||||
sleep 1
|
||||
printf '.'
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
export IP_V4_ADDRESS="$IP_V4_ADDRESS"
|
||||
|
||||
# wait for the VM to complete its default cloud-init.
|
||||
while incus exec ss-mgmt -- [ ! -f /var/lib/cloud/instance/boot-finished ]; do
|
||||
sleep 1
|
||||
done
|
98
migrate.sh
98
migrate.sh
|
@ -1,98 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
CURRENT_CLUSTER="$(lxc remote get-default)"
|
||||
|
||||
if echo "$CURRENT_CLUSTER" | grep -q "production"; then
|
||||
echo "WARNING: You are running a migration procedure on a production system."
|
||||
echo ""
|
||||
|
||||
|
||||
RESPONSE=
|
||||
read -r -p " Are you sure you want to continue (y) ": RESPONSE
|
||||
if [ "$RESPONSE" != "y" ]; then
|
||||
echo "STOPPING."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
source ./defaults.sh
|
||||
|
||||
export CLUSTER_PATH="$CLUSTERS_DIR/$CURRENT_CLUSTER"
|
||||
CLUSTER_DEFINITION="$CLUSTER_PATH/cluster_definition"
|
||||
export CLUSTER_DEFINITION="$CLUSTER_DEFINITION"
|
||||
|
||||
# ensure the cluster definition exists.
|
||||
if [ ! -f "$CLUSTER_DEFINITION" ]; then
|
||||
echo "ERROR: The cluster definition could not be found. You may need to re-run 'ss-cluster create'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$CLUSTER_DEFINITION"
|
||||
|
||||
# source project defition.
|
||||
# Now let's load the project definition.
|
||||
PROJECT_PATH="$PROJECTS_DIR/$PROJECT_NAME"
|
||||
PROJECT_DEFINITION_PATH="$PROJECT_PATH/project_definition"
|
||||
source "$PROJECT_DEFINITION_PATH"
|
||||
|
||||
export PRIMARY_SITE_DEFINITION_PATH="$SITES_PATH/$PRIMARY_DOMAIN/site_definition"
|
||||
source "$PRIMARY_SITE_DEFINITION_PATH"
|
||||
|
||||
# Check to see if any of the VMs actually don't exist.
|
||||
# (we only migrate instantiated vms)
|
||||
for VM in www btcpayserver; do
|
||||
LXD_NAME="$VM-${DOMAIN_NAME//./-}"
|
||||
|
||||
# if the VM doesn't exist, the we emit an error message and hard quit.
|
||||
if ! lxc list --format csv | grep -q "$LXD_NAME"; then
|
||||
echo "ERROR: there is no VM named '$LXD_NAME'. You probably need to run ss-deploy again."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
BTCPAY_RESTORE_ARCHIVE_PATH="$SITES_PATH/$PRIMARY_DOMAIN/backups/btcpayserver/$(date +%s).tar.gz"
|
||||
echo "INFO: The BTCPAY_RESTORE_ARCHIVE_PATH for this migration will be: $BTCPAY_RESTORE_ARCHIVE_PATH"
|
||||
|
||||
# first we run ss-deploy --stop
|
||||
# this grabs a backup of all data (backups are on by default) and saves them to the management machine
|
||||
# the --stop flag ensures that services do NOT come back online.
|
||||
# by default, we grab a backup.
|
||||
|
||||
bash -c "./deploy.sh --stop --backup-archive-path=$BTCPAY_RESTORE_ARCHIVE_PATH"
|
||||
|
||||
RESPONSE=
|
||||
read -r -p "Are you sure you want to continue the migration? We have a backup TODO.": RESPONSE
|
||||
if [ "$RESPONSE" != "y" ]; then
|
||||
echo "STOPPING."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
for VM in www btcpayserver; do
|
||||
LXD_NAME="$VM-${DOMAIN_NAME//./-}"
|
||||
lxc delete -f "$LXD_NAME"
|
||||
|
||||
lxc profile delete "$LXD_NAME"
|
||||
done
|
||||
|
||||
|
||||
# delete the base image so it can be created.
|
||||
if lxc list | grep -q sovereign-stack-base; then
|
||||
lxc delete -f sovereign-stack-base
|
||||
fi
|
||||
|
||||
# these only get initialzed upon creation, so we MUST delete here so they get recreated.
|
||||
if lxc profile list | grep -q sovereign-stack; then
|
||||
lxc profile delete sovereign-stack
|
||||
fi
|
||||
|
||||
if lxc image list | grep -q "sovereign-stack-base"; then
|
||||
lxc image rm sovereign-stack-base
|
||||
fi
|
||||
|
||||
# Then we can run a restore operation and specify the backup archive at the CLI.
|
||||
bash -c "./deploy.sh -y --restore-www --restore-btcpay --backup-archive-path=$BTCPAY_RESTORE_ARCHIVE_PATH"
|
22
publish.sh
22
publish.sh
|
@ -1,22 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -exu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# this script will tag the repo then push it to origin
|
||||
TAG_NAME="$(head -n 1 ./version.txt)"
|
||||
TAG_MESSAGE="Creating tag $TAG_NAME on $(date)."
|
||||
|
||||
git tag -a "$TAG_NAME" -m "$TAG_MESSAGE" -s
|
||||
|
||||
# optional; push to remote
|
||||
git push --set-upstream origin --all
|
||||
git push --set-upstream origin --tags
|
||||
|
||||
RESPONSE=
|
||||
read -r -p " Would you like to push this to the main ss repo? (y) ": RESPONSE
|
||||
if [ "$RESPONSE" != "y" ]; then
|
||||
# optional; push to remote
|
||||
git push --set-upstream ss-upstream --all
|
||||
git push --set-upstream ss-upstream --tags
|
||||
fi
|
39
reset.sh
39
reset.sh
|
@ -1,39 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
SSH_ENDPOINT_HOSTNAME="atlantis"
|
||||
SSH_ENDPOINT_DOMAIN_NAME="ancapistan.io"
|
||||
TEST_DOMAIN="ancapistan.casa"
|
||||
CLUSTER_NAME="development"
|
||||
|
||||
export LXD_VM_NAME="${TEST_DOMAIN//./-}"
|
||||
|
||||
if [ -n "$TEST_DOMAIN" ]; then
|
||||
lxc delete --force www-"$LXD_VM_NAME"
|
||||
lxc delete --force btcpay-"$LXD_VM_NAME"
|
||||
lxc delete --force sovereign-stack
|
||||
lxc delete --force sovereign-stack-base
|
||||
|
||||
lxc profile delete www-"$LXD_VM_NAME"
|
||||
lxc profile delete btcpay-"$LXD_VM_NAME"
|
||||
fi
|
||||
|
||||
lxc profile delete sovereign-stack
|
||||
|
||||
lxc image rm sovereign-stack-base
|
||||
lxc image rm ubuntu-base
|
||||
|
||||
lxc network delete lxdbrSS
|
||||
|
||||
lxc storage delete sovereign-stack
|
||||
|
||||
lxc remote switch "local"
|
||||
lxc remote remove "$CLUSTER_NAME"
|
||||
|
||||
source "$HOME/.bashrc"
|
||||
|
||||
./cluster.sh create "$CLUSTER_NAME" "$SSH_ENDPOINT_HOSTNAME.$SSH_ENDPOINT_DOMAIN_NAME"
|
||||
#--data-plane-interface=enp89s0
|
||||
|
||||
#./deploy.sh
|
23
reset_env.sh
23
reset_env.sh
|
@ -1,23 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
export DOMAIN_NAME=
|
||||
export DUPLICITY_BACKUP_PASSPHRASE=
|
||||
export BTCPAY_HOSTNAME_IN_CERT=
|
||||
export DEPLOY_GHOST=true
|
||||
export DEPLOY_NEXTCLOUD=false
|
||||
export DEPLOY_NOSTR_RELAY=true
|
||||
export NOSTR_ACCOUNT_PUBKEY=
|
||||
export DEPLOY_GITEA=false
|
||||
export DEPLOY_ONION_SITE=false
|
||||
export GHOST_MYSQL_PASSWORD=
|
||||
export GHOST_MYSQL_ROOT_PASSWORD=
|
||||
export NEXTCLOUD_MYSQL_PASSWORD=
|
||||
export NEXTCLOUD_MYSQL_ROOT_PASSWORD=
|
||||
export GITEA_MYSQL_PASSWORD=
|
||||
export GITEA_MYSQL_ROOT_PASSWORD=
|
||||
export LANGUAGE_CODE="en"
|
||||
|
||||
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
source "$SCRIPT_DIR/defaults.sh"
|
|
@ -1,7 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
lxc list
|
||||
lxc network list
|
||||
lxc profile list
|
||||
lxc storage list
|
||||
lxc image list
|
|
@ -1,17 +0,0 @@
|
|||
FROM ubuntu:22.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && apt-get install -y wait-for-it dnsutils rsync sshfs snapd lxd-client
|
||||
|
||||
RUN mkdir /sovereign-stack
|
||||
COPY ./deployment /sovereign-stack
|
||||
WORKDIR /sovereign-stack
|
||||
|
||||
RUN mkdir /domain
|
||||
VOLUME /domain
|
||||
ENV SITE_PATH=/domain
|
||||
|
||||
COPY ./entrypoint.sh /entrypoint.sh
|
||||
RUN chmod 0744 /entrypoint.sh
|
||||
|
||||
CMD /entrypoint.sh
|
|
@ -1,8 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [ -z "$DOMAIN_NAME" ]; then
|
||||
echo "ERROR: DOMAIN_NAME not defined.".
|
||||
exit 1
|
||||
fi
|
||||
|
||||
/sovereign-stack/deploy.sh --domain="$DOMAIN_NAME"
|
|
@ -1,32 +0,0 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
|
||||
# a hidden service that routes to the nginx container at http://onionurl.onion server block
|
||||
tor-onion:
|
||||
image: tor:latest
|
||||
networks:
|
||||
- tor-net
|
||||
volumes:
|
||||
- ${REMOTE_HOME}/tor:/var/lib/tor
|
||||
- tor-logs:/var/log/tor
|
||||
configs:
|
||||
- source: tor-config
|
||||
target: /etc/tor/torrc
|
||||
mode: 0644
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
|
||||
volumes:
|
||||
tor-data:
|
||||
tor-logs:
|
||||
|
||||
networks:
|
||||
tor-net:
|
||||
attachable: true
|
||||
|
||||
configs:
|
||||
tor-config:
|
||||
file: ${TOR_CONFIG_PATH}
|
|
@ -0,0 +1,93 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -exu
|
||||
|
||||
# this script uninstalls incus from the MANAGEMENT MACHINE
|
||||
# if you want to remove incus from remote cluster hosts, run ss-reset.
|
||||
|
||||
PURGE_INCUS=false
|
||||
|
||||
# grab any modifications from the command line.
|
||||
for i in "$@"; do
|
||||
case $i in
|
||||
--purge)
|
||||
PURGE_INCUS=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unexpected option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# this script undoes install.sh
|
||||
if ! command -v incus >/dev/null 2>&1; then
|
||||
echo "This script requires incus to be installed. Please run 'install.sh'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! incus remote get-default | grep -q "local"; then
|
||||
echo "ERROR: You MUST be on the local remote when uninstalling the SSME."
|
||||
echo "INFO: You can use 'incus remote switch local' to do this."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
if ! incus project list | grep -q "default (current)"; then
|
||||
echo "ERROR: You MUST be on the default project when uninstalling the SSME."
|
||||
echo "INFO: You can use 'incus project switch default' to do this."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
if incus list --format csv | grep -q "ss-mgmt"; then
|
||||
|
||||
if incus list --format csv -q | grep -q "ss-mgmt,RUNNING"; then
|
||||
incus stop ss-mgmt
|
||||
fi
|
||||
|
||||
if incus config device list ss-mgmt -q | grep -q "ss-code"; then
|
||||
incus config device remove ss-mgmt ss-code
|
||||
fi
|
||||
|
||||
if incus config device list ss-mgmt -q | grep -q "ss-root"; then
|
||||
incus config device remove ss-mgmt ss-root
|
||||
fi
|
||||
|
||||
if incus config device list ss-mgmt -q | grep -q "ss-ssh"; then
|
||||
incus config device remove ss-mgmt ss-ssh
|
||||
fi
|
||||
|
||||
incus delete ss-mgmt
|
||||
fi
|
||||
|
||||
if [ "$PURGE_INCUS" = true ]; then
|
||||
|
||||
if incus profile device list default | grep -q root; then
|
||||
incus profile device remove default root
|
||||
fi
|
||||
|
||||
if incus profile device list default | grep -q enp5s0; then
|
||||
incus profile device remove default enp5s0
|
||||
fi
|
||||
|
||||
if incus network list --project default | grep -q incusbr0; then
|
||||
incus network delete incusbr0
|
||||
fi
|
||||
|
||||
# this file contains the BASE_IMAGE_NAME
|
||||
. ./deployment/base.sh
|
||||
if incus image list | grep -q "$UBUNTU_BASE_IMAGE_NAME"; then
|
||||
incus image delete "$UBUNTU_BASE_IMAGE_NAME"
|
||||
fi
|
||||
|
||||
if incus storage list --format csv | grep -q sovereign-stack; then
|
||||
incus storage delete sovereign-stack
|
||||
fi
|
||||
|
||||
if dpkg -l | grep -q incus; then
|
||||
sudo apt purge incus -y
|
||||
fi
|
||||
|
||||
fi
|
|
@ -1 +0,0 @@
|
|||
v0.0.22
|
Loading…
Reference in New Issue