Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
[submodule "ci-cd-automation/Proxmox-Launchpad"]
path = ci-cd-automation/Proxmox-Launchpad
url = https://github.com/maxklema/proxmox-launchpad.git
[submodule "mie-opensource-landing"]
path = mie-opensource-landing
url = https://github.com/maxklema/mie-opensource-landing
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

Configuration storage for the [opensource.mieweb.org](https://opensource.mieweb.org:8006) Proxmox project.

To learn everything there is about our cluster, see our documentation at [https://opensource.mieweb.org/docs/intro](https://opensource.mieweb.org/docs/intro).

This repository contains configuration files and scripts for managing a Proxmox-based container hosting environment, including automated DNS, NGINX reverse proxy, dynamic port mapping, and the Proxmox LaunchPad GitHub Action for automated container deployment.

## Cluster Graph
Expand Down Expand Up @@ -99,6 +101,11 @@ If you have an account in the [opensource-mieweb](https://opensource.mieweb.org:
- Use the Command Line: ssh create-container@opensource.mieweb.org (mie123!)
- Use the Proxmox LaunchPad Github Action to automatically provision, update, and delete containers for you: [Proxmox LaunchPad](#proxmox-launchpad)

## MIE Opensource Landing

Contains all the source code for [https://opensource.mieweb.org's](https://opensource.mieweb.org) landing page, built with React + Docusaurus.
- Documentation is located at [https://opensource.mieweb.org/docs/intro](https://opensource.mieweb.org/docs/intro).

## How It Works

- **DNS**: All `*.opensource.mieweb.com` requests are routed to the NGINX proxy via Dnsmasq, providing automatic subdomain resolution for containers.
Expand Down
4 changes: 2 additions & 2 deletions ci-cd-automation/check-container-exists.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ REPO_BASE_NAME=$(basename -s .git "$PROJECT_REPOSITORY")

# Check if repository folder is present.
if [ "$PVE1" == "true" ]; then
if pct exec $CONTAINER_ID -- test -f /root/container-updates.log; then
if [ ! -z "$CONTAINER_ID" ] && pct exec $CONTAINER_ID -- test -f /root/container-updates.log; then
exit 2; # Update Repository
else
exit 0; # Clone Repository
fi
else
if ssh 10.15.0.5 "pct exec $CONTAINER_ID -- test -f /root/container-updates.log"; then
if [ ! -z "$CONTAINER_ID" ] && ssh 10.15.0.5 "pct exec $CONTAINER_ID -- test -f /root/container-updates.log" ; then
exit 2; # Update Repository
else
exit 0; # Clone Repository
Expand Down
2 changes: 1 addition & 1 deletion ci-cd-automation/helper-scripts/PVE_user_authentication.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ if [ -z "$PROXMOX_PASSWORD" ]; then
echo ""
fi

USER_AUTHENTICATED=$(ssh root@10.15.234.122 "node /root/bin/js/runner.js authenticateUser \"$PROXMOX_USERNAME\" \"$PROXMOX_PASSWORD\"")
USER_AUTHENTICATED=$(ssh root@create-container "node /root/bin/js/runner.js authenticateUser \"$PROXMOX_USERNAME\" \"$PROXMOX_PASSWORD\"")

if [ $USER_AUTHENTICATED == 'false' ]; then
outputError 1 "Your Proxmox account, $PROXMOX_USERNAME@pve, was not authenticated. Retry with valid credentials."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ outputError() {
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
echo -e "${BOLD}${MAGENTA}❌ Script Failed. Exiting... ${RESET}"
echo -e "$2"
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
exit $1
}

Expand All @@ -26,7 +26,7 @@ source /var/lib/vz/snippets/helper-scripts/verify_container_ownership.sh #Ensure
if [ ! -z "$CONTAINER_OWNERSHIP" ]; then
outputError 1 "You already own a container with name \"$CONTAINER_NAME\". Please delete it before creating a new one."
fi

# Cloning Container Template and Setting it up =====

REPO_BASE_NAME=$(basename -s .git "$PROJECT_REPOSITORY")
Expand Down Expand Up @@ -117,8 +117,6 @@ echo "$PUB_KEY" >> /home/update-container/.ssh/authorized_keys
echo "$PUB_KEY" >> /home/delete-container/.ssh/authorized_keys
echo "$PUB_KEY" >> /home/container-exists/.ssh/authorized_keys

ssh root@10.15.234.122 "echo \"$PUB_KEY\" >> /root/.ssh/authorized_keys"

echo "🔑 Creating Service File..."
pct exec $NEXT_ID -- bash -c "cat <<EOF > /etc/systemd/system/github-runner.service
[Unit]
Expand Down
92 changes: 75 additions & 17 deletions ci-cd-automation/update-container.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash
# Script to automatically fetch new contents from a branch, push them to container, and restart intern
# Last Modified on August 5th, 2025 by Maxwell Klema
# Last Modified on August 17th, 2025 by Maxwell Klema
# ----------------------------------------

RESET="\033[0m"
Expand Down Expand Up @@ -65,7 +65,7 @@ if [ "$REPOSITORY_BRANCH_EXISTS" != "200" ]; then
fi


# # Get Project Root Directroy
# Get Project Root Directroy

if [ "$PROJECT_ROOT" == "." ] || [ -z "$PROJECT_ROOT" ]; then
PROJECT_ROOT="/"
Expand Down Expand Up @@ -116,7 +116,6 @@ if [ ! -z "$HTTP_PORT" ]; then
&& mv -f /tmp/port_map.json.new /etc/nginx/port_map.json "
fi


# Clone repository if needed ====

if (( "$CONTAINER_ID" % 2 == 0 )); then
Expand All @@ -137,6 +136,64 @@ fi
EOF
fi

# Update Environment Variables

if [ ! -z "$RUNTIME_LANGUAGE" ] && echo "$RUNTIME_LANGUAGE" | jq . >/dev/null 2>&1; then # If RUNTIME_LANGUAGE is set and is valid JSON
MULTI_COMPONENT="Y"
fi

# Helper Function to write environment variables to a file inside container
writeEnvToFile() {
env_file_path="$1"
component_path="$2"
env_vars=$(cat "$env_file_path")
if (( $CONTAINER_ID % 2 == 0 )); then
ssh 10.15.0.5 "pct exec $CONTAINER_ID -- bash -c 'if [ ! -f \"$component_path/.env\" ]; then touch \"$component_path/.env\"; fi; echo \"$env_vars\" >> \"$component_path/.env\"'"
else
pct exec $CONTAINER_ID -- bash -c "if [ ! -f \"$component_path/.env\" ]; then touch \"$component_path/.env\"; fi; echo \"$env_vars\" >> \"$component_path/.env\""
fi
}

# Check If there are environment variables
if [ ! -z "$CONTAINER_ENV_VARS" ]; then
# generate random temp .env folder to store all env files for different components
RANDOM_NUM=$(shuf -i 100000-999999 -n 1)
ENV_FOLDER="env_$RANDOM_NUM"
ENV_FOLDER_PATH="/var/lib/vz/snippets/container-env-vars/$ENV_FOLDER"
mkdir -p "$ENV_FOLDER_PATH"

if [ "${MULTI_COMPONENT^^}" == "Y" ]; then # Multi-Component
if echo "$CONTAINER_ENV_VARS" | jq -e > /dev/null 2>&1; then #if exit status of jq is 0 (valid JSON) // success
for key in $(echo "$CONTAINER_ENV_VARS" | jq -r 'keys[]'); do
COMPONENT_PATH="/root/$REPO_BASE_NAME/$PROJECT_ROOT/$key"
ENV_FILE_NAME=$(echo "$COMPONENT_PATH" | tr '/' '_')
ENV_FILE_NAME="$ENV_FILE_NAME.txt"
ENV_FILE_PATH="$ENV_FOLDER_PATH/$ENV_FILE_NAME"
touch "$ENV_FILE_PATH"
echo "$CONTAINER_ENV_VARS" | jq -r --arg key "$key" '.[$key] | to_entries[] | "\(.key)=\(.value)"' > "$ENV_FILE_PATH"
writeEnvToFile "$ENV_FILE_PATH" "$COMPONENT_PATH"
done
else
outputError "Your \"CONTAINER_ENV_VARS\" is not valid JSON. Please re-format and try again."
writeLog "Invalid JSON in CONTAINER_ENV_VARS (GH_ACTION mode)"
exit 16
fi
else # Single Component
ENV_FILE="env_$RANDOM_NUM.txt"
ENV_FILE_PATH="$ENV_FOLDER_PATH/$ENV_FILE"
touch "$ENV_FILE_PATH"
if echo "$CONTAINER_ENV_VARS" | jq -e > /dev/null 2>&1; then #if exit status of jq is 0 (valid JSON) // success
COMPONENT_PATH="/root/$REPO_BASE_NAME/$PROJECT_ROOT"
echo "$CONTAINER_ENV_VARS " | jq -r 'to_entries[] | "\(.key)=\(.value)"' > "$ENV_FILE_PATH" #k=v pairs
writeEnvToFile "$ENV_FILE_PATH" "$COMPONENT_PATH"
else
outputError "Your \"CONTAINER_ENV_VARS\" is not valid JSON. Please re-format and try again."
writeLog "Invalid JSON in CONTAINER_ENV_VARS for single component (GH_ACTION mode)"
exit 16
fi
fi
fi

# Update Container with New Contents from repository =====

startComponentPVE1() {
Expand All @@ -148,15 +205,15 @@ startComponentPVE1() {
INSTALL_CMD="$5"

if [ "${RUNTIME^^}" == "NODEJS" ]; then
pct set $CONTAINER_ID --memory 4096 --swap 0 --cores 4
pct set $CONTAINER_ID --memory 4096 --swap 0 --cores 4
pct exec $CONTAINER_ID -- bash -c "cd /root/$REPO_BASE_NAME/$PROJECT_ROOT/ && git fetch origin && git reset --hard origin/$PROJECT_BRANCH && git pull" > /dev/null 2>&1
pct exec $CONTAINER_ID -- bash -c "cd /root/$REPO_BASE_NAME/$PROJECT_ROOT/$COMP_DIR && $INSTALL_CMD && $BUILD_CMD" > /dev/null 2>&1
pct set $CONTAINER_ID --memory 2048 --swap 0 --cores 2
pct set $CONTAINER_ID --memory 2048 --swap 0 --cores 2
elif [ "${RUNTIME^^}" == "PYTHON" ]; then
pct set $CONTAINER_ID --memory 4096 --swap 0 --cores 4
pct set $CONTAINER_ID --memory 4096 --swap 0 --cores 4
pct exec $CONTAINER_ID -- bash -c "cd /root/$REPO_BASE_NAME/$PROJECT_ROOT/ && git fetch origin && git reset --hard origin/$PROJECT_BRANCH && git pull" > /dev/null 2>&1
pct exec $CONTAINER_ID -- bash -c "cd /root/$REPO_BASE_NAME/$PROJECT_ROOT/$COMP_DIR && source venv/bin/activate && $INSTALL_CMD && $BUILD_CMD" > /dev/null 2>&1
pct set $CONTAINER_ID --memory 2048 --swap 0 --cores 2
pct set $CONTAINER_ID --memory 2048 --swap 0 --cores 2
fi
}

Expand All @@ -174,22 +231,17 @@ startComponentPVE2() {
pct exec $CONTAINER_ID -- bash -c 'cd /root/$REPO_BASE_NAME/$PROJECT_ROOT/ && git fetch origin && git reset --hard origin/$PROJECT_BRANCH && git pull' > /dev/null 2>&1
pct exec $CONTAINER_ID -- bash -c 'cd /root/$REPO_BASE_NAME/$PROJECT_ROOT/$COMP_DIR && $INSTALL_CMD' && '$BUILD_CMD' > /dev/null 2>&1
pct set $CONTAINER_ID --memory 2048 --swap 0 --cores 2
"
"
elif [ "${RUNTIME^^}" == "PYTHON" ]; then
ssh root@10.15.0.5 "
pct set $CONTAINER_ID --memory 4096 --swap 0 --cores 4 &&
pct exec $CONTAINER_ID -- bash -c 'cd /root/$REPO_BASE_NAME/$PROJECT_ROOT && git fetch origin && git reset --hard origin/$PROJECT_BRANCH && git pull' > /dev/null 2>&1
pct exec $CONTAINER_ID -- bash -c 'cd /root/$REPO_BASE_NAME/$PROJECT_ROOT/$COMP_DIR && source venv/bin/activate && $INSTALL_CMD' && '$BUILD_CMD' > /dev/null 2>&1
pct set $CONTAINER_ID --memory 2048 --swap 0 --cores 2
"
"
fi
}


if [ ! -z "$RUNTIME_LANGUAGE" ] && echo "$RUNTIME_LANGUAGE" | jq . >/dev/null 2>&1; then # If RUNTIME_LANGUAGE is set and is valid JSON
MULTI_COMPONENT="Y"
fi

if [ "${MULTI_COMPONENT^^}" == "Y" ]; then
for COMPONENT in $(echo "$START_COMMAND" | jq -r 'keys[]'); do
START=$(echo "$START_COMMAND" | jq -r --arg k "$COMPONENT" '.[$k]')
Expand All @@ -208,17 +260,23 @@ if [ "${MULTI_COMPONENT^^}" == "Y" ]; then
done
if [ ! -z "$ROOT_START_COMMAND" ]; then
if (( $CONTAINER_ID % 2 == 0 )); then
ssh root@10.15.0.5 "pct exec $CONTAINER_ID -- bash -c 'cd /root/$REPO_BASE_NAME/$PROJECT_ROOT && $ROOT_START_COMMAND'"
ssh root@10.15.0.5 "pct exec $CONTAINER_ID -- bash -c 'cd /root/$REPO_BASE_NAME/$PROJECT_ROOT && $ROOT_START_COMMAND'"
else
pct exec $CONTAINER_ID -- bash -c "cd /root/$REPO_BASE_NAME/$PROJECT_ROOT && $ROOT_START_COMMAND"
pct exec $CONTAINER_ID -- bash -c "cd /root/$REPO_BASE_NAME/$PROJECT_ROOT && $ROOT_START_COMMAND"
fi
fi
# startComponent "$RUNTIME_LANGUAGE" "$BUILD_COMMAND" "$START_COMMAND" "."
else
if (( $CONTAINER_ID % 2 == 0 )); then
startComponentPVE2 "$RUNTIME_LANGUAGE" "$BUILD_COMMAND" "$START_COMMAND" "." "$INSTALL_COMMAND"
if [ ! -z "$ROOT_START_COMMAND" ]; then
ssh root@10.15.0.5 "pct exec $CONTAINER_ID -- bash -c 'cd /root/$REPO_BASE_NAME/$PROJECT_ROOT && $ROOT_START_COMMAND'" > /dev/null 2>&1
fi
else
startComponentPVE1 "$RUNTIME_LANGUAGE" "$BUILD_COMMAND" "$START_COMMAND" "." "$INSTALL_COMMAND"
if [ ! -z "$ROOT_START_COMMAND" ]; then
ssh root@10.15.0.5 "pct exec $CONTAINER_ID -- bash -c 'cd /root/$REPO_BASE_NAME/$PROJECT_ROOT && $ROOT_START_COMMAND'" > /dev/null 2>&1
fi
fi
fi

Expand Down Expand Up @@ -262,5 +320,5 @@ QUOTED_CMD=$(printf ' %q' "${CMD[@]}")

tmux new-session -d -s "$CONTAINER_NAME" "$QUOTED_CMD"
echo "✅ Container $CONTAINER_ID has been updated with new contents from branch \"$PROJECT_BRANCH\" on repository \"$PROJECT_REPOSITORY\"."
echo "Wait a few minutes for all background processes to complete before accessing the container."
exit 0

9 changes: 5 additions & 4 deletions container-creation/create-container.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ echoContainerDetails() {
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
echo -e "${BOLD}${BLUE}Still not working? Contact Max K. at maxklema@gmail.com${RESET}"
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"

}

trap cleanup SIGINT SIGTERM SIGHUP
Expand Down Expand Up @@ -71,6 +71,7 @@ SERVICES_BASE_FILE="${16}"
LINUX_DISTRO="${17}"
MULTI_COMPONENTS="${18}"
ROOT_START_COMMAND="${19}"
SELF_HOSTED_RUNNER="${20}"

# Pick the correct template to clone =====

Expand All @@ -96,7 +97,7 @@ fi

# Create the Container Clone ====

if [ "${GH_ACTION^^}" != "Y" ]; then
if [ "${GH_ACTION^^}" != "Y" ] || [ "${SELF_HOSTED_RUNNER^^}" == "N" ]; then
CONTAINER_ID=$(pvesh get /cluster/nextid) #Get the next available LXC ID

echo "⏳ Cloning Container..."
Expand Down Expand Up @@ -178,10 +179,10 @@ pct exec $CONTAINER_ID -- bash -c "cd /root && touch container-updates.log"
# Run Contianer Provision Script to add container to port_map.json
echo "⏳ Running Container Provision Script..."
if [ -f "/var/lib/vz/snippets/container-port-maps/$PROTOCOL_FILE" ]; then
/var/lib/vz/snippets/register-container.sh $CONTAINER_ID $HTTP_PORT /var/lib/vz/snippets/container-port-maps/$PROTOCOL_FILE "$USERNAME_ONLY" "$ROOT_PSWD"
/var/lib/vz/snippets/register-container.sh $CONTAINER_ID $HTTP_PORT /var/lib/vz/snippets/container-port-maps/$PROTOCOL_FILE "$USERNAME_ONLY"
rm -rf /var/lib/vz/snippets/container-port-maps/$PROTOCOL_FILE > /dev/null 2>&1
else
/var/lib/vz/snippets/register-container.sh $CONTAINER_ID $HTTP_PORT "" "$PROXMOX_USERNAME" "$ROOT_PSWD"
/var/lib/vz/snippets/register-container.sh $CONTAINER_ID $HTTP_PORT "" "$PROXMOX_USERNAME"
fi

SSH_PORT=$(iptables -t nat -S PREROUTING | grep "to-destination $CONTAINER_IP:22" | awk -F'--dport ' '{print $2}' | awk '{print $1}' | head -n 1 || true)
Expand Down
Loading